Skip to content

Commit

Permalink
Merge pull request #1562 from jhasse/googletest
Browse files Browse the repository at this point in the history
Use GoogleTest instead of our own framework
  • Loading branch information
jhasse authored Nov 22, 2023
2 parents 236e320 + 87c92f2 commit 4b6a8ac
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 277 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
- name: Install dependencies
run: |
apt update
apt install -y python3-pytest ninja-build clang-tidy python3-pip clang
apt install -y python3-pytest ninja-build clang-tidy python3-pip clang libgtest-dev
pip3 install cmake==3.17.*
- name: Configure (GCC)
run: cmake -Bbuild-gcc -DCMAKE_BUILD_TYPE=Debug -G'Ninja Multi-Config'
Expand Down Expand Up @@ -144,7 +144,6 @@ jobs:
run: |
python3 configure.py --bootstrap
./ninja all
./ninja_test --gtest_filter=-SubprocessTest.SetWithLots
python3 misc/ninja_syntax_test.py
./misc/output_test.py
Expand Down
31 changes: 30 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,34 @@ endif()

include(CTest)
if(BUILD_TESTING)
find_package(GTest)
if(NOT GTest_FOUND)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/release-1.10.0.tar.gz
URL_HASH SHA1=9c89be7df9c5e8cb0bc20b3c4b39bf7e82686770
)
FetchContent_MakeAvailable(googletest)

# Before googletest-1.11.0, the CMake files provided by the source archive
# did not define the GTest::gtest target, only the gtest one, so define
# an alias when needed to ensure the rest of this file works with all
# GoogleTest releases.
#
# Note that surprisingly, this is not needed when using GTEST_ROOT to
# point to a local installation, because this one contains CMake-generated
# files that contain the right target definition, and which will be
# picked up by the find_package(GTest) file above.
#
# This comment and the four lines below can be removed once Ninja only
# depends on release-1.11.0 or above.
if (NOT TARGET GTest::gtest)
message(STATUS "Defining GTest::gtest alias to work-around bug in older release.")
add_library(GTest::gtest ALIAS gtest)
endif()
endif()

