From 1f8e19c49b70340dc216b453fa7f162a5d9ca05e Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Sun, 22 Sep 2019 17:13:31 +0200 Subject: [PATCH] Move to GTest for better integration. --- .travis.yml | 2 +- 2019/CMakeLists.txt | 11 ++-- 2019/tests/test_solutions.cpp | 98 ++++++++++++++++++++++------------- 3 files changed, 68 insertions(+), 43 deletions(-) diff --git a/.travis.yml b/.travis.yml index cd0dd7a..643a033 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ addons: packages: - libboost-filesystem-dev - libboost-program-options-dev - - libboost-test-dev + - libgtest-dev diff --git a/2019/CMakeLists.txt b/2019/CMakeLists.txt index 7e17420..e58e7e4 100644 --- a/2019/CMakeLists.txt +++ b/2019/CMakeLists.txt @@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.12) project(aoc2019) -find_package(Boost REQUIRED COMPONENTS program_options unit_test_framework filesystem) +find_package(Boost REQUIRED COMPONENTS program_options filesystem) +find_package(GTest) add_library(AoCSolutions src/implementations.hpp src/implementations.cpp src/day01.cpp src/days.hpp) target_compile_features(AoCSolutions PUBLIC cxx_std_17) @@ -13,10 +14,10 @@ target_link_libraries(runner AoCSolutions Boost::program_options) add_executable(test_solutions tests/test_solutions.cpp) target_compile_features(test_solutions PUBLIC cxx_std_17) -target_link_libraries(test_solutions AoCSolutions Boost::unit_test_framework Boost::filesystem) +target_link_libraries(test_solutions AoCSolutions Boost::filesystem gtest gtest_main) +target_compile_definitions(test_solutions PRIVATE "TEST_SAMPLES_DIR=\"${CMAKE_SOURCE_DIR}/tests/samples\"") target_include_directories(test_solutions PRIVATE "${CMAKE_SOURCE_DIR}/src") enable_testing() -add_test(NAME test_solutions - COMMAND test_solutions - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/tests") +include(GoogleTest) +gtest_discover_tests(test_solutions) diff --git a/2019/tests/test_solutions.cpp b/2019/tests/test_solutions.cpp index 370412d..399ff3c 100644 --- a/2019/tests/test_solutions.cpp +++ b/2019/tests/test_solutions.cpp @@ -1,15 +1,69 @@ #define BOOST_TEST_MODULE solutions_tests -#include +#include +#include #include #include -#include -#include +#include #include "implementations.hpp" -std::vector get_samples() { +class SolutionsTest : public testing::TestWithParam { +protected: + std::string input_data = ""; + std::string output_data = ""; + aoc2019::solution_t implementation = nullptr; + + // Read input data + void SetUp() override; + +private: + static void readToString(const std::string &name, std::string &target); +}; + +void SolutionsTest::SetUp() { + const auto input_name = GetParam(); + const auto output_name = input_name.substr(0, input_name.length() - 3) + ".out"; + + const char *base_name = input_name.c_str(); + if (const auto last_slash = input_name.rfind('/'); last_slash != std::string::npos) { + base_name += last_slash + 1; + } + + int day, part; + const auto read_result = std::sscanf(base_name, "%02d-%1d-", &day, &part); // NOLINT(cert-err34-c) + // Ensure that we've read the input files. + assert(read_result != 0); + + const bool part2 = part == 2; + implementation = aoc2019::get_implementation(day, part2); + + readToString(input_name, input_data); + readToString(output_name, output_data); +} + +void SolutionsTest::readToString(const std::string &name, std::string &target) { + std::ifstream source(name); + + target.assign(std::istreambuf_iterator(source), + std::istreambuf_iterator()); +} + +TEST_P(SolutionsTest, TestExpectedOutcome) { + std::stringstream input_buffer, output_buffer; + + // Sanity check, don't call null implementation + ASSERT_NE(implementation, nullptr); + + input_buffer.str(input_data); + + implementation(input_buffer, output_buffer); + + ASSERT_EQ(output_data, output_buffer.str()); +} + +static std::vector get_samples() { std::vector samples; - for (const auto &entry : boost::filesystem::directory_iterator("./samples")) { + for (const auto &entry : boost::filesystem::directory_iterator(TEST_SAMPLES_DIR)) { if (entry.path().filename().extension() == ".in") { samples.push_back(entry.path().string()); } @@ -21,35 +75,5 @@ std::vector get_samples() { return samples; } -static std::string read_file(const std::string &file_name) { - std::ifstream file(file_name); - return std::string(std::istreambuf_iterator(file), - std::istreambuf_iterator()); -} - -static void test_solution_impl(const std::string &input_name) { - std::regex name_parser("/(\\d{2})-(1|2).*\\.in$"); - std::smatch match; - // Sanity check, is this a parseable input file? - BOOST_TEST(std::regex_search(input_name, match, name_parser)); - - const auto output_filename = input_name.substr(0, input_name.length() - 3) + ".out"; - const int day = std::atoi(match[1].str().c_str()); - const int part2 = match[2].str() == "2"; - - const auto desired_output = read_file(output_filename); - const auto implementation = aoc2019::get_implementation(day, part2); - - std::stringstream output_buffer; - std::ifstream input(input_name); - - implementation(input, output_buffer); - - BOOST_TEST(desired_output == output_buffer.str()); -} - -BOOST_DATA_TEST_CASE(test_solution, - boost::unit_test::data::make(get_samples()), - input_name) { - test_solution_impl(input_name); -} +INSTANTIATE_TEST_CASE_P(InstantiatedSolutionsTest, SolutionsTest, + testing::ValuesIn(get_samples()));