diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d3b7b6d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.20) +project(cppbessot LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if(NOT DEFINED DB_SCHEMA_DIR_TO_GENERATE OR "${DB_SCHEMA_DIR_TO_GENERATE}" STREQUAL "") + message(FATAL_ERROR + "Set DB_SCHEMA_DIR_TO_GENERATE to the exact schema directory basename to test, for example -DDB_SCHEMA_DIR_TO_GENERATE=v1.2.") +endif() + +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CppBeSSOT.cmake") + +include(CTest) + +if(BUILD_TESTING) + add_subdirectory(tests EXCLUDE_FROM_ALL) +endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..b08ed8d --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,7 @@ +if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/googletest/CMakeLists.txt") + message(FATAL_ERROR + "GoogleTest submodule is missing. Run `git submodule update --init --recursive tests/googletest` from the cppbessot repo root.") +endif() + +add_subdirectory(googletest EXCLUDE_FROM_ALL) +add_subdirectory(cpp-serdes EXCLUDE_FROM_ALL) diff --git a/tests/cpp-serdes/CMakeLists.txt b/tests/cpp-serdes/CMakeLists.txt new file mode 100644 index 0000000..4f9885f --- /dev/null +++ b/tests/cpp-serdes/CMakeLists.txt @@ -0,0 +1,26 @@ +include(GoogleTest) + +set(CPP_SERDES_TEST_NAME "cpp_serdes_${DB_SCHEMA_DIR_TO_GENERATE}") +string(REPLACE "." "_" CPP_SERDES_TEST_NAME "${CPP_SERDES_TEST_NAME}") +string(REPLACE "-" "_" CPP_SERDES_TEST_NAME "${CPP_SERDES_TEST_NAME}") + +set(CPP_SERDES_TEST_SOURCES + main.cpp + government_address_roundtrip_test.cpp + trip_attempt_result_roundtrip_test.cpp +) + +add_executable(${CPP_SERDES_TEST_NAME} ${CPP_SERDES_TEST_SOURCES}) +target_compile_features(${CPP_SERDES_TEST_NAME} PRIVATE cxx_std_20) +target_include_directories(${CPP_SERDES_TEST_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") +target_link_libraries(${CPP_SERDES_TEST_NAME} + PRIVATE + cppbessot::openai_model_gen + GTest::gtest_main +) +target_compile_definitions(${CPP_SERDES_TEST_NAME} + PRIVATE + CPP_SERDES_SCHEMA_DIR="${DB_SCHEMA_DIR_TO_GENERATE}" +) + +gtest_discover_tests(${CPP_SERDES_TEST_NAME}) diff --git a/tests/cpp-serdes/government_address_roundtrip_test.cpp b/tests/cpp-serdes/government_address_roundtrip_test.cpp new file mode 100644 index 0000000..14bb398 --- /dev/null +++ b/tests/cpp-serdes/government_address_roundtrip_test.cpp @@ -0,0 +1,27 @@ +#include + +#include + +#include "test_helpers.h" + +TEST(GovernmentAddressJsonSerdes, RoundTripsViaJson) +{ + models::GovernmentAddress original{}; + original.id = "gov-addr-42"; + original.addressLabel = "District Office"; + original.regionLookupKey = "region-west"; + + const nlohmann::json expected = { + {"id", "gov-addr-42"}, + {"addressLabel", "District Office"}, + {"regionLookupKey", "region-west"}, + }; + + const nlohmann::json serialized = original.toJson(); + expect_json_roundtrip_equal(serialized, expected); + + const models::GovernmentAddress reparsed = models::GovernmentAddress::fromJson(serialized); + EXPECT_EQ(reparsed.id, original.id); + EXPECT_EQ(reparsed.addressLabel, original.addressLabel); + EXPECT_EQ(reparsed.regionLookupKey, original.regionLookupKey); +} diff --git a/tests/cpp-serdes/main.cpp b/tests/cpp-serdes/main.cpp new file mode 100644 index 0000000..97a847a --- /dev/null +++ b/tests/cpp-serdes/main.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/cpp-serdes/test_helpers.h b/tests/cpp-serdes/test_helpers.h new file mode 100644 index 0000000..6070db7 --- /dev/null +++ b/tests/cpp-serdes/test_helpers.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +inline void expect_json_roundtrip_equal(const nlohmann::json& actual, const nlohmann::json& expected) +{ + EXPECT_EQ(actual, expected) << "expected: " << expected.dump() << "\nactual: " << actual.dump(); +} diff --git a/tests/cpp-serdes/trip_attempt_result_roundtrip_test.cpp b/tests/cpp-serdes/trip_attempt_result_roundtrip_test.cpp new file mode 100644 index 0000000..81e6673 --- /dev/null +++ b/tests/cpp-serdes/trip_attempt_result_roundtrip_test.cpp @@ -0,0 +1,54 @@ +#include + +#include + +#include "test_helpers.h" + +TEST(TripAttemptResultJsonSerdes, RoundTripsViaJson) +{ + models::TripAttemptResult original{}; + original.id = "attempt-result-7"; + original.result = "failed"; + original.retryReason = "weather"; + original.governmentSuspensionReason = ""; + original.governmentTerminationReason = ""; + original.complianceSuspensionReason = ""; + original.complianceTerminationReason = ""; + original.policySuspensionReason = ""; + original.policyTerminationReason = ""; + original.cancelationReason = ""; + original.failureReason = "blocked-route"; + original.details = "bridge closure"; + + const nlohmann::json expected = { + {"id", "attempt-result-7"}, + {"result", "failed"}, + {"retryReason", "weather"}, + {"governmentSuspensionReason", ""}, + {"governmentTerminationReason", ""}, + {"complianceSuspensionReason", ""}, + {"complianceTerminationReason", ""}, + {"policySuspensionReason", ""}, + {"policyTerminationReason", ""}, + {"cancelationReason", ""}, + {"failureReason", "blocked-route"}, + {"details", "bridge closure"}, + }; + + const nlohmann::json serialized = original.toJson(); + expect_json_roundtrip_equal(serialized, expected); + + const models::TripAttemptResult reparsed = models::TripAttemptResult::fromJson(serialized); + EXPECT_EQ(reparsed.id, original.id); + EXPECT_EQ(reparsed.result, original.result); + EXPECT_EQ(reparsed.retryReason, original.retryReason); + EXPECT_EQ(reparsed.governmentSuspensionReason, original.governmentSuspensionReason); + EXPECT_EQ(reparsed.governmentTerminationReason, original.governmentTerminationReason); + EXPECT_EQ(reparsed.complianceSuspensionReason, original.complianceSuspensionReason); + EXPECT_EQ(reparsed.complianceTerminationReason, original.complianceTerminationReason); + EXPECT_EQ(reparsed.policySuspensionReason, original.policySuspensionReason); + EXPECT_EQ(reparsed.policyTerminationReason, original.policyTerminationReason); + EXPECT_EQ(reparsed.cancelationReason, original.cancelationReason); + EXPECT_EQ(reparsed.failureReason, original.failureReason); + EXPECT_EQ(reparsed.details, original.details); +}