From b086f51d950fc762d530ed612d31c178e75d6c2f Mon Sep 17 00:00:00 2001 From: Frank Osterfeld Date: Mon, 13 Nov 2023 22:58:05 +0100 Subject: [PATCH] WIP: Enable Plugin tests for clang and use ut --- core/test/CMakeLists.txt | 6 +- core/test/app_grc.cpp | 197 +++++++++++++++++++-------------------- 2 files changed, 101 insertions(+), 102 deletions(-) diff --git a/core/test/CMakeLists.txt b/core/test/CMakeLists.txt index c3db0dec3..94cc706d6 100644 --- a/core/test/CMakeLists.txt +++ b/core/test/CMakeLists.txt @@ -42,7 +42,7 @@ add_ut_test(qa_port_array) add_ut_test(qa_thread_affinity) add_ut_test(qa_thread_pool) -if (NOT (EMSCRIPTEN OR (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang"))) +if (NOT EMSCRIPTEN) add_subdirectory(plugins) add_executable(qa_plugins_test qa_plugins_test.cpp) @@ -52,6 +52,8 @@ if (NOT (EMSCRIPTEN OR (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang"))) add_app_test(app_plugins_test app_plugins_test.cpp) - add_app_test(app_grc) + add_executable(app_grc app_grc.cpp) + setup_test_no_asan(app_grc) + target_link_libraries(app_grc PRIVATE yaml-cpp::yaml-cpp gr-basic gr-testing) endif () diff --git a/core/test/app_grc.cpp b/core/test/app_grc.cpp index 60be4f36a..8b316b19e 100644 --- a/core/test/app_grc.cpp +++ b/core/test/app_grc.cpp @@ -1,7 +1,3 @@ -// TODO: This is a test application that doesn't use ut framework. -// Once all problems with ut and plugins have been resolved, -// implement a unit testing suite - #include #include @@ -11,6 +7,8 @@ #include #include +#include + template struct ArraySource : public gr::Block> { std::array, 2> outA; @@ -34,7 +32,7 @@ struct ArraySink : public gr::Block> { ENABLE_REFLECTION_FOR_TEMPLATE(ArraySink, inA, inB, bool_setting, string_setting, bool_vector, string_vector, double_vector, int16_vector); struct TestContext { - TestContext(std::vector paths) : registry(), loader(®istry, std::move(paths)) {} + explicit TestContext(std::vector paths = {}) : registry(), loader(®istry, std::move(paths)) {} gr::BlockRegistry registry; gr::plugin_loader loader; @@ -57,122 +55,121 @@ collectEdges(const gr::Graph &graph) { }); return result; }; + +auto readFile(const auto &path) { + std::ifstream input(path); + std::stringstream buffer; + buffer << input.rdbuf(); + return buffer.str(); +}; + } // namespace -int -main(int argc, char *argv[]) { - std::vector paths; - if (argc < 2) { - paths.push_back(TESTS_BINARY_PATH "/plugins"); - } else { - for (int i = 1; i < argc; ++i) { - paths.push_back(argv[i]); - } - } +using namespace boost::ut; - auto read_file = [](const auto &path) { - std::ifstream input(path); - std::stringstream buffer; - buffer << input.rdbuf(); - return buffer.str(); - }; +namespace gr::app_grc_test { - TestContext context(std::move(paths)); +const boost::ut::suite AppGrcTests = [] { - // Test the basic graph loading and storing - { - using namespace gr; - registerBuiltinBlocks(&context.registry); +static TestContext context = [] { + TestContext ctx({TESTS_BINARY_PATH "/plugins"}); + registerBuiltinBlocks(&ctx.registry); + GP_REGISTER_NODE_RUNTIME(&ctx.registry, ArraySource, double); + GP_REGISTER_NODE_RUNTIME(&ctx.registry, ArraySink, double); + return ctx; +}(); - auto graph_source = read_file(TESTS_SOURCE_PATH "/grc/test.grc"); +"Basic graph loading and storing"_test = [] { + using namespace gr; + auto graph_source = readFile(TESTS_SOURCE_PATH "/grc/test.grc"); - auto graph = gr::load_grc(context.loader, graph_source); - auto graph_saved_source = gr::save_grc(graph); + auto graph = gr::load_grc(context.loader, graph_source); + auto graph_saved_source = gr::save_grc(graph); - auto graph_expected_source = read_file(TESTS_SOURCE_PATH "/grc/test.grc.expected"); - assert(graph_saved_source + "\n" - == graph_expected_source); // TODO: this is not a good assert since we will add new parameters regularly... should not be identity but checking critical parameter/aspects + auto graph_expected_source = readFile(TESTS_SOURCE_PATH "/grc/test.grc.expected"); + expect(graph_saved_source + "\n" + == graph_expected_source); // TODO: this is not a good assert since we will add new parameters regularly... should not be identity but checking critical parameter/aspects - gr::scheduler::Simple scheduler(std::move(graph)); - scheduler.runAndWait(); - } + gr::scheduler::Simple scheduler(std::move(graph)); + scheduler.runAndWait(); +}; +"Save and load"_test = [] { // Test if we get the same graph when saving it and loading the saved // data into another graph - { - using namespace gr; - registerBuiltinBlocks(&context.registry); - - auto graph_source = read_file(TESTS_SOURCE_PATH "/grc/test.grc"); + using namespace gr; + auto graph_source = readFile(TESTS_SOURCE_PATH "/grc/test.grc"); + try { auto graph_1 = gr::load_grc(context.loader, graph_source); auto graph_saved_source = gr::save_grc(graph_1); - auto graph_2 = gr::load_grc(context.loader, graph_saved_source); - - assert(collectBlocks(graph_1) == collectBlocks(graph_2)); - assert(collectEdges(graph_1) == collectEdges(graph_2)); + expect(collectBlocks(graph_1) == collectBlocks(graph_2)); + expect(collectEdges(graph_1) == collectEdges(graph_2)); + } catch (const std::string &e) { + fmt::println(std::cerr, "Unexpected exception: {}", e); + expect(false); } +}; - // Test that connections involving port collections are handled correctly - { - using namespace gr; - registerBuiltinBlocks(&context.registry); - GP_REGISTER_NODE_RUNTIME(&context.registry, ArraySource, double); - GP_REGISTER_NODE_RUNTIME(&context.registry, ArraySink, double); +"Port collections"_test = [] { + using namespace gr; - gr::Graph graph_1; - auto &arraySink = graph_1.emplaceBlock>(); - auto &arraySource0 = graph_1.emplaceBlock>(); - auto &arraySource1 = graph_1.emplaceBlock>(); + gr::Graph graph_1; + auto &arraySink = graph_1.emplaceBlock>(); + auto &arraySource0 = graph_1.emplaceBlock>(); + auto &arraySource1 = graph_1.emplaceBlock>(); - graph_1.connect<"outA", 0>(arraySource0).to<"inB", 1>(arraySink); - graph_1.connect<"outA", 1>(arraySource1).to<"inB", 0>(arraySink); - graph_1.connect<"outB", 0>(arraySource0).to<"inA", 0>(arraySink); - graph_1.connect<"outB", 1>(arraySource1).to<"inA", 1>(arraySink); + graph_1.connect<"outA", 0>(arraySource0).to<"inB", 1>(arraySink); + graph_1.connect<"outA", 1>(arraySource1).to<"inB", 0>(arraySink); + graph_1.connect<"outB", 0>(arraySource0).to<"inA", 0>(arraySink); + graph_1.connect<"outB", 1>(arraySource1).to<"inA", 1>(arraySink); - assert(graph_1.performConnections()); + expect(graph_1.performConnections()); - const auto graph_1_saved = gr::save_grc(graph_1); - const auto graph_2 = gr::load_grc(context.loader, graph_1_saved); + const auto graph_1_saved = gr::save_grc(graph_1); + const auto graph_2 = gr::load_grc(context.loader, graph_1_saved); - assert(collectBlocks(graph_1) == collectBlocks(graph_2)); - assert(collectEdges(graph_1) == collectEdges(graph_2)); - } + expect(collectBlocks(graph_1) == collectBlocks(graph_2)); + expect(collectEdges(graph_1) == collectEdges(graph_2)); +}; - // Test settings serialization - { - using namespace gr; - registerBuiltinBlocks(&context.registry); - GP_REGISTER_NODE_RUNTIME(&context.registry, ArraySink, double); - - gr::Graph graph_1; - const auto expectedString = std::string("abc"); - const auto expectedBool = true; - const auto expectedStringVector = std::vector{ "a", "b", "c" }; - const auto expectedBoolVector = std::vector{ true, false, true }; - const auto expectedDoubleVector = std::vector{ 1., 2., 3. }; - const auto expectedInt16Vector = std::vector{ 1, 2, 3 }; - auto &arraySink = graph_1.emplaceBlock>({ { "bool_setting", expectedBool }, - { "string_setting", expectedString }, - { "bool_vector", expectedBoolVector }, - { "string_vector", expectedStringVector }, - { "double_vector", expectedDoubleVector }, - { "int16_vector", expectedInt16Vector } }); - - const auto graph_1_saved = gr::save_grc(graph_1); - const auto graph_2 = gr::load_grc(context.loader, graph_1_saved); - graph_2.forEachBlock([&](const auto &node) { - const auto settings = node.settings().get(); - assert(std::get(settings.at("bool_setting")) == expectedBool); - assert(std::get(settings.at("string_setting")) == expectedString); - assert(std::get>(settings.at("bool_vector")) == expectedBoolVector); - assert(std::get>(settings.at("string_vector")) == expectedStringVector); - assert(std::get>(settings.at("double_vector")) == expectedDoubleVector); - assert(std::get>(settings.at("int16_vector")) == expectedInt16Vector); - }); - - assert(collectBlocks(graph_1) == collectBlocks(graph_2)); - assert(collectEdges(graph_1) == collectEdges(graph_2)); - } -} +"Settings serialization"_test = [] { + using namespace gr; + + gr::Graph graph_1; + const auto expectedString = std::string("abc"); + const auto expectedBool = true; + const auto expectedStringVector = std::vector{ "a", "b", "c" }; + const auto expectedBoolVector = std::vector{ true, false, true }; + const auto expectedDoubleVector = std::vector{ 1., 2., 3. }; + const auto expectedInt16Vector = std::vector{ 1, 2, 3 }; + auto &arraySink = graph_1.emplaceBlock>({ { "bool_setting", expectedBool }, + { "string_setting", expectedString }, + { "bool_vector", expectedBoolVector }, + { "string_vector", expectedStringVector }, + { "double_vector", expectedDoubleVector }, + { "int16_vector", expectedInt16Vector } }); + + const auto graph_1_saved = gr::save_grc(graph_1); + const auto graph_2 = gr::load_grc(context.loader, graph_1_saved); + graph_2.forEachBlock([&](const auto &node) { + const auto settings = node.settings().get(); + expect(std::get(settings.at("bool_setting")) == expectedBool); + expect(std::get(settings.at("string_setting")) == expectedString); + expect(std::get>(settings.at("bool_vector")) == expectedBoolVector); + expect(std::get>(settings.at("string_vector")) == expectedStringVector); + expect(std::get>(settings.at("double_vector")) == expectedDoubleVector); + expect(std::get>(settings.at("int16_vector")) == expectedInt16Vector); + }); + + expect(collectBlocks(graph_1) == collectBlocks(graph_2)); + expect(collectEdges(graph_1) == collectEdges(graph_2)); +}; + +}; + +} // namespace gr::app_grc_test +int +main() { /* tests are statically executed */ +} \ No newline at end of file