File indexing completed on 2026-10-29 08:25:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <algorithms/algorithm.h>
0010
0011 #include <catch2/catch_test_macros.hpp>
0012 #include <catch2/matchers/catch_matchers_string.hpp>
0013
0014 #include <cstddef>
0015 #include <latch>
0016 #include <string>
0017 #include <thread>
0018 #include <vector>
0019
0020 using namespace algorithms;
0021 using Catch::Matchers::ContainsSubstring;
0022
0023 namespace algorithm_svc_test {
0024
0025 using IntAlgorithm = Algorithm<Input<int>, Output<int>>;
0026 using DoubleAlgorithm = Algorithm<Input<double>, Output<double>>;
0027
0028 class AddOne : public IntAlgorithm {
0029 public:
0030 AddOne() : IntAlgorithm{"AddOne", {"in"}, {"out"}, "Adds one"} {}
0031 void process(const Input& input, const Output& output) const final {
0032 *std::get<0>(output) = *std::get<0>(input) + 1;
0033 }
0034 };
0035
0036 class Twice : public IntAlgorithm {
0037 public:
0038 Twice() : IntAlgorithm{"Twice", {"in"}, {"out"}, "Multiplies by two"} {}
0039 void process(const Input& input, const Output& output) const final {
0040 *std::get<0>(output) = *std::get<0>(input) * 2;
0041 }
0042 };
0043
0044 class Half : public DoubleAlgorithm {
0045 public:
0046 Half() : DoubleAlgorithm{"Half", {"in"}, {"out"}, "Divides by two"} {}
0047 void process(const Input& input, const Output& output) const final {
0048 *std::get<0>(output) = *std::get<0>(input) / 2;
0049 }
0050 };
0051
0052 }
0053
0054 using namespace algorithm_svc_test;
0055
0056 TEST_CASE("AlgorithmSvc creates registered algorithms by type and name", "[algorithm]") {
0057 auto& svc = AlgorithmSvc::instance();
0058 CHECK(svc.name() == "AlgorithmSvc");
0059
0060 svc.add<AddOne>();
0061 svc.add<Twice>();
0062 svc.add<Half>();
0063
0064 svc.add<AddOne>();
0065
0066
0067 CHECK_THROWS_AS(svc.ls<IntAlgorithm>(), Error);
0068 CHECK_THROWS_WITH(svc.get<IntAlgorithm>("algorithm_svc_test::AddOne"),
0069 "Attempt to use AlgorithmSvc, but service not yet marked as ready");
0070
0071 ServiceSvc::instance().init();
0072 REQUIRE(svc.ready());
0073
0074
0075 CHECK(svc.ls<IntAlgorithm>() ==
0076 std::vector<std::string>{"algorithm_svc_test::AddOne", "algorithm_svc_test::Twice"});
0077 CHECK(svc.ls<DoubleAlgorithm>() == std::vector<std::string>{"algorithm_svc_test::Half"});
0078 CHECK(svc.ls<Algorithm<Input<float>, Output<float>>>().empty());
0079
0080
0081 const auto add_one = svc.get<IntAlgorithm>("algorithm_svc_test::AddOne");
0082 const auto twice = svc.get<IntAlgorithm>("algorithm_svc_test::Twice");
0083 const auto half = svc.get<DoubleAlgorithm>("algorithm_svc_test::Half");
0084 REQUIRE(add_one != nullptr);
0085 REQUIRE(twice != nullptr);
0086 REQUIRE(half != nullptr);
0087 CHECK(add_one != svc.get<IntAlgorithm>("algorithm_svc_test::AddOne"));
0088 CHECK(add_one->name() == "AddOne");
0089 CHECK(twice->name() == "Twice");
0090
0091 const int i = 3;
0092 int j = 0;
0093 add_one->process({&i}, {&j});
0094 CHECK(j == 4);
0095 twice->process({&i}, {&j});
0096 CHECK(j == 6);
0097
0098 const double x = 3.;
0099 double y = 0.;
0100 half->process({&x}, {&y});
0101 CHECK(y == 1.5);
0102
0103
0104 CHECK_THROWS_WITH(svc.get<IntAlgorithm>("algorithm_svc_test::Half"),
0105 ContainsSubstring("No factory with name algorithm_svc_test::Half and type"));
0106 CHECK_THROWS_WITH((svc.get<Algorithm<Input<float>, Output<float>>>("AddOne")),
0107 ContainsSubstring("No factory with name AddOne"));
0108 CHECK_THROWS_WITH(svc.get<IntAlgorithm>(""), "Invalid name provided: ''");
0109
0110
0111 constexpr std::size_t kThreads = 8;
0112 std::vector<int> results(kThreads, 0);
0113 {
0114 std::latch start{kThreads};
0115 std::vector<std::jthread> threads;
0116 for (std::size_t t = 0; t < kThreads; ++t) {
0117 threads.emplace_back([&svc, &start, &results, t] {
0118 start.arrive_and_wait();
0119 svc.add<Twice>();
0120 const auto names = svc.ls<IntAlgorithm>();
0121 const auto algo = svc.get<IntAlgorithm>(names[t % names.size()]);
0122 const int in = static_cast<int>(t);
0123 algo->process({&in}, {&results[t]});
0124 });
0125 }
0126 }
0127 for (std::size_t t = 0; t < kThreads; ++t) {
0128 CHECK(results[t] == ((t % 2 == 0) ? static_cast<int>(t) + 1 : 2 * static_cast<int>(t)));
0129 }
0130 }