|  | // Copyright 2013 Google Inc. All Rights Reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #include "base/command_line.h" | 
|  | #include "util/build_config.h" | 
|  | #include "util/test/test.h" | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | #include <windows.h> | 
|  | #else | 
|  | #include <unistd.h> | 
|  | #endif | 
|  |  | 
|  | namespace testing { | 
|  | Test* g_current_test; | 
|  | }  // namespace testing | 
|  |  | 
|  | struct RegisteredTest { | 
|  | testing::Test* (*factory)(); | 
|  | const char* name; | 
|  | bool should_run; | 
|  | }; | 
|  |  | 
|  | // This can't be a vector because tests call RegisterTest from static | 
|  | // initializers and the order static initializers run it isn't specified. So | 
|  | // the vector constructor isn't guaranteed to run before all of the | 
|  | // RegisterTest() calls. | 
|  | static RegisteredTest tests[10000]; | 
|  | static int ntests; | 
|  |  | 
|  | void RegisterTest(testing::Test* (*factory)(), const char* name) { | 
|  | tests[ntests].factory = factory; | 
|  | tests[ntests++].name = name; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | bool PatternMatchesString(const char* pattern, const char* str) { | 
|  | switch (*pattern) { | 
|  | case '\0': | 
|  | case '-': | 
|  | return *str == '\0'; | 
|  | case '*': | 
|  | return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || | 
|  | PatternMatchesString(pattern + 1, str); | 
|  | default: | 
|  | return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool TestMatchesFilter(const char* test, const char* filter) { | 
|  | // Split --gtest_filter at '-' into positive and negative filters. | 
|  | const char* const dash = strchr(filter, '-'); | 
|  | const char* pos = | 
|  | dash == filter ? "*" : filter;  // Treat '-test1' as '*-test1' | 
|  | const char* neg = dash ? dash + 1 : ""; | 
|  | return PatternMatchesString(pos, test) && !PatternMatchesString(neg, test); | 
|  | } | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | struct ScopedEnableVTEscapeProcessing { | 
|  | ScopedEnableVTEscapeProcessing() { | 
|  | console_ = GetStdHandle(STD_OUTPUT_HANDLE); | 
|  | CONSOLE_SCREEN_BUFFER_INFO csbi; | 
|  | if (GetConsoleScreenBufferInfo(console_, &csbi) && | 
|  | GetConsoleMode(console_, &original_mode_)) { | 
|  | SetConsoleMode(console_, original_mode_ | | 
|  | ENABLE_VIRTUAL_TERMINAL_PROCESSING | | 
|  | DISABLE_NEWLINE_AUTO_RETURN); | 
|  | } else { | 
|  | console_ = INVALID_HANDLE_VALUE; | 
|  | } | 
|  | } | 
|  |  | 
|  | ~ScopedEnableVTEscapeProcessing() { | 
|  | if (is_valid()) | 
|  | SetConsoleMode(console_, original_mode_); | 
|  | } | 
|  |  | 
|  | bool is_valid() const { return console_ != INVALID_HANDLE_VALUE; } | 
|  |  | 
|  | HANDLE console_; | 
|  | DWORD original_mode_; | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | int main(int argc, char** argv) { | 
|  | base::CommandLine::Init(argc, argv); | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | ScopedEnableVTEscapeProcessing enable_vt_processing; | 
|  | #endif | 
|  | setvbuf(stdout, NULL, _IOLBF, BUFSIZ); | 
|  |  | 
|  | int tests_started = 0; | 
|  |  | 
|  | const char* test_filter = "*"; | 
|  | for (int i = 1; i < argc; ++i) { | 
|  | const char kTestFilterPrefix[] = "--gtest_filter="; | 
|  | if (strncmp(argv[i], kTestFilterPrefix, strlen(kTestFilterPrefix)) == 0) { | 
|  | test_filter = &argv[i][strlen(kTestFilterPrefix)]; | 
|  | } | 
|  | } | 
|  |  | 
|  | int num_active_tests = 0; | 
|  | for (int i = 0; i < ntests; i++) { | 
|  | tests[i].should_run = TestMatchesFilter(tests[i].name, test_filter); | 
|  | if (tests[i].should_run) { | 
|  | ++num_active_tests; | 
|  | } | 
|  | } | 
|  |  | 
|  | const char* prefix = ""; | 
|  | const char* suffix = "\n"; | 
|  | #if defined(OS_WIN) | 
|  | if (enable_vt_processing.is_valid()) | 
|  | #else | 
|  | if (isatty(1)) | 
|  | #endif | 
|  | { | 
|  | prefix = "\r"; | 
|  | suffix = "\x1B[K"; | 
|  | } | 
|  | bool passed = true; | 
|  | for (int i = 0; i < ntests; i++) { | 
|  | if (!tests[i].should_run) | 
|  | continue; | 
|  |  | 
|  | ++tests_started; | 
|  | testing::Test* test = tests[i].factory(); | 
|  | printf("%s[%d/%d] %s%s", prefix, tests_started, num_active_tests, | 
|  | tests[i].name, suffix); | 
|  | test->SetUp(); | 
|  | test->Run(); | 
|  | test->TearDown(); | 
|  | if (test->Failed()) | 
|  | passed = false; | 
|  | delete test; | 
|  | } | 
|  |  | 
|  | printf("\n%s\n", passed ? "PASSED" : "FAILED"); | 
|  | fflush(stdout); | 
|  | return passed ? EXIT_SUCCESS : EXIT_FAILURE; | 
|  | } |