test: runtime unit tests refactored to have a bigger granularity (less top level tests)

This commit is contained in:
Mateusz Pusz
2024-11-12 11:27:52 +01:00
parent 123b4c0f14
commit 78204c7e5f
5 changed files with 1528 additions and 1495 deletions

View File

@ -43,7 +43,9 @@ import mp_units;
using namespace mp_units;
TEST_CASE("uniform_int_distribution")
TEST_CASE("distributions", "[random][distribution]")
{
SECTION("uniform_int_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -71,7 +73,7 @@ TEST_CASE("uniform_int_distribution")
}
}
TEST_CASE("uniform_real_distribution")
SECTION("uniform_real_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -99,7 +101,7 @@ TEST_CASE("uniform_real_distribution")
}
}
TEST_CASE("binomial_distribution")
SECTION("binomial_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -127,7 +129,7 @@ TEST_CASE("binomial_distribution")
}
}
TEST_CASE("negative_binomial_distribution")
SECTION("negative_binomial_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -155,7 +157,7 @@ TEST_CASE("negative_binomial_distribution")
}
}
TEST_CASE("geometric_distribution")
SECTION("geometric_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -180,7 +182,7 @@ TEST_CASE("geometric_distribution")
}
}
TEST_CASE("poisson_distribution")
SECTION("poisson_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -205,7 +207,7 @@ TEST_CASE("poisson_distribution")
}
}
TEST_CASE("exponential_distribution")
SECTION("exponential_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -230,7 +232,7 @@ TEST_CASE("exponential_distribution")
}
}
TEST_CASE("gamma_distribution")
SECTION("gamma_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -258,7 +260,7 @@ TEST_CASE("gamma_distribution")
}
}
TEST_CASE("weibull_distribution")
SECTION("weibull_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -286,7 +288,7 @@ TEST_CASE("weibull_distribution")
}
}
TEST_CASE("extreme_value_distribution")
SECTION("extreme_value_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -314,7 +316,7 @@ TEST_CASE("extreme_value_distribution")
}
}
TEST_CASE("normal_distribution")
SECTION("normal_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -342,7 +344,7 @@ TEST_CASE("normal_distribution")
}
}
TEST_CASE("lognormal_distribution")
SECTION("lognormal_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -370,7 +372,7 @@ TEST_CASE("lognormal_distribution")
}
}
TEST_CASE("chi_squared_distribution")
SECTION("chi_squared_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -395,7 +397,7 @@ TEST_CASE("chi_squared_distribution")
}
}
TEST_CASE("cauchy_distribution")
SECTION("cauchy_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -423,7 +425,7 @@ TEST_CASE("cauchy_distribution")
}
}
TEST_CASE("fisher_f_distribution")
SECTION("fisher_f_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -451,7 +453,7 @@ TEST_CASE("fisher_f_distribution")
}
}
TEST_CASE("student_t_distribution")
SECTION("student_t_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -476,7 +478,7 @@ TEST_CASE("student_t_distribution")
}
}
TEST_CASE("discrete_distribution")
SECTION("discrete_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -523,7 +525,7 @@ TEST_CASE("discrete_distribution")
}
}
TEST_CASE("piecewise_constant_distribution")
SECTION("piecewise_constant_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -591,7 +593,7 @@ TEST_CASE("piecewise_constant_distribution")
}
}
TEST_CASE("piecewise_linear_distribution")
SECTION("piecewise_linear_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -658,3 +660,4 @@ TEST_CASE("piecewise_linear_distribution")
CHECK(units_dist.densities() == stl_dist.densities());
}
}
}

View File

