• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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