15#if defined(ENABLE_CATCH)
17# include <catch2/catch_all.hpp>
33 explicit TempJSONFile(
const std::string& contents) {
34 path_ = std::filesystem::temp_directory_path()
36 std::ofstream(path_) << contents;
40 std::filesystem::remove(path_, ec);
42 TempJSONFile(
const TempJSONFile&) =
delete;
43 TempJSONFile& operator=(
const TempJSONFile&) =
delete;
44 TempJSONFile(TempJSONFile&&) =
delete;
45 TempJSONFile& operator=(TempJSONFile&&) =
delete;
47 [[nodiscard]] std::string path()
const {
48 return path_.string();
52 std::filesystem::path path_;
53 static inline int counter_ = 0;
58TEST_CASE(
"PropsSI: '?<options>' suffix on fluid string parses + dispatches",
"[FactoryOptions][PropsSI]") {
59 const double T = 300.0;
60 const double p = 101325.0;
62 REQUIRE(std::isfinite(rho_ref));
64 SECTION(
"bare '?' is a no-op (empty options)") {
66 REQUIRE(rho == Catch::Approx(rho_ref));
68 SECTION(
"empty JSON object is a no-op") {
70 REQUIRE(rho == Catch::Approx(rho_ref));
77TEST_CASE(
"PropsSI: non-empty options on opted-out backend errors gracefully",
"[FactoryOptions][PropsSI]") {
82 const double rho =
CoolProp::PropsSI(
"D",
"T", 300.0,
"P", 101325.0, R
"(HEOS::Water?{"key":1})");
83 REQUIRE_FALSE(std::isfinite(rho));
85 REQUIRE_FALSE(err.empty());
88TEST_CASE(
"PropsSI: '@path' indirection reads file on fluid string",
"[FactoryOptions][PropsSI]") {
90 const std::string fluid_arg =
"HEOS::Water?@" + f.path();
92 REQUIRE(std::isfinite(rho));
94 const double rho_ref =
CoolProp::PropsSI(
"D",
"T", 300.0,
"P", 101325.0,
"HEOS::Water");
95 REQUIRE(rho == Catch::Approx(rho_ref));
98TEST_CASE(
"Props1SI / PhaseSI: '?<options>' suffix accepted through high-level API",
"[FactoryOptions][PropsSI]") {
99 SECTION(
"Props1SI empty options") {
101 REQUIRE(tcrit == Catch::Approx(647.096).margin(0.5));
103 SECTION(
"PhaseSI empty options") {
104 const std::string phase =
CoolProp::PhaseSI(
"T", 300.0,
"P", 101325.0,
"HEOS::Water?{}");
105 REQUIRE(phase ==
"liquid");
109TEST_CASE(
"AbstractState::factory: ambiguous '?<options>' on both sides throws",
"[FactoryOptions]") {
115TEST_CASE("AbstractState::factory: '?<options>' on the fluid side is hoisted",
"[FactoryOptions]") {
119 SECTION(
"empty options on fluid side accepted") {
121 REQUIRE(AS !=
nullptr);
123 SECTION(
"non-empty options on fluid side reach the default overload (throws)") {
128TEST_CASE("AbstractState::factory: '?<options>' on the LAST mixture token is hoisted",
"[FactoryOptions]") {
134 SECTION(
"empty options on last mixture token accepted") {
136 REQUIRE(AS !=
nullptr);
137 REQUIRE(AS->fluid_names().size() == 2);
138 REQUIRE(AS->fluid_names()[0] ==
"R32");
139 REQUIRE(AS->fluid_names()[1] ==
"R125");
141 SECTION(
"empty options on first mixture token accepted") {
143 REQUIRE(AS !=
nullptr);
144 REQUIRE(AS->fluid_names()[0] ==
"R32");
145 REQUIRE(AS->fluid_names()[1] ==
"R125");
147 SECTION(
"non-empty options on last mixture token reach the default overload (throws)") {
150 SECTION("options on multiple mixture tokens is rejected") {