| // | |
| // Copyright 2019 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // test_utils_unittest.cpp: Unit tests for ANGLE's test utility functions | |
| #include "gtest/gtest.h" | |
| #include "common/system_utils.h" | |
| #include "tests/test_utils/runner/TestSuite.h" | |
| #include "util/Timer.h" | |
| #include "util/test_utils.h" | |
| #include "util/test_utils_unittest_helper.h" | |
| using namespace angle; | |
| namespace | |
| { | |
| #if defined(ANGLE_PLATFORM_WINDOWS) | |
| constexpr char kRunAppHelperExecutable[] = "test_utils_unittest_helper.exe"; | |
| #elif ANGLE_PLATFORM_IOS_FAMILY | |
| constexpr char kRunAppHelperExecutable[] = | |
| "../test_utils_unittest_helper.app/test_utils_unittest_helper"; | |
| #else | |
| constexpr char kRunAppHelperExecutable[] = "test_utils_unittest_helper"; | |
| #endif | |
| // Transforms various line endings into C/Unix line endings: | |
| // | |
| // - A\nB -> A\nB | |
| // - A\rB -> A\nB | |
| // - A\r\nB -> A\nB | |
| std::string NormalizeNewLines(const std::string &str) | |
| { | |
| std::string result; | |
| for (size_t i = 0; i < str.size(); ++i) | |
| { | |
| if (str[i] == '\r') | |
| { | |
| if (i + 1 < str.size() && str[i + 1] == '\n') | |
| { | |
| ++i; | |
| } | |
| result += '\n'; | |
| } | |
| else | |
| { | |
| result += str[i]; | |
| } | |
| } | |
| return result; | |
| } | |
| // Tests that Sleep() actually waits some time. | |
| TEST(TestUtils, Sleep) | |
| { | |
| Timer timer; | |
| timer.start(); | |
| angle::Sleep(500); | |
| timer.stop(); | |
| // Use a slightly fuzzy range | |
| EXPECT_GT(timer.getElapsedWallClockTime(), 0.48); | |
| } | |
| // TODO: android support. http://anglebug.com/3125 | |
| #if defined(ANGLE_PLATFORM_ANDROID) | |
| # define MAYBE_RunApp DISABLED_RunApp | |
| # define MAYBE_RunAppAsync DISABLED_RunAppAsync | |
| # define MAYBE_RunAppAsyncRedirectStderrToStdout DISABLED_RunAppAsyncRedirectStderrToStdout | |
| // TODO: fuchsia support. http://anglebug.com/7312 | |
| #elif defined(ANGLE_PLATFORM_FUCHSIA) | |
| # define MAYBE_RunApp DISABLED_RunApp | |
| # define MAYBE_RunAppAsync DISABLED_RunAppAsync | |
| # define MAYBE_RunAppAsyncRedirectStderrToStdout DISABLED_RunAppAsyncRedirectStderrToStdout | |
| // TODO: iOS simulator support. http://anglebug.com/8116 | |
| #elif ANGLE_PLATFORM_IOS_FAMILY_SIMULATOR | |
| # define MAYBE_RunApp DISABLED_RunApp | |
| # define MAYBE_RunAppAsync DISABLED_RunAppAsync | |
| # define MAYBE_RunAppAsyncRedirectStderrToStdout DISABLED_RunAppAsyncRedirectStderrToStdout | |
| #else | |
| # define MAYBE_RunApp RunApp | |
| # define MAYBE_RunAppAsync RunAppAsync | |
| # define MAYBE_RunAppAsyncRedirectStderrToStdout RunAppAsyncRedirectStderrToStdout | |
| #endif // defined(ANGLE_PLATFORM_ANDROID) | |
| std::string GetTestAppExecutablePath() | |
| { | |
| std::string testExecutableName = angle::TestSuite::GetInstance()->getTestExecutableName(); | |
| std::string executablePath = angle::StripFilenameFromPath(testExecutableName); | |
| EXPECT_NE(executablePath, ""); | |
| executablePath += "/"; | |
| executablePath += kRunAppHelperExecutable; | |
| return executablePath; | |
| } | |
| // Test running an external application and receiving its output | |
| TEST(TestUtils, MAYBE_RunApp) | |
| { | |
| std::string executablePath = GetTestAppExecutablePath(); | |
| std::vector<const char *> args = {executablePath.c_str(), kRunAppTestArg1, kRunAppTestArg2}; | |
| // Test that the application can be executed. | |
| { | |
| ProcessHandle process(args, ProcessOutputCapture::StdoutAndStderrSeparately); | |
| EXPECT_TRUE(process->started()); | |
| EXPECT_TRUE(process->finish()); | |
| EXPECT_TRUE(process->finished()); | |
| EXPECT_GT(process->getElapsedTimeSeconds(), 0.0); | |
| EXPECT_EQ(kRunAppTestStdout, NormalizeNewLines(process->getStdout())); | |
| EXPECT_EQ(kRunAppTestStderr, NormalizeNewLines(process->getStderr())); | |
| EXPECT_EQ(EXIT_SUCCESS, process->getExitCode()); | |
| } | |
| // Test that environment variables reach the child. | |
| { | |
| bool setEnvDone = SetEnvironmentVar(kRunAppTestEnvVarName, kRunAppTestEnvVarValue); | |
| EXPECT_TRUE(setEnvDone); | |
| ProcessHandle process(LaunchProcess(args, ProcessOutputCapture::StdoutAndStderrSeparately)); | |
| EXPECT_TRUE(process->started()); | |
| EXPECT_TRUE(process->finish()); | |
| EXPECT_GT(process->getElapsedTimeSeconds(), 0.0); | |
| EXPECT_EQ("", process->getStdout()); | |
| EXPECT_EQ(kRunAppTestEnvVarValue, NormalizeNewLines(process->getStderr())); | |
| EXPECT_EQ(EXIT_SUCCESS, process->getExitCode()); | |
| // Unset environment var. | |
| SetEnvironmentVar(kRunAppTestEnvVarName, ""); | |
| } | |
| } | |
| // Test running an external application and receiving its output asynchronously. | |
| TEST(TestUtils, MAYBE_RunAppAsync) | |
| { | |
| std::string executablePath = GetTestAppExecutablePath(); | |
| std::vector<const char *> args = {executablePath.c_str(), kRunAppTestArg1, kRunAppTestArg2}; | |
| // Test that the application can be executed and the output is captured correctly. | |
| { | |
| ProcessHandle process(args, ProcessOutputCapture::StdoutAndStderrSeparately); | |
| EXPECT_TRUE(process->started()); | |
| constexpr double kTimeout = 3.0; | |
| Timer timer; | |
| timer.start(); | |
| while (!process->finished() && timer.getElapsedWallClockTime() < kTimeout) | |
| { | |
| angle::Sleep(1); | |
| } | |
| EXPECT_TRUE(process->finished()); | |
| EXPECT_GT(process->getElapsedTimeSeconds(), 0.0); | |
| EXPECT_EQ(kRunAppTestStdout, NormalizeNewLines(process->getStdout())); | |
| EXPECT_EQ(kRunAppTestStderr, NormalizeNewLines(process->getStderr())); | |
| EXPECT_EQ(EXIT_SUCCESS, process->getExitCode()); | |
| } | |
| } | |
| // Test running an external application and receiving its stdout and stderr output interleaved. | |
| TEST(TestUtils, MAYBE_RunAppAsyncRedirectStderrToStdout) | |
| { | |
| std::string executablePath = GetTestAppExecutablePath(); | |
| std::vector<const char *> args = {executablePath.c_str(), kRunAppTestArg1, kRunAppTestArg2}; | |
| // Test that the application can be executed and the output is captured correctly. | |
| { | |
| ProcessHandle process(args, ProcessOutputCapture::StdoutAndStderrInterleaved); | |
| EXPECT_TRUE(process->started()); | |
| constexpr double kTimeout = 3.0; | |
| Timer timer; | |
| timer.start(); | |
| while (!process->finished() && timer.getElapsedWallClockTime() < kTimeout) | |
| { | |
| angle::Sleep(1); | |
| } | |
| EXPECT_TRUE(process->finished()); | |
| EXPECT_GT(process->getElapsedTimeSeconds(), 0.0); | |
| EXPECT_EQ(std::string(kRunAppTestStdout) + kRunAppTestStderr, | |
| NormalizeNewLines(process->getStdout())); | |
| EXPECT_EQ("", process->getStderr()); | |
| EXPECT_EQ(EXIT_SUCCESS, process->getExitCode()); | |
| } | |
| } | |
| // Verify that NumberOfProcessors returns something reasonable. | |
| TEST(TestUtils, NumberOfProcessors) | |
| { | |
| int numProcs = angle::NumberOfProcessors(); | |
| EXPECT_GT(numProcs, 0); | |
| EXPECT_LT(numProcs, 1000); | |
| } | |
| } // namespace |