1 // Copyright 2013 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include "base/command_line.h"
21 #include "util/build_config.h"
22 #include "util/test/test.h"
23
24 #if defined(OS_WIN)
25 #include <windows.h>
26 #else
27 #include <unistd.h>
28 #endif
29
30 namespace testing {
31 Test* g_current_test;
32 } // namespace testing
33
34 struct RegisteredTest {
35 testing::Test* (*factory)();
36 const char* name;
37 bool should_run;
38 };
39
40 // This can't be a vector because tests call RegisterTest from static
41 // initializers and the order static initializers run it isn't specified. So
42 // the vector constructor isn't guaranteed to run before all of the
43 // RegisterTest() calls.
44 static RegisteredTest tests[10000];
45 static int ntests;
46
RegisterTest(testing::Test * (* factory)(),const char * name)47 void RegisterTest(testing::Test* (*factory)(), const char* name) {
48 tests[ntests].factory = factory;
49 tests[ntests++].name = name;
50 }
51
52 namespace {
53
PatternMatchesString(const char * pattern,const char * str)54 bool PatternMatchesString(const char* pattern, const char* str) {
55 switch (*pattern) {
56 case '\0':
57 case '-':
58 case ':':
59 return *str == '\0';
60 case '*':
61 return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
62 PatternMatchesString(pattern + 1, str);
63 default:
64 return *pattern == *str && PatternMatchesString(pattern + 1, str + 1);
65 }
66 }
67
PatternListMatchString(const char * pattern,const char * str)68 bool PatternListMatchString(const char* pattern, const char* str) {
69 const char* const colon = strchr(pattern, ':');
70 if (PatternMatchesString(pattern, str))
71 return true;
72
73 if (!colon)
74 return false;
75
76 return PatternListMatchString(colon + 1, str);
77 }
78
TestMatchesFilter(const char * test,const char * filter)79 bool TestMatchesFilter(const char* test, const char* filter) {
80 // Split --gtest_filter at '-' into positive and negative filters.
81 const char* const dash = strchr(filter, '-');
82 const char* pos =
83 dash == filter ? "*" : filter; // Treat '-test1' as '*-test1'
84 const char* neg = dash ? dash + 1 : "";
85 return PatternListMatchString(pos, test) &&
86 !PatternListMatchString(neg, test);
87 }
88
89 #if defined(OS_WIN)
90 struct ScopedEnableVTEscapeProcessing {
ScopedEnableVTEscapeProcessing__anona6bc9aa20111::ScopedEnableVTEscapeProcessing91 ScopedEnableVTEscapeProcessing() {
92 console_ = GetStdHandle(STD_OUTPUT_HANDLE);
93 CONSOLE_SCREEN_BUFFER_INFO csbi;
94 if (GetConsoleScreenBufferInfo(console_, &csbi) &&
95 GetConsoleMode(console_, &original_mode_)) {
96 SetConsoleMode(console_, original_mode_ |
97 ENABLE_VIRTUAL_TERMINAL_PROCESSING |
98 DISABLE_NEWLINE_AUTO_RETURN);
99 } else {
100 console_ = INVALID_HANDLE_VALUE;
101 }
102 }
103
~ScopedEnableVTEscapeProcessing__anona6bc9aa20111::ScopedEnableVTEscapeProcessing104 ~ScopedEnableVTEscapeProcessing() {
105 if (is_valid())
106 SetConsoleMode(console_, original_mode_);
107 }
108
is_valid__anona6bc9aa20111::ScopedEnableVTEscapeProcessing109 bool is_valid() const { return console_ != INVALID_HANDLE_VALUE; }
110
111 HANDLE console_;
112 DWORD original_mode_;
113 };
114 #endif
115
116 } // namespace
117
main(int argc,char ** argv)118 int main(int argc, char** argv) {
119 base::CommandLine::Init(argc, argv);
120
121 #if defined(OS_WIN)
122 ScopedEnableVTEscapeProcessing enable_vt_processing;
123 #endif
124 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
125
126 int tests_started = 0;
127
128 const char* test_filter = "*";
129 for (int i = 1; i < argc; ++i) {
130 const char kTestFilterPrefix[] = "--gtest_filter=";
131 if (strncmp(argv[i], kTestFilterPrefix, strlen(kTestFilterPrefix)) == 0) {
132 test_filter = &argv[i][strlen(kTestFilterPrefix)];
133 }
134 }
135
136 int num_active_tests = 0;
137 for (int i = 0; i < ntests; i++) {
138 tests[i].should_run = TestMatchesFilter(tests[i].name, test_filter);
139 if (tests[i].should_run) {
140 ++num_active_tests;
141 }
142 }
143
144 const char* prefix = "";
145 const char* suffix = "\n";
146 #if defined(OS_WIN)
147 if (enable_vt_processing.is_valid())
148 #else
149 // When run from Xcode, the console returns "true" to isatty(1) but it
150 // does not interprets ANSI escape sequence resulting in difficult to
151 // read output. There is no portable way to detect if the console is
152 // Xcode's console (term is set to xterm or xterm-256colors) but Xcode
153 // sets the __XCODE_BUILT_PRODUCTS_DIR_PATHS environment variable. Use
154 // this as a proxy to detect that the console does not interpret the
155 // ANSI sequences correctly.
156 if (isatty(1) && getenv("__XCODE_BUILT_PRODUCTS_DIR_PATHS") == NULL)
157 #endif
158 {
159 prefix = "\r";
160 suffix = "\x1B[K";
161 }
162 bool passed = true;
163 for (int i = 0; i < ntests; i++) {
164 if (!tests[i].should_run)
165 continue;
166
167 ++tests_started;
168 testing::Test* test = tests[i].factory();
169 printf("%s[%d/%d] %s%s", prefix, tests_started, num_active_tests,
170 tests[i].name, suffix);
171 test->SetUp();
172 test->Run();
173 test->TearDown();
174 if (test->Failed())
175 passed = false;
176 delete test;
177 }
178
179 printf("\n%s\n", passed ? "PASSED" : "FAILED");
180 fflush(stdout);
181 return passed ? EXIT_SUCCESS : EXIT_FAILURE;
182 }
183