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:
2026-11-09 13:53:17 -05:00
parent 74e55a6859
commit cb20faeb3d
202 changed files with 35505 additions and 953 deletions

93
tests/model/state.cpp Normal file
View File

@@ -0,0 +1,93 @@
#include <array>
#include <limits>
#include <utility>
#include <vector>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include "serif/discretization/blocks/fields.hpp"
#include "serif/model/state.hpp"
namespace {
namespace blocks = serif::discretization::blocks;
namespace dependencies = serif::utils::dependencies;
using Density = blocks::density::mass;
using Shape = blocks::surface_deformation::coefficients;
using ShapeRow = blocks::surface_deformation::shape_equilibrium;
using Constant = blocks::barotropic_constant::mass_normalization;
using Layout = blocks::SystemLayout<dependencies::KeyList<Density, Shape, Constant>, dependencies::KeyList<ShapeRow, Constant, Density>>;
using State = serif::model::StellarState<Layout>;
}
TEST_CASE("A stellar state owns its layout and exposes fields in physical rather than residual order", "[model][state][unit]") {
Layout layout{.state_sizes = {2, 3, 1}, .residual_sizes = {3, 1, 2}};
State state(layout, {1.0, 2.0, 3.0, 4.0, 5.0, 6.0});
layout.state_sizes[0] = 9;
layout.residual_sizes[0] = 8;
CHECK(state.layout().state_sizes == std::array<std::size_t, 3>{2, 3, 1});
CHECK(state.layout().residual_sizes == std::array<std::size_t, 3>{3, 1, 2});
CHECK(state.layout().offset<blocks::RepresentedValueKind::residual, Density>() == 4);
CHECK(state.get<Density>().data() == state.values().data());
CHECK(state.get<Shape>().data() == state.values().data() + 2);
CHECK(state.get<Constant>().data() == state.values().data() + 5);
REQUIRE(state.get<Shape>().size() == 3);
state.get<Shape>()[1] = 7.0;
state.get<Constant>()[0] = 8.0;
CHECK(state.values()[3] == 7.0);
CHECK(state.values()[5] == 8.0);
const State& read_only = state;
CHECK(read_only.get<Shape>()[1] == 7.0);
CHECK(read_only.values().data() == state.values().data());
}
TEST_CASE("Copied and moved stellar candidates retain independent coefficients and valid typed access", "[model][state][ownership]") {
const Layout layout{.state_sizes = {2, 3, 1}, .residual_sizes = {3, 1, 2}};
State original(layout, {1.0, 2.0, 3.0, 4.0, 5.0, 6.0});
State candidate = original;
CHECK(candidate.values().data() != original.values().data());
candidate.get<Density>()[0] = 9.0;
candidate.get<Shape>()[2] = 10.0;
CHECK(original.get<Density>()[0] == 1.0);
CHECK(original.get<Shape>()[2] == 5.0);
State moved(std::move(candidate));
CHECK(moved.layout() == layout);
CHECK(moved.get<Density>()[0] == 9.0);
CHECK(moved.get<Shape>()[2] == 10.0);
CHECK(moved.get<Shape>().data() == moved.values().data() + 2);
moved.get<Constant>()[0] = 11.0;
CHECK(original.get<Constant>()[0] == 6.0);
State assigned(Layout{.state_sizes = {1, 1, 1}, .residual_sizes = {1, 1, 1}});
assigned = std::move(moved);
CHECK(assigned.layout() == layout);
CHECK(assigned.get<Constant>()[0] == 11.0);
CHECK(assigned.get<Constant>().data() == assigned.values().data() + 5);
assigned = original;
assigned.get<Density>()[1] = 12.0;
CHECK(original.get<Density>()[1] == 2.0);
}
TEST_CASE("Stellar states reject inconsistent storage and overflowing sizes while supporting empty coordinates", "[model][state][validation]") {
const Layout layout{.state_sizes = {2, 3, 1}, .residual_sizes = {3, 1, 2}};
const State zero(layout);
REQUIRE(zero.values().size() == 6);
for (double value : zero.values()) {
CHECK(value == 0.0);
}
CHECK_THROWS_WITH(State(layout, std::vector<double>(5)), Catch::Matchers::ContainsSubstring("INVALID_DOF_COUNT"));
CHECK_THROWS_WITH(State(layout, std::vector<double>(7)), Catch::Matchers::ContainsSubstring("INVALID_DOF_COUNT"));
const Layout overflow{.state_sizes = {std::numeric_limits<std::size_t>::max(), 1, 0}, .residual_sizes = {0, 1, 0}};
CHECK_THROWS_WITH(State(overflow), Catch::Matchers::ContainsSubstring("INVALID_DOF_COUNT"));
const State partial(Layout{.state_sizes = {0, 2, 0}, .residual_sizes = {2, 0, 0}});
CHECK(partial.get<Density>().empty());
CHECK(partial.get<Shape>().size() == 2);
CHECK(partial.get<Constant>().empty());
const blocks::SystemLayout<dependencies::KeyList<>, dependencies::KeyList<>> empty_layout{};
const serif::model::StellarState empty(empty_layout);
CHECK(empty.values().empty());
}