Skip to content

Commit

Permalink
WIP: Enable Plugin tests for clang and use ut
Browse files Browse the repository at this point in the history
  • Loading branch information
frankosterfeld committed Nov 14, 2023
1 parent 9f24bac commit b086f51
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 102 deletions.
6 changes: 4 additions & 2 deletions core/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 ()
197 changes: 97 additions & 100 deletions core/test/app_grc.cpp
Original file line number Diff line number Diff line change
@@ -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 <fstream>
#include <sstream>

Expand All @@ -11,6 +7,8 @@
#include <build_configure.hpp>
#include <gnuradio-4.0/basic/common_blocks.hpp>

#include <boost/ut.hpp>

template<typename T>
struct ArraySource : public gr::Block<ArraySource<T>> {
std::array<gr::PortOut<T>, 2> outA;
Expand All @@ -34,7 +32,7 @@ struct ArraySink : public gr::Block<ArraySink<T>> {
ENABLE_REFLECTION_FOR_TEMPLATE(ArraySink, inA, inB, bool_setting, string_setting, bool_vector, string_vector, double_vector, int16_vector);

struct TestContext {
TestContext(std::vector<std::filesystem::path> paths) : registry(), loader(&registry, std::move(paths)) {}
explicit TestContext(std::vector<std::filesystem::path> paths = {}) : registry(), loader(&registry, std::move(paths)) {}

gr::BlockRegistry registry;
gr::plugin_loader loader;
Expand All @@ -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<std::filesystem::path> 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<ArraySink<double>>();
auto &arraySource0 = graph_1.emplaceBlock<ArraySource<double>>();
auto &arraySource1 = graph_1.emplaceBlock<ArraySource<double>>();
gr::Graph graph_1;
auto &arraySink = graph_1.emplaceBlock<ArraySink<double>>();
auto &arraySource0 = graph_1.emplaceBlock<ArraySource<double>>();
auto &arraySource1 = graph_1.emplaceBlock<ArraySource<double>>();

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<std::string>{ "a", "b", "c" };
const auto expectedBoolVector = std::vector<bool>{ true, false, true };
const auto expectedDoubleVector = std::vector<double>{ 1., 2., 3. };
const auto expectedInt16Vector = std::vector<int16_t>{ 1, 2, 3 };
auto &arraySink = graph_1.emplaceBlock<ArraySink<double>>({ { "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<bool>(settings.at("bool_setting")) == expectedBool);
assert(std::get<std::string>(settings.at("string_setting")) == expectedString);
assert(std::get<std::vector<bool>>(settings.at("bool_vector")) == expectedBoolVector);
assert(std::get<std::vector<std::string>>(settings.at("string_vector")) == expectedStringVector);
assert(std::get<std::vector<double>>(settings.at("double_vector")) == expectedDoubleVector);
assert(std::get<std::vector<int16_t>>(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<std::string>{ "a", "b", "c" };
const auto expectedBoolVector = std::vector<bool>{ true, false, true };
const auto expectedDoubleVector = std::vector<double>{ 1., 2., 3. };
const auto expectedInt16Vector = std::vector<int16_t>{ 1, 2, 3 };
auto &arraySink = graph_1.emplaceBlock<ArraySink<double>>({ { "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<bool>(settings.at("bool_setting")) == expectedBool);
expect(std::get<std::string>(settings.at("string_setting")) == expectedString);
expect(std::get<std::vector<bool>>(settings.at("bool_vector")) == expectedBoolVector);
expect(std::get<std::vector<std::string>>(settings.at("string_vector")) == expectedStringVector);
expect(std::get<std::vector<double>>(settings.at("double_vector")) == expectedDoubleVector);
expect(std::get<std::vector<int16_t>>(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 */
}

0 comments on commit b086f51

Please sign in to comment.