Files
MeanField_SERiF/tests/utils/laneemden/formatting.cpp

72 lines
3.9 KiB
C++
Raw Normal View History

#include <array>
#include <format>
#include <iterator>
#include <string>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include "serif/utils/laneemden/solution.hpp"
namespace {
namespace laneemden = serif::utils::laneemden;
constexpr laneemden::Sample sample{.xi = 2.0, .theta = 0.5, .derivative = -0.25};
/** @brief Use distinct profile and surface values so selection forwarding is observable. */
[[nodiscard]] laneemden::Solution example_solution() {
return {
.n = 1.0,
.samples = {{.xi = 0.0, .theta = 1.0, .derivative = 0.0}, sample},
.surface = laneemden::Sample{.xi = 3.0, .theta = 0.0, .derivative = -0.5}
};
}
}
TEST_CASE("Lane Emden sample formatting selects complete or individual values", "[laneemden][formatting]") {
CHECK(std::format("{}", sample) == "(ξ=2, θ=0.5, dθ/dξ=-0.25)");
CHECK(std::format("{:}", sample) == std::format("{}", sample));
CHECK(std::format("{:all}", sample) == std::format("{}", sample));
CHECK(std::format("{:xi}", sample) == "2");
CHECK(std::format("{:theta}", sample) == "0.5");
CHECK(std::format("{:derivative}", sample) == "-0.25");
CHECK(std::format("{1:theta} / {0:xi}", sample, sample) == "0.5 / 2");
CHECK(std::format("{{{:xi}}}", sample) == "{2}");
}
TEST_CASE("Lane Emden solution formatting forwards selection to its profile and surface", "[laneemden][formatting]") {
const auto solution = example_solution();
CHECK(std::format("{}", solution) == "Solution(n=1, samples=[(ξ=0, θ=1, dθ/dξ=0), (ξ=2, θ=0.5, dθ/dξ=-0.25)], surface=(ξ=3, θ=0, dθ/dξ=-0.5))");
CHECK(std::format("{:}", solution) == std::format("{}", solution));
CHECK(std::format("{:all}", solution) == std::format("{}", solution));
CHECK(std::format("{:xi}", solution) == "Solution(n=1, samples=[0, 2], surface=3)");
CHECK(std::format("{:theta}", solution) == "Solution(n=1, samples=[1, 0.5], surface=0)");
CHECK(std::format("{:derivative}", solution) == "Solution(n=1, samples=[0, -0.25], surface=-0.5)");
const laneemden::Solution empty{.n = 5.0, .samples = {}, .surface = {}};
CHECK(std::format("{}", empty) == "Solution(n=5, samples=[], surface=none)");
CHECK(std::format("{:theta}", empty) == "Solution(n=5, samples=[], surface=none)");
}
TEST_CASE("Lane Emden formatters preserve surrounding output and independent selectors", "[laneemden][formatting]") {
const auto solution = example_solution();
const std::string expected = "prefix Solution(n=1, samples=[1, 0.5], surface=0) | 2 | Solution(n=1, samples=[0, -0.25], surface=-0.5) suffix";
std::string appended = "prefix ";
std::format_to(std::back_inserter(appended), "{:theta} | {:xi} | {:derivative} suffix", solution, sample, solution);
CHECK(appended == expected);
std::array<char, 512> buffer{};
const auto end = std::format_to(buffer.data(), "prefix {:theta} | {:xi} | {:derivative} suffix", solution, sample, solution);
CHECK(std::string(buffer.data(), end) == expected);
}
TEST_CASE("Lane Emden formatters reject unsupported selectors through the central error helper", "[laneemden][formatting]") {
const auto solution = example_solution();
for (const std::string specifier : {"radius", "xi,theta", "theta ", ".2f", "theta:.2f"}) {
CAPTURE(specifier);
const std::string format = "{:" + specifier + "}";
CHECK_THROWS_AS(std::vformat(format, std::make_format_args(sample)), std::format_error);
CHECK_THROWS_AS(std::vformat(format, std::make_format_args(solution)), std::format_error);
CHECK_THROWS_WITH(std::vformat(format, std::make_format_args(sample)), Catch::Matchers::ContainsSubstring("Unknown Lane–Emden sample selector"));
}
CHECK_THROWS_AS(std::vformat("{:xi", std::make_format_args(sample)), std::format_error);
CHECK_THROWS_AS(std::vformat("{:theta", std::make_format_args(solution)), std::format_error);
}