# Tests all build into ninja_test executable.
add_executable(ninja_test
src/build_log_test.cc
Expand Down Expand Up @@ -254,7 +282,8 @@ if(BUILD_TESTING)
target_sources(ninja_test PRIVATE src/includes_normalize_test.cc src/msvc_helper_test.cc
windows/ninja.manifest)
endif()
target_link_libraries(ninja_test PRIVATE libninja libninja-re2c)
find_package(Threads REQUIRED)
target_link_libraries(ninja_test PRIVATE libninja libninja-re2c GTest::gtest Threads::Threads)

foreach(perftest
build_log_perftest
Expand Down
2 changes: 0 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,13 @@ for:
pacman -S --quiet --noconfirm --needed re2c 2>&1\n
./configure.py --bootstrap --platform mingw 2>&1\n
./ninja all\n
./ninja_test 2>&1\n
./misc/ninja_syntax_test.py 2>&1\n\"@"
- matrix:
only:
- image: Ubuntu1804
build_script:
- ./configure.py --bootstrap
- ./ninja all
- ./ninja_test
- misc/ninja_syntax_test.py
- misc/output_test.py

Expand Down
38 changes: 0 additions & 38 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,44 +582,6 @@ def has_re2c():
# build.ninja file.
n = ninja_writer

n.comment('Tests all build into ninja_test executable.')

objs = []
if platform.is_msvc():
cxxvariables = [('pdb', 'ninja_test.pdb')]

for name in ['build_log_test',
'build_test',
'clean_test',
'clparser_test',
'depfile_parser_test',
'deps_log_test',
'dyndep_parser_test',
'disk_interface_test',
'edit_distance_test',
'graph_test',
'json_test',
'lexer_test',
'manifest_parser_test',
'missing_deps_test',
'ninja_test',
'state_test',
'status_test',
'string_piece_util_test',
'subprocess_test',
'test',
'util_test']:
objs += cxx(name, variables=cxxvariables)
if platform.is_windows():
for name in ['includes_normalize_test', 'msvc_helper_test']:
objs += cxx(name, variables=cxxvariables)

ninja_test = n.build(binary('ninja_test'), 'link', objs, implicit=ninja_lib,
variables=[('libs', libs)])
n.newline()
all_targets += ninja_test


n.comment('Ancillary executables.')

if platform.is_aix() and '-maix64' not in ldflags:
Expand Down
4 changes: 2 additions & 2 deletions src/includes_normalize_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ TEST(IncludesNormalize, LongInvalidPath) {
// Construct max size path having cwd prefix.
// kExactlyMaxPath = "$cwd\\a\\aaaa...aaaa\0";
char kExactlyMaxPath[_MAX_PATH + 1];
ASSERT_NE(_getcwd(kExactlyMaxPath, sizeof kExactlyMaxPath), NULL);
ASSERT_STRNE(_getcwd(kExactlyMaxPath, sizeof kExactlyMaxPath), NULL);

int cwd_len = strlen(kExactlyMaxPath);
ASSERT_LE(cwd_len + 3 + 1, _MAX_PATH)
ASSERT_LE(cwd_len + 3 + 1, _MAX_PATH);
kExactlyMaxPath[cwd_len] = '\\';
kExactlyMaxPath[cwd_len + 1] = 'a';
kExactlyMaxPath[cwd_len + 2] = '\\';
Expand Down
3 changes: 1 addition & 2 deletions src/missing_deps_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct MissingDependencyScannerTest : public testing::Test {
scanner_(&delegate_, &deps_log_, &state_, &filesystem_) {
std::string err;
deps_log_.OpenForWrite(kTestDepsLogFilename, &err);
ASSERT_EQ("", err);
EXPECT_EQ("", err);
}

~MissingDependencyScannerTest() {
Expand Down Expand Up @@ -165,4 +165,3 @@ TEST_F(MissingDependencyScannerTest, CycleInGraph) {
std::vector<Node*> nodes = state_.RootNodes(&err);
ASSERT_NE("", err);
}

148 changes: 3 additions & 145 deletions src/ninja_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,151 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN32
#include "getopt.h"
#elif defined(_AIX)
#include "getopt.h"
#include <unistd.h>
#else
#include <getopt.h>
#endif

#include "test.h"
#include "line_printer.h"

using namespace std;

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];
testing::Test* g_current_test;
static int ntests;
static LinePrinter printer;

void RegisterTest(testing::Test* (*factory)(), const char* name) {
tests[ntests].factory = factory;
tests[ntests++].name = name;
}

namespace {
string StringPrintf(const char* format, ...) {
const int N = 1024;
char buf[N];

va_list ap;
va_start(ap, format);
vsnprintf(buf, N, format, ap);
va_end(ap);

return buf;
}

void Usage() {
fprintf(stderr,
"usage: ninja_tests [options]\n"
"\n"
"options:\n"
" --gtest_filter=POSITIVE_PATTERN[-NEGATIVE_PATTERN]\n"
" Run tests whose names match the positive but not the negative pattern.\n"
" '*' matches any substring. (gtest's ':', '?' are not implemented).\n");
}

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

bool ReadFlags(int* argc, char*** argv, const char** test_filter) {
enum { OPT_GTEST_FILTER = 1 };
const option kLongOptions[] = {
{ "gtest_filter", required_argument, NULL, OPT_GTEST_FILTER },
{ NULL, 0, NULL, 0 }
};

int opt;
while ((opt = getopt_long(*argc, *argv, "h", kLongOptions, NULL)) != -1) {
switch (opt) {
case OPT_GTEST_FILTER:
if (strchr(optarg, '?') == NULL && strchr(optarg, ':') == NULL) {
*test_filter = optarg;
break;
} // else fall through.
default:
Usage();
return false;
}
}
*argv += optind;
*argc -= optind;
return true;
}

} // namespace

bool testing::Test::Check(bool condition, const char* file, int line,
const char* error) {
if (!condition) {
printer.PrintOnNewLine(
StringPrintf("*** Failure in %s:%d\n%s\n", file, line, error));
failed_ = true;
}
return condition;
}
#include <gtest/gtest.h>

int main(int argc, char **argv) {
int tests_started = 0;

const char* test_filter = "*";
if (!ReadFlags(&argc, &argv, &test_filter))
return 1;

int nactivetests = 0;
for (int i = 0; i < ntests; i++)
if ((tests[i].should_run = TestMatchesFilter(tests[i].name, test_filter)))
++nactivetests;

bool passed = true;
for (int i = 0; i < ntests; i++) {
if (!tests[i].should_run) continue;

++tests_started;
testing::Test* test = tests[i].factory();
printer.Print(
StringPrintf("[%d/%d] %s", tests_started, nactivetests, tests[i].name),
LinePrinter::ELIDE);
test->SetUp();
test->Run();
test->TearDown();
if (test->Failed())
passed = false;
delete test;
}

printer.PrintOnNewLine(passed ? "passed\n" : "failed\n");
return passed ? EXIT_SUCCESS : EXIT_FAILURE;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Loading

0 comments on commit 4b6a8ac

Please sign in to comment.