blob: 94ee8350be7c1b7949c27f31d4a0a7a7651c7810 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <array>
#include "tools/kazoo/test.h"
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 a
// vector constructor isn't guaranteed to run before all of the RegisterTest()
// calls.
static std::array<RegisteredTest, 10000> tests;
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);
}
} // namespace
int main(int argc, char** argv) {
setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
int tests_started = 0;
bool break_on_failure = false;
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)];
}
const char kTestBreakOnFailure[] = "--gtest_break_on_failure";
if (strcmp(argv[i], kTestBreakOnFailure) == 0) {
break_on_failure = true;
}
}
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 (isatty(1)) {
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;
if (break_on_failure) {
__builtin_trap();
}
}
delete test;
}
printf("\n%s\n", passed ? "PASSED" : "FAILED");
fflush(stdout);
return passed ? EXIT_SUCCESS : EXIT_FAILURE;
}