diff --git a/CMakeLists.txt b/CMakeLists.txt index 028f4c5e..af42e3e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ xo_toplevel_compile_options() # ---------------------------------------------------------------- add_subdirectory(src/printjson) -#add_subdirectory(utest) +add_subdirectory(utest) # ---------------------------------------------------------------- # provide find_package() support for printjson customers diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt new file mode 100644 index 00000000..0b2177e8 --- /dev/null +++ b/utest/CMakeLists.txt @@ -0,0 +1,58 @@ +# build unittest printjson/utest + +set(SELF_EXE utest.printjson) +set(SELF_SRCS printjson_utest_main.cpp PrintJson.test.cpp) + +add_executable(${SELF_EXE} ${SELF_SRCS}) +xo_include_options2(${SELF_EXE}) + +add_test(NAME ${SELF_EXE} COMMAND ${SELF_EXE}) +target_code_coverage(${SELF_EXE} AUTO ALL) + +# ---------------------------------------------------------------- +# generic project dependency + +## PROJECT_SOURCE_DIR: +## so we can for example write +## #include "indentlog/scope.hpp" +## from anywhere in the project +## PROJECT_BINARY_DIR: +## since version file will be in build directory, need that directory +## to also be included in compiler's include path +## +#target_include_directories(${SELF_EXE} PUBLIC +# ${PROJECT_SOURCE_DIR} +# ${PROJECT_BINARY_DIR}) + +# ---------------------------------------------------------------- +# dependencies on this codebase + +xo_self_dependency(${SELF_EXE} printjson) + +# ---------------------------------------------------------------- +# dependencies on other codebases + +xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2) + +# need this so that catch2/include appears in compile_commands.json, +# on which lsp integration relies. +# +# See also /nix/store/*-catch2-*/lib/cmake/Catch2/ParseAndAddCatchTests.cmake; +# commands here derived from ^ .cmake file +# +#find_path(CATCH_INCLUDE_DIR "catch2/catch.hpp") +#target_include_directories(${SELF_EXE} PUBLIC ${CATCH_INCLUDE_DIR}) + +# supplied from xo_include_options2() +## ---------------------------------------------------------------- +## make standard directories for std:: includes explicit +## so that +## (1) they appear in compile_commands.json. +## (2) clangd (run from emacs lsp-mode) can find them +## +#if(CMAKE_EXPORT_COMPILE_COMMANDS) +# set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES +# ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) +#endif() + +# end CMakeLists.txt diff --git a/utest/CMakeLists.txt.safe b/utest/CMakeLists.txt.safe new file mode 100644 index 00000000..60200a81 --- /dev/null +++ b/utest/CMakeLists.txt.safe @@ -0,0 +1,55 @@ +# build unittest printjson/utest + +set(SELF_EXECUTABLE_NAME utest.printjson) +set(SELF_SOURCE_FILES printjson_utest_main.cpp PrintJson.test.cpp) + +add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) + +add_test(NAME ${SELF_EXECUTABLE_NAME} COMMAND ${SELF_EXECUTABLE_NAME}) + +# ---------------------------------------------------------------- +# generic project dependency + +# PROJECT_SOURCE_DIR: +# so we can for example write +# #include "indentlog/scope.hpp" +# from anywhere in the project +# PROJECT_BINARY_DIR: +# since version file will be in build directory, need that directory +# to also be included in compiler's include path +# +target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR}) + +# ---------------------------------------------------------------- +# internal dependencies: logutil, ... + +target_link_libraries(${SELF_EXECUTABLE_NAME} PUBLIC printjson) + +# ---------------------------------------------------------------- +# 3rd part dependency: catch2: + +find_package(Catch2 2 REQUIRED) + +# need this so that catch2/include appears in compile_commands.json, +# on which lsp integration relies. +# +# See also /nix/store/*-catch2-*/lib/cmake/Catch2/ParseAndAddCatchTests.cmake; +# commands here derived from ^ .cmake file +# +find_path(CATCH_INCLUDE_DIR "catch2/catch.hpp") +target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC ${CATCH_INCLUDE_DIR}) + +# ---------------------------------------------------------------- +# make standard directories for std:: includes explicit +# so that +# (1) they appear in compile_commands.json. +# (2) clangd (run from emacs lsp-mode) can find them +# +if(CMAKE_EXPORT_COMPILE_COMMANDS) + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES + ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) +endif() + +# end CMakeLists.txt diff --git a/utest/PrintJson.test.cpp b/utest/PrintJson.test.cpp new file mode 100644 index 00000000..51259e23 --- /dev/null +++ b/utest/PrintJson.test.cpp @@ -0,0 +1,124 @@ +/* file PrintJson.test.cpp + * + * author: Roland Conybeare, Aug 2022 + */ + +#include "xo/printjson/PrintJson.hpp" +#include "xo/printjson/init_printjson.hpp" +#include "xo/reflect/Reflect.hpp" +#include "xo/reflect/StructReflector.hpp" +#include +#include +#include + +//#define STRINGIFY(x) #x + +namespace xo { + using xo::json::PrintJson; + using xo::reflect::Reflect; + using xo::reflect::StructReflector; + using xo::reflect::TaggedPtr; + + namespace ut { + InitEvidence s_init_evidence = InitSubsys::require(); + + namespace { + struct TestStruct0 {}; + } + + TEST_CASE("print-json-empty-struct", "[printjson]") { + INFO(tag("s_init_evidence", s_init_evidence)); + + StructReflector sr; + + sr.require_complete(); + + TestStruct0 recd0; + + PrintJson print_json; + + TaggedPtr tp = Reflect::make_tp(&recd0); + + std::stringstream ss; + + print_json.print(tp, &ss); + + REQUIRE(ss.str() == std::string("{\"_name_\": \"TestStruct0\"}")); + } /*TEST_CASE(print-json-empty-struct)*/ + + namespace { + struct TestStruct1 { + std::int16_t i16_; std::uint16_t u16_; + std::int32_t i32_; std::uint32_t u32_; + std::int64_t i64_; std::uint64_t u64_; + float f32_; double f64_; + std::string s_; + }; + } + + TEST_CASE("print-json-s1", "[printjson]") { + INFO(tag("s_init_evidence", s_init_evidence)); + + StructReflector sr; + { + REFLECT_MEMBER(sr, i16); + REFLECT_MEMBER(sr, u16); + REFLECT_MEMBER(sr, i32); + REFLECT_MEMBER(sr, u32); + REFLECT_MEMBER(sr, i64); + REFLECT_MEMBER(sr, u64); + REFLECT_MEMBER(sr, f32); + REFLECT_MEMBER(sr, f64); + REFLECT_MEMBER(sr, s); + + sr.require_complete(); + } + + TestStruct1 recd1{-1, 2, -3, 4, -5, 6, 1.23f, 4.56, "hello, world"}; + + PrintJson print_json; + + TaggedPtr tp = Reflect::make_tp(&recd1); + + std::stringstream ss; + + print_json.print(tp, &ss); + + REQUIRE(ss.str() == std::string("{\"_name_\": \"TestStruct1\"" + ", \"i16\": -1" + ", \"u16\": 2" + ", \"i32\": -3" + ", \"u32\": 4" + ", \"i64\": -5" + ", \"u64\": 6" + ", \"f32\": 1.23" + ", \"f64\": 4.56" + ", \"s\": \"hello, world\"}")); + } /*TEST_CASE(print-json-s1)*/ + + TEST_CASE("print-json-v1", "[printjson]") { + INFO(tag("s_init_evidence", s_init_evidence)); + + std::vector v1{1, 2, 3}; + + PrintJson print_json; + + TaggedPtr tp = Reflect::make_tp(&v1); + + std::stringstream ss; + + print_json.print(tp, &ss); + + REQUIRE(ss.str() == std::string("[1, 2, 3]")); + } /*TEST_CASE(print-json-v1)*/ + + /* also see tests: + * [option_util/utest/Px2.test.cpp] + * [option_util/utest/Size2.test.cpp] + * [option_util/utest/PxSize2.test.cpp] + */ + } /*namespace ut */ +} /*namespace xo*/ + + +/* end StructReflector.test.cpp */ diff --git a/utest/printjson_utest_main.cpp b/utest/printjson_utest_main.cpp new file mode 100644 index 00000000..e7c11b66 --- /dev/null +++ b/utest/printjson_utest_main.cpp @@ -0,0 +1,6 @@ +/* file printjson_utest_main.cpp */ + +#define CATCH_CONFIG_MAIN +#include "catch2/catch.hpp" + +/* end printjson_utest_main.cpp */