blob: 6b2e26d6b966f6fa42bf343a97e7effe7968ee6b [file] [log] [blame]
// 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;
}