test(tests): added test suite
The test suite is extensive. Note that LLMs were used to aid in the development of the test suite. All LLM generated code was manually reviewed.
This commit is contained in:
103
tests/utils/dependencies/context.cpp
Normal file
103
tests/utils/dependencies/context.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "serif/utils/dependencies/dependencies.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
namespace dependencies = serif::utils::dependencies;
|
||||
|
||||
struct Owned {};
|
||||
struct Borrowed {};
|
||||
struct Result {};
|
||||
}
|
||||
|
||||
TEST_CASE("Dependency contexts distinguish ownership and borrowed roles", "[unit][utils][dependencies]") {
|
||||
int value = 3;
|
||||
auto context = dependencies::make_dependency_context(dependencies::own<Owned>(value), dependencies::borrow<Borrowed>(value));
|
||||
auto selection = context.select(dependencies::KeyList<Borrowed>{});
|
||||
|
||||
value = 8;
|
||||
CHECK(context.get<Owned>() == 3);
|
||||
CHECK(context.get<Borrowed>() == 8);
|
||||
CHECK(std::addressof(selection.get<Borrowed>()) == std::addressof(value));
|
||||
|
||||
auto graph = dependencies::make_computation_graph(dependencies::make_computation<Result, dependencies::InputList<Borrowed>>([](int input) { return 2 * input; }));
|
||||
auto cache = dependencies::make_computation_cache(std::move(graph), selection);
|
||||
REQUIRE(cache.try_prepare(selection));
|
||||
CHECK(cache.get<Result>() == 16);
|
||||
|
||||
value = 9;
|
||||
CHECK(cache.get<Result>() == 16); // An accepted result remains frozen until explicitly refreshed.
|
||||
REQUIRE(cache.try_prepare(selection));
|
||||
CHECK(cache.get<Result>() == 18);
|
||||
}
|
||||
|
||||
TEST_CASE("Replacing a borrowed source invalidates its identity even at equal value", "[unit][utils][dependencies]") {
|
||||
int original = 4;
|
||||
int replacement = 4;
|
||||
int calls = 0;
|
||||
auto context = dependencies::make_dependency_context(dependencies::borrow<Borrowed>(original));
|
||||
auto graph = dependencies::make_computation_graph(dependencies::make_computation<Result, dependencies::InputList<Borrowed>>([&calls](int input) { ++calls; return input; }));
|
||||
auto cache = dependencies::make_computation_cache(std::move(graph), context);
|
||||
|
||||
REQUIRE(cache.try_prepare(context));
|
||||
context = dependencies::make_dependency_context(dependencies::borrow<Borrowed>(replacement));
|
||||
auto report = cache.try_prepare(context);
|
||||
REQUIRE(report);
|
||||
CHECK(report->source_changed<Borrowed>());
|
||||
CHECK(calls == 2);
|
||||
|
||||
original = 7;
|
||||
REQUIRE(cache.try_prepare(context));
|
||||
CHECK(calls == 2);
|
||||
CHECK(cache.get<Result>() == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("ComputationCache dependency results can move without leaving readable moved-from state", "[unit][utils][dependencies]") {
|
||||
const auto context = dependencies::make_dependency_context();
|
||||
auto graph = dependencies::make_computation_graph(dependencies::make_computation<Result, dependencies::InputList<>>([coefficient = std::make_unique<int>(7)] { return std::make_unique<int>(*coefficient); }));
|
||||
auto original = dependencies::make_computation_cache(std::move(graph), context);
|
||||
REQUIRE(original.try_prepare(context));
|
||||
|
||||
auto moved = std::move(original);
|
||||
CHECK_FALSE(original.ready());
|
||||
CHECK_FALSE(original.contains<Result>());
|
||||
CHECK_THROWS_AS(original.get<Result>(), std::logic_error);
|
||||
REQUIRE(moved.contains<Result>());
|
||||
CHECK(*moved.get<Result>() == 7);
|
||||
const auto report = moved.try_prepare(context);
|
||||
REQUIRE(report);
|
||||
CHECK(report->reused_count() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Combining disjoint contexts preserves owned values borrowed identities and selected tracking policies", "[unit][utils][dependencies]")
|
||||
{
|
||||
int value = 4;
|
||||
const auto borrowed = dependencies::make_dependency_context(dependencies::borrow<Borrowed>(value, dependencies::track_by([](const int input)
|
||||
{
|
||||
return input / 10;
|
||||
})));
|
||||
const auto context = dependencies::combine_dependency_contexts(
|
||||
dependencies::make_dependency_context(dependencies::own<Owned>(3)), borrowed.select(dependencies::KeyList<Borrowed>{}));
|
||||
CHECK(context.get<Owned>() == 3);
|
||||
CHECK(&context.get<Borrowed>() == &value);
|
||||
STATIC_CHECK(std::same_as<typename decltype(context)::Keys, dependencies::KeyList<Owned, Borrowed>>);
|
||||
|
||||
auto cache = dependencies::make_computation_cache(context, dependencies::make_computation<Result, dependencies::InputList<Owned, Borrowed>>([](const int owned, const int input)
|
||||
{
|
||||
return owned + input / 10;
|
||||
}));
|
||||
REQUIRE(cache.try_prepare(context));
|
||||
CHECK(cache.get<Result>() == 3);
|
||||
value = 8;
|
||||
const auto unchanged = cache.try_prepare(context);
|
||||
REQUIRE(unchanged);
|
||||
CHECK(unchanged->reused_count() == 1);
|
||||
value = 12;
|
||||
const auto changed = cache.try_prepare(context);
|
||||
REQUIRE(changed);
|
||||
CHECK(changed->source_changed<Borrowed>());
|
||||
CHECK(cache.get<Result>() == 4);
|
||||
}
|
||||
Reference in New Issue
Block a user