Skip to content

Commit 6f576d9

Browse files
[libc] android atest compat (#93852)
These changes slighly modify the output of the unittests so that they better match GTest, so that utilities that parse the expected output from GTest (such as Android's unit test harness) can read the output from our unit tests. This allows our unit tests to be run on Android devices. Add very primitive command line parsing to: - support --gtest_color=no to disable printing terminal colors. - recognize --gtest_print_time and print the test time in milliseconds. - most of our unit tests run on the order of microseconds, so its useful to preserve the existing behavior. But upsteram GTest ONLY prints time tests in milliseconds, and Android's atest expects to be able to parse exactly that. Atest always passes --gtest_print_time. The word `took` is removed as that also differs from upstream GTest, tripping up parsers. - ignore other --gtest_* flags Do so so that atest can parse the output correctly. Print the test number count before each run, so that atest can parse this value correctly. Link: https://android-review.googlesource.com/c/platform/external/llvm-libc/+/3107252 Link: https://google.github.io/googletest/advanced.html#colored-terminal-output Link: https://google.github.io/googletest/advanced.html#suppressing-the-elapsed-time
1 parent 22ada55 commit 6f576d9

File tree

4 files changed

+93
-34
lines changed

4 files changed

+93
-34
lines changed

libc/test/UnitTest/LibcTest.cpp

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,19 +127,37 @@ void Test::addTest(Test *T) {
127127
End = T;
128128
}
129129

130-
int Test::runTests(const char *TestFilter) {
131-
int TestCount = 0;
130+
int Test::getNumTests() {
131+
int N = 0;
132+
for (Test *T = Start; T; T = T->Next, ++N)
133+
;
134+
return N;
135+
}
136+
137+
int Test::runTests(const TestOptions &Options) {
138+
const char *green = Options.PrintColor ? "\033[32m" : "";
139+
const char *red = Options.PrintColor ? "\033[31m" : "";
140+
const char *reset = Options.PrintColor ? "\033[0m" : "";
141+
142+
int TestCount = getNumTests();
143+
if (TestCount) {
144+
tlog << green << "[==========] " << reset << "Running " << TestCount
145+
<< " test";
146+
if (TestCount > 1)
147+
tlog << "s";
148+
tlog << " from 1 test suite.\n";
149+
}
150+
132151
int FailCount = 0;
133152
for (Test *T = Start; T != nullptr; T = T->Next) {
134153
const char *TestName = T->getName();
135-
cpp::string StrTestName(TestName);
136-
constexpr auto GREEN = "\033[32m";
137-
constexpr auto RED = "\033[31m";
138-
constexpr auto RESET = "\033[0m";
139-
if ((TestFilter != nullptr) && (StrTestName != TestFilter)) {
154+
155+
if (Options.TestFilter && cpp::string(TestName) != Options.TestFilter) {
156+
--TestCount;
140157
continue;
141158
}
142-
tlog << GREEN << "[ RUN ] " << RESET << TestName << '\n';
159+
160+
tlog << green << "[ RUN ] " << reset << TestName << '\n';
143161
[[maybe_unused]] const auto start_time = clock();
144162
RunContext Ctx;
145163
T->SetUp();
@@ -149,13 +167,13 @@ int Test::runTests(const char *TestFilter) {
149167
[[maybe_unused]] const auto end_time = clock();
150168
switch (Ctx.status()) {
151169
case RunContext::RunResult::Fail:
152-
tlog << RED << "[ FAILED ] " << RESET << TestName << '\n';
170+
tlog << red << "[ FAILED ] " << reset << TestName << '\n';
153171
++FailCount;
154172
break;
155173
case RunContext::RunResult::Pass:
156-
tlog << GREEN << "[ OK ] " << RESET << TestName;
174+
tlog << green << "[ OK ] " << reset << TestName;
157175
#ifdef LIBC_TEST_USE_CLOCK
158-
tlog << " (took ";
176+
tlog << " (";
159177
if (start_time > end_time) {
160178
tlog << "unknown - try rerunning)\n";
161179
} else {
@@ -164,7 +182,7 @@ int Test::runTests(const char *TestFilter) {
164182
const uint64_t duration_us = (duration * 1000 * 1000) / CLOCKS_PER_SEC;
165183
const uint64_t duration_ns =
166184
(duration * 1000 * 1000 * 1000) / CLOCKS_PER_SEC;
167-
if (duration_ms != 0)
185+
if (Options.TimeInMs || duration_ms != 0)
168186
tlog << duration_ms << " ms)\n";
169187
else if (duration_us != 0)
170188
tlog << duration_us << " us)\n";
@@ -176,7 +194,6 @@ int Test::runTests(const char *TestFilter) {
176194
#endif
177195
break;
178196
}
179-
++TestCount;
180197
}
181198

182199
if (TestCount > 0) {
@@ -185,8 +202,8 @@ int Test::runTests(const char *TestFilter) {
185202
<< '\n';
186203
} else {
187204
tlog << "No tests run.\n";
188-
if (TestFilter) {
189-
tlog << "No matching test for " << TestFilter << '\n';
205+
if (Options.TestFilter) {
206+
tlog << "No matching test for " << Options.TestFilter << '\n';
190207
}
191208
}
192209

libc/test/UnitTest/LibcTest.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,30 @@ bool test(RunContext *Ctx, TestCond Cond, ValType LHS, ValType RHS,
100100

101101
} // namespace internal
102102

103+
struct TestOptions {
104+
// If set, then just this one test from the suite will be run.
105+
const char *TestFilter = nullptr;
106+
// Should the test results print color codes to stdout?
107+
bool PrintColor = true;
108+
// Should the test results print timing only in milliseconds, as GTest does?
109+
bool TimeInMs = false;
110+
};
111+
103112
// NOTE: One should not create instances and call methods on them directly. One
104113
// should use the macros TEST or TEST_F to write test cases.
105114
class Test {
106115
Test *Next = nullptr;
107116
internal::RunContext *Ctx = nullptr;
108117

109118
void setContext(internal::RunContext *C) { Ctx = C; }
119+
static int getNumTests();
110120

111121
public:
112122
virtual ~Test() {}
113123
virtual void SetUp() {}
114124
virtual void TearDown() {}
115125

116-
static int runTests(const char *);
126+
static int runTests(const TestOptions &Options);
117127

118128
protected:
119129
static void addTest(Test *T);

libc/test/UnitTest/LibcTestMain.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,46 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "LibcTest.h"
10+
#include "src/__support/CPP/string_view.h"
1011

11-
static const char *getTestFilter(int argc, char *argv[]) {
12-
return argc > 1 ? argv[1] : nullptr;
12+
using LIBC_NAMESPACE::cpp::string_view;
13+
using LIBC_NAMESPACE::testing::TestOptions;
14+
15+
namespace {
16+
17+
// A poor-man's getopt_long.
18+
// Run unit tests with --gtest_color=no to disable printing colors, or
19+
// --gtest_print_time to print timings in milliseconds only (as GTest does, so
20+
// external tools such as Android's atest may expect that format to parse the
21+
// output). Other command line flags starting with --gtest_ are ignored.
22+
// Otherwise, the last command line arg is used as a test filter, if command
23+
// line args are specified.
24+
TestOptions parseOptions(int argc, char **argv) {
25+
TestOptions Options;
26+
27+
for (int i = 1; i < argc; ++i) {
28+
string_view arg{argv[i]};
29+
30+
if (arg == "--gtest_color=no")
31+
Options.PrintColor = false;
32+
else if (arg == "--gtest_print_time")
33+
Options.TimeInMs = true;
34+
// Ignore other unsupported gtest specific flags.
35+
else if (arg.starts_with("--gtest_"))
36+
continue;
37+
else
38+
Options.TestFilter = argv[i];
39+
}
40+
41+
return Options;
1342
}
1443

44+
} // anonymous namespace
45+
1546
extern "C" int main(int argc, char **argv, char **envp) {
1647
LIBC_NAMESPACE::testing::argc = argc;
1748
LIBC_NAMESPACE::testing::argv = argv;
1849
LIBC_NAMESPACE::testing::envp = envp;
1950

20-
const char *TestFilter = getTestFilter(argc, argv);
21-
return LIBC_NAMESPACE::testing::Test::runTests(TestFilter);
51+
return LIBC_NAMESPACE::testing::Test::runTests(parseOptions(argc, argv));
2252
}

libc/test/utils/UnitTest/testfilter_test.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "test/UnitTest/LibcTest.h"
1010

11+
using LIBC_NAMESPACE::testing::TestOptions;
12+
1113
TEST(LlvmLibcTestFilterTest, CorrectFilter) {}
1214

1315
TEST(LlvmLibcTestFilterTest, CorrectFilter2) {}
@@ -17,22 +19,22 @@ TEST(LlvmLibcTestFilterTest, IncorrectFilter) {}
1719
TEST(LlvmLibcTestFilterTest, NoFilter) {}
1820

1921
TEST(LlvmLibcTestFilterTest, CheckCorrectFilter) {
20-
ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(
21-
"LlvmLibcTestFilterTest.NoFilter"),
22-
0);
23-
ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(
24-
"LlvmLibcTestFilterTest.IncorrFilter"),
25-
1);
26-
ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(
27-
"LlvmLibcTestFilterTest.CorrectFilter"),
28-
0);
29-
ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(
30-
"LlvmLibcTestFilterTest.CorrectFilter2"),
31-
0);
22+
TestOptions Options;
23+
Options.TestFilter = "LlvmLibcTestFilterTest.NoFilter";
24+
ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(Options), 0);
25+
26+
Options.TestFilter = "LlvmLibcTestFilterTest.IncorrFilter";
27+
ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(Options), 1);
28+
29+
Options.TestFilter = "LlvmLibcTestFilterTest.CorrectFilter";
30+
ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(Options), 0);
31+
32+
Options.TestFilter = "LlvmLibcTestFilterTest.CorrectFilter2";
33+
ASSERT_EQ(LIBC_NAMESPACE::testing::Test::runTests(Options), 0);
3234
}
3335

3436
int main() {
35-
LIBC_NAMESPACE::testing::Test::runTests(
36-
"LlvmLibcTestFilterTest.CheckCorrectFilter");
37+
TestOptions Options{"LlvmLibcTestFilterTest.NoFilter", /*PrintColor=*/true};
38+
LIBC_NAMESPACE::testing::Test::runTests(Options);
3739
return 0;
3840
}

0 commit comments

Comments
 (0)