| // 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; | |
| } |