aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/test/UnitTest/LibcTest.cpp47
-rw-r--r--libc/test/UnitTest/LibcTest.h12
-rw-r--r--libc/test/UnitTest/LibcTestMain.cpp38
-rw-r--r--libc/test/utils/UnitTest/testfilter_test.cpp30
4 files changed, 93 insertions, 34 deletions
diff --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp
index 846ad33..539a2e4 100644
--- a/libc/test/UnitTest/LibcTest.cpp
+++ b/libc/test/UnitTest/LibcTest.cpp
@@ -127,19 +127,37 @@ void Test::addTest(Test *T) {
End = T;
}
-int Test::runTests(const char *TestFilter) {
- int TestCount = 0;
+int Test::getNumTests() {
+ int N = 0;
+ for (Test *T = Start; T; T = T->Next, ++N)
+ ;
+ return N;
+}
+
+int Test::runTests(const TestOptions &Options) {
+ const char *green = Options.PrintColor ? "\033[32m" : "";
+ const char *red = Options.PrintColor ? "\033[31m" : "";
+ const char *reset = Options.PrintColor ? "\033[0m" : "";
+
+ int TestCount = getNumTests();
+ if (TestCount) {
+ tlog << green << "[==========] " << reset << "Running " << TestCount
+ << " test";
+ if (TestCount > 1)
+ tlog << "s";
+ tlog << " from 1 test suite.\n";
+ }
+
int FailCount = 0;
for (Test *T = Start; T != nullptr; T = T->Next) {
const char *TestName = T->getName();
- cpp::string StrTestName(TestName);
- constexpr auto GREEN = "\033[32m";
- constexpr auto RED = "\033[31m";
- constexpr auto RESET = "\033[0m";
- if ((TestFilter != nullptr) && (StrTestName != TestFilter)) {
+
+ if (Options.TestFilter && cpp::string(TestName) != Options.TestFilter) {
+ --TestCount;
continue;
}
- tlog << GREEN << "[ RUN ] " << RESET << TestName << '\n';
+
+ tlog << green << "[ RUN ] " << reset << TestName << '\n';
[[maybe_unused]] const auto start_time = clock();
RunContext Ctx;
T->SetUp();
@@ -149,13 +167,13 @@ int Test::runTests(const char *TestFilter) {
[[maybe_unused]] const auto end_time = clock();
switch (Ctx.status()) {
case RunContext::RunResult::Fail:
- tlog << RED << "[ FAILED ] " << RESET << TestName << '\n';
+ tlog << red << "[ FAILED ] " << reset << TestName << '\n';
++FailCount;
break;
case RunContext::RunResult::Pass:
- tlog << GREEN << "[ OK ] " << RESET << TestName;
+ tlog << green << "[ OK ] " << reset << TestName;
#ifdef LIBC_TEST_USE_CLOCK
- tlog << " (took ";
+ tlog << " (";
if (start_time > end_time) {
tlog << "unknown - try rerunning)\n";
} else {
@@ -164,7 +182,7 @@ int Test::runTests(const char *TestFilter) {
const uint64_t duration_us = (duration * 1000 * 1000) / CLOCKS_PER_SEC;
const uint64_t duration_ns =
(duration * 1000 * 1000 * 1000) / CLOCKS_PER_SEC;
- if (duration_ms != 0)
+ if (Options.TimeInMs || duration_ms != 0)
tlog << duration_ms << " ms)\n";
else if (duration_us != 0)
tlog << duration_us << " us)\n";
@@ -176,7 +194,6 @@ int Test::runTests(const char *TestFilter) {
#endif
break;
}
- ++TestCount;
}
if (TestCount > 0) {
@@ -185,8 +202,8 @@ int Test::runTests(const char *TestFilter) {
<< '\n';
} else {
tlog << "No tests run.\n";
- if (TestFilter) {
- tlog << "No matching test for " << TestFilter << '\n';
+ if (Options.TestFilter) {
+ tlog << "No matching test for " << Options.TestFilter << '\n';
}
}
diff --git a/libc/test/UnitTest/LibcTest.h b/libc/test/UnitTest/LibcTest.h
index bba3c6d..42ba37a 100644
--- a/libc/test/UnitTest/LibcTest.h
+++ b/libc/test/UnitTest/LibcTest.h
@@ -100,6 +100,15 @@ bool test(RunContext *Ctx, TestCond Cond, ValType LHS, ValType RHS,
} // namespace internal
+struct TestOptions {
+ // If set, then just this one test from the suite will be run.
+ const char *TestFilter = nullptr;
+ // Should the test results print color codes to stdout?
+ bool PrintColor = true;
+ // Should the test results print timing only in milliseconds, as GTest does?
+ bool TimeInMs = false;
+};
+
// NOTE: One should not create instances and call methods on them directly. One
// should use the macros TEST or TEST_F to write test cases.
class Test {
@@ -107,13 +116,14 @@ class Test {
internal::RunContext *Ctx = nullptr;
void setContext(internal::RunContext *C) { Ctx = C; }
+ static int getNumTests();
public:
virtual ~Test() {}
virtual void SetUp() {}
virtual void TearDown() {}
- static int runTests(const char *);
+ static int runTests(const TestOptions &Options);
protected:
static void addTest(Test *T);
diff --git a/libc/test/UnitTest/LibcTestMain.cpp b/libc/test/UnitTest/LibcTestMain.cpp
index bf1a921..94536e9 100644
--- a/libc/test/UnitTest/LibcTestMain.cpp
+++ b/libc/test/UnitTest/LibcTestMain.cpp
@@ -7,16 +7,46 @@
//===----------------------------------------------------------------------===//
#include "LibcTest.h"
+#include "src/__support/CPP/string_view.h"
-static const char *getTestFilter(int argc, char *argv[]) {
- return argc > 1 ? argv[1] : nullptr;
+using LIBC_NAMESPACE::cpp::string_view;
+using LIBC_NAMESPACE::testing::TestOptions;
+
+namespace {
+
+// A poor-man's getopt_long.
+// Run unit tests with --gtest_color=no to disable printing colors, or
+// --gtest_print_time to print timings in milliseconds only (as GTest does, so
+// external tools such as Android's atest may expect that format to parse the
+// output). Other command line flags starting with --gtest_ are ignored.
+// Otherwise, the last command line arg is used as a test filter, if command
+// line args are specified.
+TestOptions parseOptions(int argc, char **argv) {
+ TestOptions Options;
+
+ for (int i = 1; i < argc; ++i) {
+ string_view arg{argv[i]};
+
+ if (arg == "--gtest_color=no")
+ Options.PrintColor = false;
+ else if (arg == "--gtest_print_time")
+ Options.TimeInMs = true;
+ // Ignore other unsupported gtest specific flags.
+ else if (arg.starts_with("--gtest_"))
+ continue;
+ else
+ Options.TestFilter = argv[i];
+ }
+
+ return Options;
}
+} // anonymous namespace
+
extern "C" int main(int argc, char **argv, char **envp) {
LIBC_NAMESPACE::testing::argc = argc;
LIBC_NAMESPACE::testing::argv = argv;
LIBC_NAMESPACE::testing::envp = envp;
- const char *TestFilter = getTestFilter(argc, argv);
- return LIBC_NAMESPACE::testing::Test::runTests(TestFilter);
+ return LIBC_NAMESPACE::testing::Test::runTests(parseOptions(argc, argv));
}
diff --git a/libc/test/utils/UnitTest/testfilter_test.cpp b/libc/test/utils/UnitTest/testfilter_test.cpp
index 567b5e2..d7e6825 100644
--- a/libc/test/utils/UnitTest/testfilter_test.cpp
+++ b/libc/test/utils/UnitTest/testfilter_test.cpp
@@ -8,6 +8,8 @@
#include "test/UnitTest/LibcTest.h"
+using LIBC_NAMESPACE::testing::TestOptions;
+
TEST(LlvmLibcTestFilterTest, CorrectFilter) {}
TEST(LlvmLibcTestFilterTest, CorrectFilter2) {}
@@ -17,22 +19,22 @@ TEST(LlvmLibcTestFilterTest, IncorrectFilter) {}
TEST(LlvmLibcTestFilterTest, NoFilter) {}
TEST(LlvmLibcTestFilterTest, CheckCorrectFilter) {
- ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(
- "LlvmLibcTestFilterTest.NoFilter"),
- 0);
- ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(
- "LlvmLibcTestFilterTest.IncorrFilter"),
- 1);
- ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(
- "LlvmLibcTestFilterTest.CorrectFilter"),
- 0);
- ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(
- "LlvmLibcTestFilterTest.CorrectFilter2"),
- 0);
+ TestOptions Options;
+ Options.TestFilter = "LlvmLibcTestFilterTest.NoFilter";
+ ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(Options), 0);
+
+ Options.TestFilter = "LlvmLibcTestFilterTest.IncorrFilter";
+ ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(Options), 1);
+
+ Options.TestFilter = "LlvmLibcTestFilterTest.CorrectFilter";
+ ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(Options), 0);
+
+ Options.TestFilter = "LlvmLibcTestFilterTest.CorrectFilter2";
+ ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(Options), 0);
}
int main() {
- LIBC_NAMESPACE::testing::Test::runTests(
- "LlvmLibcTestFilterTest.CheckCorrectFilter");
+ TestOptions Options{"LlvmLibcTestFilterTest.NoFilter", /*PrintColor=*/true};
+ LIBC_NAMESPACE::testing::Test::runTests(Options);
return 0;
}