@ -38,7 +38,9 @@ import mp_units;
using namespace mp_units;
TEST_CASE("fixed_string::at", "[fixed_string]")
TEST_CASE("fixed_string operations", "[fixed_string]")
{
SECTION("fixed_string::at")
{
basic_fixed_string txt = "abc";
SECTION("in range")
@ -53,6 +55,7 @@ TEST_CASE("fixed_string::at", "[fixed_string]")
REQUIRE_THROWS_MATCHES(txt.at(1024), std::out_of_range, Catch::Matchers::Message("basic_fixed_string::at"));
}
}
}
TEST_CASE("fixed_string text output", "[fixed_string][ostream][fmt]")
{

View File

@ -55,7 +55,271 @@ constexpr bool mp_units::is_vector<T> = true;
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
TEST_CASE("dimension_symbol", "[dimension][symbol]")
{
using enum text_encoding;
std::ostringstream os;
SECTION("default formatting")
{
os << dimension_symbol(isq::power.dimension);
CHECK(os.str() == "L²MT⁻³");
}
SECTION("Portable mode")
{
os << dimension_symbol<dimension_symbol_formatting{.encoding = portable}>(isq::power.dimension);
CHECK(os.str() == "L^2MT^-3");
}
}
TEST_CASE("unit_symbol", "[unit][symbol]")
{
using enum text_encoding;
using enum unit_symbol_solidus;
using enum unit_symbol_separator;
std::ostringstream os;
SECTION("default formatting")
{
os << unit_symbol(m / s2);
CHECK(os.str() == "m/s²");
}
SECTION("Portable mode")
{
os << unit_symbol<unit_symbol_formatting{.encoding = portable}>(m / s2);
CHECK(os.str() == "m/s^2");
}
SECTION("solidus")
{
os << unit_symbol<unit_symbol_formatting{.solidus = never}>(m / s2);
CHECK(os.str() == "m s⁻²");
}
SECTION("separator")
{
os << unit_symbol<unit_symbol_formatting{.solidus = never, .separator = half_high_dot}>(m / s2);
CHECK(os.str() == "m⋅s⁻²");
}
}
// TODO add dimension formatting tests
TEST_CASE("unit formatting", "[unit][fmt]")
{
SECTION("Unit formatting should use proper text encoding")
{
SECTION("Unicode text output")
{
CHECK(MP_UNITS_STD_FMT::format("{:U}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:U}", si::kilo<si::ohm>) == "");
CHECK(MP_UNITS_STD_FMT::format("{:U}", us) == "µs");
CHECK(MP_UNITS_STD_FMT::format("{:U}", m / s2) == "m/s²");
}
SECTION("Unicode text output is used by default")
{
CHECK(MP_UNITS_STD_FMT::format("{}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{}", si::kilo<si::ohm>) == "");
CHECK(MP_UNITS_STD_FMT::format("{}", us) == "µs");
CHECK(MP_UNITS_STD_FMT::format("{}", m / s2) == "m/s²");
}
SECTION("Portable text output")
{
CHECK(MP_UNITS_STD_FMT::format("{:P}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:P}", si::kilo<si::ohm>) == "kohm");
CHECK(MP_UNITS_STD_FMT::format("{:P}", us) == "us");
CHECK(MP_UNITS_STD_FMT::format("{:P}", m / s2) == "m/s^2");
}
}
SECTION("unit formatting should print solidus according to specs")
{
SECTION("Solidus for only one element in denominator")
{
CHECK(MP_UNITS_STD_FMT::format("{:1}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:1}", m / s2) == "m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:1}", kg / m / s2) == "kg m⁻¹ s⁻²");
}
SECTION("Solidus for only one element in denominator is used by default")
{
CHECK(MP_UNITS_STD_FMT::format("{}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{}", m / s2) == "m/s²");
CHECK(MP_UNITS_STD_FMT::format("{}", kg / m / s2) == "kg m⁻¹ s⁻²");
}
SECTION("Always use solidus")
{
CHECK(MP_UNITS_STD_FMT::format("{:a}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:a}", m / s2) == "m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:a}", kg / m / s2) == "kg/(m s²)");
}
SECTION("Never use solidus")
{
CHECK(MP_UNITS_STD_FMT::format("{:n}", km / h) == "km h⁻¹");
CHECK(MP_UNITS_STD_FMT::format("{:n}", m / s2) == "m s⁻²");
CHECK(MP_UNITS_STD_FMT::format("{:n}", kg / m / s2) == "kg m⁻¹ s⁻²");
}
}
SECTION("Unit formatting should user proper separator")
{
SECTION("Space")
{
CHECK(MP_UNITS_STD_FMT::format("{:s}", kg * m / s2) == "kg m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:s}", kg / m / s2) == "kg m⁻¹ s⁻²");
CHECK(MP_UNITS_STD_FMT::format("{:sa}", kg / m / s2) == "kg/(m s²)");
}
SECTION("Space is used by default")
{
CHECK(MP_UNITS_STD_FMT::format("{}", kg * m / s2) == "kg m/s²");
CHECK(MP_UNITS_STD_FMT::format("{}", kg / m / s2) == "kg m⁻¹ s⁻²");
CHECK(MP_UNITS_STD_FMT::format("{:a}", kg / m / s2) == "kg/(m s²)");
}
SECTION("Dot")
{
CHECK(MP_UNITS_STD_FMT::format("{:d}", kg * m / s2) == "kg⋅m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:d}", kg / m / s2) == "kg⋅m⁻¹⋅s⁻²");
CHECK(MP_UNITS_STD_FMT::format("{:ad}", kg / m / s2) == "kg/(m⋅s²)");
}
}
}
TEST_CASE("unit formatting error handling", "[unit][fmt][exception]")
{
SECTION("unknown unit modifiers should throw")
{
SECTION("only the invalid modifier")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:x}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("invalid unit modifier specified"));
}
SECTION("invalid modifier in the front")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:xUda}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("invalid unit modifier specified"));
}
SECTION("invalid modifier in the end")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:Udax}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("invalid unit modifier specified"));
}
SECTION("invalid modifier in the middle")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:Udxa}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("invalid unit modifier specified"));
}
}
SECTION("repeated unit modifiers should throw")
{
SECTION("text encoding")
{
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:UdaU}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:dUaU}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:dUUa}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
}
SECTION("solidus")
{
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:aUda}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:daUa}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:daaU}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
}
SECTION("separator")
{
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:dUad}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:dadU}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:addU}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
}
}
SECTION("more then one modifier of the same kind should throw")
{
SECTION("text encoding")
{
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:UdaP}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:dPaU}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:dPUa}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
}
SECTION("solidus")
{
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:aUdn}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:dnUa}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:da1U}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
}
SECTION("separator")
{
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:dUas}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:sadU}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(
MP_UNITS_STD_FMT::vformat("{:adsU}", MP_UNITS_STD_FMT::make_format_args(m)), MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
}
}
SECTION("half_high_dot separator requested for portable encoding should throw")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dPa}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("half_high_dot unit separator allowed only for UTF-8 encoding"));
}
}
TEST_CASE("default quantity formatting", "[quantity][ostream][fmt]")
{
std::ostringstream os;
@ -375,266 +639,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
}
}
TEST_CASE("quantity format string with only %N should print quantity value only", "[text][fmt]")
{
SECTION("integral representation")
{
SECTION("positive value") { CHECK(MP_UNITS_STD_FMT::format("{:%N}", 123 * isq::speed[km / h]) == "123"); }
SECTION("negative value")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", 5 * isq::length[m] - 10 * isq::length[m]) == "-5");
}
}
SECTION("floating-point representation")
{
SECTION("positive value")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", 221. * isq::length[km] / (2 * isq::time[h])) == "110.5");
}
SECTION("negative value")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", 3.14 * isq::length[m] - 10 * isq::length[m]) == "-6.859999999999999");
}
SECTION("nan")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", std::numeric_limits<double>::quiet_NaN() * isq::length[m]) == "nan");
}
SECTION("inf")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", std::numeric_limits<double>::infinity() * isq::length[m]) == "inf");
}
SECTION("-inf")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", -std::numeric_limits<double>::infinity() * isq::length[m]) == "-inf");
}
}
}
TEST_CASE("quantity format string with only %U should print quantity unit symbol only", "[text][fmt]")
{
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * isq::speed[km / h]) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * isq::resistance[si::kilo<si::ohm>]) == "");
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * isq::time[us]) == "µs");
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * isq::acceleration[m / s2]) == "m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * percent) == "%");
}
TEST_CASE("Unit formatting should use proper text encoding")
{
SECTION("Unicode text output")
{
CHECK(MP_UNITS_STD_FMT::format("{:U}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:U}", si::kilo<si::ohm>) == "");
CHECK(MP_UNITS_STD_FMT::format("{:U}", us) == "µs");
CHECK(MP_UNITS_STD_FMT::format("{:U}", m / s2) == "m/s²");
}
SECTION("Unicode text output is used by default")
{
CHECK(MP_UNITS_STD_FMT::format("{}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{}", si::kilo<si::ohm>) == "");
CHECK(MP_UNITS_STD_FMT::format("{}", us) == "µs");
CHECK(MP_UNITS_STD_FMT::format("{}", m / s2) == "m/s²");
}
SECTION("Portable text output")
{
CHECK(MP_UNITS_STD_FMT::format("{:P}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:P}", si::kilo<si::ohm>) == "kohm");
CHECK(MP_UNITS_STD_FMT::format("{:P}", us) == "us");
CHECK(MP_UNITS_STD_FMT::format("{:P}", m / s2) == "m/s^2");
}
}
TEST_CASE("Unit formatting should print solidus according to specs")
{
SECTION("Solidus for only one element in denominator")
{
CHECK(MP_UNITS_STD_FMT::format("{:1}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:1}", m / s2) == "m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:1}", kg / m / s2) == "kg m⁻¹ s⁻²");
}
SECTION("Solidus for only one element in denominator is used by default")
{
CHECK(MP_UNITS_STD_FMT::format("{}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{}", m / s2) == "m/s²");
CHECK(MP_UNITS_STD_FMT::format("{}", kg / m / s2) == "kg m⁻¹ s⁻²");
}
SECTION("Always use solidus")
{
CHECK(MP_UNITS_STD_FMT::format("{:a}", km / h) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:a}", m / s2) == "m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:a}", kg / m / s2) == "kg/(m s²)");
}
SECTION("Never use solidus")
{
CHECK(MP_UNITS_STD_FMT::format("{:n}", km / h) == "km h⁻¹");
CHECK(MP_UNITS_STD_FMT::format("{:n}", m / s2) == "m s⁻²");
CHECK(MP_UNITS_STD_FMT::format("{:n}", kg / m / s2) == "kg m⁻¹ s⁻²");
}
}
TEST_CASE("Unit formatting should user proper separator")
{
SECTION("Space")
{
CHECK(MP_UNITS_STD_FMT::format("{:s}", kg * m / s2) == "kg m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:s}", kg / m / s2) == "kg m⁻¹ s⁻²");
CHECK(MP_UNITS_STD_FMT::format("{:sa}", kg / m / s2) == "kg/(m s²)");
}
SECTION("Space is used by default")
{
CHECK(MP_UNITS_STD_FMT::format("{}", kg * m / s2) == "kg m/s²");
CHECK(MP_UNITS_STD_FMT::format("{}", kg / m / s2) == "kg m⁻¹ s⁻²");
CHECK(MP_UNITS_STD_FMT::format("{:a}", kg / m / s2) == "kg/(m s²)");
}
SECTION("Dot")
{
CHECK(MP_UNITS_STD_FMT::format("{:d}", kg * m / s2) == "kg⋅m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:d}", kg / m / s2) == "kg⋅m⁻¹⋅s⁻²");
CHECK(MP_UNITS_STD_FMT::format("{:ad}", kg / m / s2) == "kg/(m⋅s²)");
}
}
TEST_CASE("unknown unit modifiers should throw", "[text][fmt][exception]")
{
SECTION("only the invalid modifier")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:x}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error, Catch::Matchers::Message("invalid unit modifier specified"));
}
SECTION("invalid modifier in the front")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:xUda}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error, Catch::Matchers::Message("invalid unit modifier specified"));
}
SECTION("invalid modifier in the end")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:Udax}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error, Catch::Matchers::Message("invalid unit modifier specified"));
}
SECTION("invalid modifier in the middle")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:Udxa}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error, Catch::Matchers::Message("invalid unit modifier specified"));
}
}
TEST_CASE("repeated unit modifiers should throw", "[text][fmt][exception]")
{
SECTION("text encoding")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:UdaU}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dUaU}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dUUa}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
}
SECTION("solidus")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:aUda}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:daUa}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:daaU}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
}
SECTION("separator")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dUad}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dadU}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:addU}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
}
}
TEST_CASE("more then one modifier of the same kind should throw", "[text][fmt][exception]")
{
SECTION("text encoding")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:UdaP}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dPaU}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dPUa}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'UAP' unit modifiers may be used in the format spec"));
}
SECTION("solidus")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:aUdn}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dnUa}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:da1U}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of '1an' unit modifiers may be used in the format spec"));
}
SECTION("separator")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dUas}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:sadU}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:adsU}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("only one of 'sd' unit modifiers may be used in the format spec"));
}
}
TEST_CASE("half_high_dot separator requested for portable encoding should throw", "[text][fmt][exception]")
{
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:dPa}", MP_UNITS_STD_FMT::make_format_args(m)),
MP_UNITS_STD_FMT::format_error,
Catch::Matchers::Message("half_high_dot unit separator allowed only for UTF-8 encoding"));
}
TEST_CASE("%U and %N can be put anywhere in a format string", "[text][fmt]")
{
SECTION("no space") { CHECK(MP_UNITS_STD_FMT::format("{:%N%U}", 123 * isq::speed[km / h]) == "123km/h"); }
SECTION("separator") { CHECK(MP_UNITS_STD_FMT::format("{:%N###%U}", 123 * isq::speed[km / h]) == "123###km/h"); }
SECTION("opposite order") { CHECK(MP_UNITS_STD_FMT::format("{:%U %N}", 123 * isq::speed[km / h]) == "km/h 123"); }
}
TEST_CASE("quantity fill and align specification", "[text][fmt][ostream]")
TEST_CASE("quantity fill and align specification", "[quantity][ostream][fmt]")
{
SECTION("ostream")
{
@ -726,7 +731,74 @@ TEST_CASE("quantity fill and align specification", "[text][fmt][ostream]")
}
}
TEST_CASE("sign specification", "[text][fmt]")
TEST_CASE("quantity subentities selection", "[quantity][fmt]")
{
SECTION("quantity format string with only %N should print quantity value only")
{
SECTION("integral representation")
{
SECTION("positive value") { CHECK(MP_UNITS_STD_FMT::format("{:%N}", 123 * isq::speed[km / h]) == "123"); }
SECTION("negative value")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", 5 * isq::length[m] - 10 * isq::length[m]) == "-5");
}
}
SECTION("floating-point representation")
{
SECTION("positive value")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", 221. * isq::length[km] / (2 * isq::time[h])) == "110.5");
}
SECTION("negative value")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", 3.14 * isq::length[m] - 10 * isq::length[m]) == "-6.859999999999999");
}
SECTION("nan")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", std::numeric_limits<double>::quiet_NaN() * isq::length[m]) == "nan");
}
SECTION("inf")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", std::numeric_limits<double>::infinity() * isq::length[m]) == "inf");
}
SECTION("-inf")
{
CHECK(MP_UNITS_STD_FMT::format("{:%N}", -std::numeric_limits<double>::infinity() * isq::length[m]) == "-inf");
}
}
}
SECTION("quantity format string with only %U should print quantity unit symbol only")
{
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * isq::speed[km / h]) == "km/h");
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * isq::resistance[si::kilo<si::ohm>]) == "");
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * isq::time[us]) == "µs");
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * isq::acceleration[m / s2]) == "m/s²");
CHECK(MP_UNITS_STD_FMT::format("{:%U}", 123 * percent) == "%");
}
SECTION("%U and %N can be put anywhere in a format string")
{
SECTION("no space") { CHECK(MP_UNITS_STD_FMT::format("{:%N%U}", 123 * isq::speed[km / h]) == "123km/h"); }
SECTION("separator") { CHECK(MP_UNITS_STD_FMT::format("{:%N###%U}", 123 * isq::speed[km / h]) == "123###km/h"); }
SECTION("opposite order") { CHECK(MP_UNITS_STD_FMT::format("{:%U %N}", 123 * isq::speed[km / h]) == "km/h 123"); }
}
}
// TODO provide basic tests if format string when provided in a quantity formatter are passed to respective dimensions
// and units formatters (detail formatting tests for dimensions and units are done separately)
TEST_CASE("quantity numerical value formatting for `std` arithmetic types", "[quantity][fmt]")
{
SECTION("sign specification")
{
auto inf = std::numeric_limits<double>::infinity() * si::metre;
auto nan = std::numeric_limits<double>::quiet_NaN() * si::metre;
@ -746,13 +818,14 @@ TEST_CASE("sign specification", "[text][fmt]")
SECTION("value only format {:%N} on a quantity")
{
CHECK(MP_UNITS_STD_FMT::format("{0:%N},{0:%N:N[+]},{0:%N:N[-]},{0:%N:N[ ]}", 1 * isq::length[m]) == "1,+1,1, 1");
CHECK(MP_UNITS_STD_FMT::format("{0:%N},{0:%N:N[+]},{0:%N:N[-]},{0:%N:N[ ]}", -1 * isq::length[m]) == "-1,-1,-1,-1");
CHECK(MP_UNITS_STD_FMT::format("{0:%N},{0:%N:N[+]},{0:%N:N[-]},{0:%N:N[ ]}", -1 * isq::length[m]) ==
"-1,-1,-1,-1");
CHECK(MP_UNITS_STD_FMT::format("{0:%N},{0:%N:N[+]},{0:%N:N[-]},{0:%N:N[ ]}", inf) == "inf,+inf,inf, inf");
CHECK(MP_UNITS_STD_FMT::format("{0:%N},{0:%N:N[+]},{0:%N:N[-]},{0:%N:N[ ]}", nan) == "nan,+nan,nan, nan");
}
}
TEST_CASE("precision specification", "[text][fmt]")
SECTION("precision specification")
{
SECTION("full format on a quantity")
{
@ -802,7 +875,7 @@ TEST_CASE("precision specification", "[text][fmt]")
}
}
TEST_CASE("type specification", "[text][fmt]")
SECTION("type specification")
{
SECTION("full format {:%N%?%U} on a quantity")
{
@ -944,7 +1017,7 @@ TEST_CASE("type specification", "[text][fmt]")
}
}
TEST_CASE("different base types with the # specifier", "[text][fmt]")
SECTION("different base types with the # specifier")
{
SECTION("full format {:%N%?%U} on a quantity")
{
@ -986,7 +1059,7 @@ TEST_CASE("different base types with the # specifier", "[text][fmt]")
}
}
TEST_CASE("localization with the 'L' specifier", "[text][fmt][localization]")
SECTION("localization with the 'L' specifier")
{
struct group2 : std::numpunct<char> {
[[nodiscard]] char do_thousands_sep() const override { return '_'; }
@ -1022,60 +1095,9 @@ TEST_CASE("localization with the 'L' specifier", "[text][fmt][localization]")
}
}
}
TEST_CASE("unit_symbol", "[text]")
{
using enum text_encoding;
using enum unit_symbol_solidus;
using enum unit_symbol_separator;
std::ostringstream os;
SECTION("default formatting")
{
os << unit_symbol(m / s2);
CHECK(os.str() == "m/s²");
}
SECTION("Portable mode")
{
os << unit_symbol<unit_symbol_formatting{.encoding = portable}>(m / s2);
CHECK(os.str() == "m/s^2");
}
SECTION("solidus")
{
os << unit_symbol<unit_symbol_formatting{.solidus = never}>(m / s2);
CHECK(os.str() == "m s⁻²");
}
SECTION("separator")
{
os << unit_symbol<unit_symbol_formatting{.solidus = never, .separator = half_high_dot}>(m / s2);
CHECK(os.str() == "m⋅s⁻²");
}
}
TEST_CASE("dimension_symbol", "[text]")
{
using enum text_encoding;
std::ostringstream os;
SECTION("default formatting")
{
os << dimension_symbol(isq::power.dimension);
CHECK(os.str() == "L²MT⁻³");
}
SECTION("Portable mode")
{
os << dimension_symbol<dimension_symbol_formatting{.encoding = portable}>(isq::power.dimension);
CHECK(os.str() == "L^2MT^-3");
}
}
TEST_CASE("value_cast", "[text][ostream]")
TEST_CASE("check if `value_cast` properly changes the numerical value of a quantity", "[value_cast][ostream]")
{
std::ostringstream os;

View File

@ -43,7 +43,9 @@ using namespace mp_units::si::unit_symbols;
// classical
TEST_CASE("'pow<N>()' on quantity changes the value and the dimension accordingly", "[math][pow]")
TEST_CASE("math operations", "[math]")
{
SECTION("'pow<N>()' on quantity changes the value and the dimension accordingly")
{
SECTION("'pow<0>(q)' returns '1'") { CHECK(pow<0>(2 * isq::length[m]) == 1 * one); }
@ -60,23 +62,23 @@ TEST_CASE("'pow<N>()' on quantity changes the value and the dimension accordingl
}
}
TEST_CASE("'sqrt()' on quantity changes the value and the dimension accordingly", "[math][sqrt]")
SECTION("'sqrt()' on quantity changes the value and the dimension accordingly")
{
REQUIRE(sqrt(4 * isq::area[m2]) == 2 * isq::length[m]);
}
TEST_CASE("'cbrt()' on quantity changes the value and the dimension accordingly", "[math][cbrt]")
SECTION("'cbrt()' on quantity changes the value and the dimension accordingly")
{
REQUIRE(cbrt(8 * isq::volume[m3]) == 2 * isq::length[m]);
}
TEST_CASE("'fma()' on quantity changes the value and the dimension accordingly", "[math][fma]")
SECTION("'fma()' on quantity changes the value and the dimension accordingly")
{
REQUIRE(fma(1.0 * isq::length[m], 2.0 * one, 2.0 * isq::length[m]) == 4.0 * isq::length[m]);
REQUIRE(fma(isq::speed(10.0 * m / s), isq::time(2.0 * s), isq::height(42.0 * m)) == isq::length(62.0 * m));
}
TEST_CASE("fmod functions", "[math][fmod]")
SECTION("fmod functions")
{
SECTION("fmod should work on the same quantities")
{
@ -94,7 +96,7 @@ TEST_CASE("fmod functions", "[math][fmod]")
}
}
TEST_CASE("remainder functions", "[math][remainder]")
SECTION("remainder functions")
{
SECTION("remainder should work on the same quantities")
{
@ -112,21 +114,21 @@ TEST_CASE("remainder functions", "[math][remainder]")
}
}
TEST_CASE("'isfinite()' accepts dimensioned arguments", "[math][isfinite]") { REQUIRE(isfinite(4.0 * isq::length[m])); }
SECTION("'isfinite()' accepts dimensioned arguments") { REQUIRE(isfinite(4.0 * isq::length[m])); }
TEST_CASE("'isinf()' accepts dimensioned arguments", "[math][isinf]") { REQUIRE(!isinf(4.0 * isq::length[m])); }
SECTION("'isinf()' accepts dimensioned arguments") { REQUIRE(!isinf(4.0 * isq::length[m])); }
TEST_CASE("'isnan()' accepts dimensioned arguments", "[math][isnan]") { REQUIRE(!isnan(4.0 * isq::length[m])); }
SECTION("'isnan()' accepts dimensioned arguments") { REQUIRE(!isnan(4.0 * isq::length[m])); }
TEST_CASE("'pow<Num, Den>()' on quantity changes the value and the dimension accordingly", "[math][pow]")
SECTION("'pow<Num, Den>()' on quantity changes the value and the dimension accordingly")
{
REQUIRE(pow<1, 4>(16 * isq::area[m2]) == sqrt(4 * isq::length[m]));
}
// TODO add tests for exp()
TEST_CASE("absolute functions on quantity returns the absolute value", "[math][abs][fabs]")
SECTION("absolute functions on quantity returns the absolute value")
{
SECTION("'abs()' on a negative quantity returns the abs")
{
@ -143,7 +145,7 @@ TEST_CASE("absolute functions on quantity returns the absolute value", "[math][a
}
}
TEST_CASE("numeric_limits functions", "[limits]")
SECTION("numeric_limits functions")
{
SECTION("'epsilon' works as expected using default floating type")
{
@ -157,7 +159,7 @@ TEST_CASE("numeric_limits functions", "[limits]")
}
}
TEST_CASE("floor functions", "[floor]")
SECTION("floor functions")
{
SECTION("floor 1 second with target unit second should be 1 second")
{
@ -211,7 +213,7 @@ TEST_CASE("floor functions", "[floor]")
// TODO Add tests for `N`, `kN` and `kg * m / s2` i `kg * km / s2`
}
TEST_CASE("ceil functions", "[ceil]")
SECTION("ceil functions")
{
SECTION("ceil 1 second with target unit second should be 1 second")
{
@ -263,7 +265,7 @@ TEST_CASE("ceil functions", "[ceil]")
}
}
TEST_CASE("round functions", "[round]")
SECTION("round functions")
{
SECTION("round 1 second with target unit second should be 1 second")
{
@ -351,7 +353,7 @@ TEST_CASE("round functions", "[round]")
}
}
TEST_CASE("hypot functions", "[hypot]")
SECTION("hypot functions")
{
SECTION("hypot should work on the same quantities")
{
@ -365,7 +367,7 @@ TEST_CASE("hypot functions", "[hypot]")
}
}
TEST_CASE("SI trigonometric functions", "[trig][si]")
SECTION("SI trigonometric functions")
{
SECTION("sin")
{
@ -392,7 +394,7 @@ TEST_CASE("SI trigonometric functions", "[trig][si]")
}
}
TEST_CASE("SI inverse trigonometric functions", "[inv trig][si]")
SECTION("SI inverse trigonometric functions")
{
SECTION("asin")
{
@ -416,7 +418,7 @@ TEST_CASE("SI inverse trigonometric functions", "[inv trig][si]")
}
}
TEST_CASE("SI atan2 functions", "[atan2][si]")
SECTION("SI atan2 functions")
{
SECTION("atan2 should work on the same quantities")
{
@ -432,8 +434,7 @@ TEST_CASE("SI atan2 functions", "[atan2][si]")
}
}
TEST_CASE("Angle trigonometric functions", "[trig][angle]")
SECTION("Angle trigonometric functions")
{
using namespace mp_units::angular;
using namespace mp_units::angular::unit_symbols;
@ -479,7 +480,7 @@ TEST_CASE("Angle trigonometric functions", "[trig][angle]")
}
}
TEST_CASE("Angle inverse trigonometric functions", "[inv trig][angle]")
SECTION("Angle inverse trigonometric functions")
{
using namespace mp_units::angular;
using namespace mp_units::angular::unit_symbols;
@ -507,7 +508,7 @@ TEST_CASE("Angle inverse trigonometric functions", "[inv trig][angle]")
}
}
TEST_CASE("Angle atan2 functions", "[atan2][angle]")
SECTION("Angle atan2 functions")
{
using namespace mp_units::angular;
using namespace mp_units::angular::unit_symbols;
@ -526,3 +527,4 @@ TEST_CASE("Angle atan2 functions", "[atan2][angle]")
REQUIRE_THAT(atan2(1. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(45. * angle[deg]));
}
}
}

View File

@ -60,22 +60,25 @@ constexpr bool within_4_ulps(T a, T b)
} // namespace
TEST_CASE("quantity operations", "[quantity]")
{
// conversion requiring radical magnitudes
TEST_CASE("unit conversions support radical magnitudes", "[conversion][radical]")
SECTION("unit conversions support radical magnitudes")
{
REQUIRE(within_4_ulps(sqrt((1.0 * m) * (1.0 * km)).numerical_value_in(m), sqrt(1000.0)));
}
// Reproducing issue #474 exactly:
TEST_CASE("Issue 474 is fixed", "[conversion][radical]")
SECTION("Issue 474 is fixed")
{
constexpr auto val_issue_474 = 8.0 * si::si2019::boltzmann_constant * 1000.0 * K / (std::numbers::pi * 10 * Da);
REQUIRE(within_4_ulps(sqrt(val_issue_474).numerical_value_in(m / s),
sqrt(val_issue_474.numerical_value_in(m * m / s / s))));
}
TEST_CASE("Volatile representation type", "[volatile]")
SECTION("Volatile representation type")
{
volatile std::int16_t vint = 123;
REQUIRE(quantity(vint * m).numerical_value_in(m) == 123);
}
}