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,8 +43,10 @@ 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>;
@ -69,10 +71,10 @@ TEST_CASE("uniform_int_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("uniform_real_distribution")
{
SECTION("uniform_real_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -97,10 +99,10 @@ TEST_CASE("uniform_real_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("binomial_distribution")
{
SECTION("binomial_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -125,10 +127,10 @@ TEST_CASE("binomial_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("negative_binomial_distribution")
{
SECTION("negative_binomial_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -153,10 +155,10 @@ TEST_CASE("negative_binomial_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("geometric_distribution")
{
SECTION("geometric_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -178,10 +180,10 @@ TEST_CASE("geometric_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("poisson_distribution")
{
SECTION("poisson_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -203,10 +205,10 @@ TEST_CASE("poisson_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("exponential_distribution")
{
SECTION("exponential_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -228,10 +230,10 @@ TEST_CASE("exponential_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("gamma_distribution")
{
SECTION("gamma_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -256,10 +258,10 @@ TEST_CASE("gamma_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("weibull_distribution")
{
SECTION("weibull_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -284,10 +286,10 @@ TEST_CASE("weibull_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("extreme_value_distribution")
{
SECTION("extreme_value_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -312,10 +314,10 @@ TEST_CASE("extreme_value_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("normal_distribution")
{
SECTION("normal_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -340,10 +342,10 @@ TEST_CASE("normal_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("lognormal_distribution")
{
SECTION("lognormal_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -368,10 +370,10 @@ TEST_CASE("lognormal_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("chi_squared_distribution")
{
SECTION("chi_squared_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -393,10 +395,10 @@ TEST_CASE("chi_squared_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("cauchy_distribution")
{
SECTION("cauchy_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -421,10 +423,10 @@ TEST_CASE("cauchy_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("fisher_f_distribution")
{
SECTION("fisher_f_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -449,10 +451,10 @@ TEST_CASE("fisher_f_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("student_t_distribution")
{
SECTION("student_t_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -474,10 +476,10 @@ TEST_CASE("student_t_distribution")
CHECK(units_dist.min() == stl_dist.min() * si::metre);
CHECK(units_dist.max() == stl_dist.max() * si::metre);
}
}
}
TEST_CASE("discrete_distribution")
{
SECTION("discrete_distribution")
{
using rep = std::int64_t;
using q = quantity<isq::length[si::metre], rep>;
@ -521,10 +523,10 @@ TEST_CASE("discrete_distribution")
CHECK(units_dist.probabilities() == stl_dist.probabilities());
}
}
}
TEST_CASE("piecewise_constant_distribution")
{
SECTION("piecewise_constant_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -589,10 +591,10 @@ TEST_CASE("piecewise_constant_distribution")
CHECK(units_dist.intervals() == intervals_qty_vec);
CHECK(units_dist.densities() == stl_dist.densities());
}
}
}
TEST_CASE("piecewise_linear_distribution")
{
SECTION("piecewise_linear_distribution")
{
using rep = long double;
using q = quantity<isq::length[si::metre], rep>;
@ -657,4 +659,5 @@ TEST_CASE("piecewise_linear_distribution")
CHECK(units_dist.intervals() == intervals_qty_vec);
CHECK(units_dist.densities() == stl_dist.densities());
}
}
}

View File

@ -38,8 +38,10 @@ 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")
{
@ -52,6 +54,7 @@ TEST_CASE("fixed_string::at", "[fixed_string]")
REQUIRE_THROWS_MATCHES(txt.at(3), std::out_of_range, Catch::Matchers::Message("basic_fixed_string::at"));
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,8 +731,75 @@ 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,14 +818,15 @@ 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")
{
SECTION("default spec")
@ -800,10 +873,10 @@ TEST_CASE("precision specification", "[text][fmt]")
CHECK(MP_UNITS_STD_FMT::format("{:%N:N[.5f]}", 1.2345 * isq::length[m]) == "1.23450");
CHECK(MP_UNITS_STD_FMT::format("{:%N:N[.10f]}", 1.2345 * isq::length[m]) == "1.2345000000");
}
}
}
TEST_CASE("type specification", "[text][fmt]")
{
SECTION("type specification")
{
SECTION("full format {:%N%?%U} on a quantity")
{
SECTION("default spec")
@ -942,10 +1015,10 @@ TEST_CASE("type specification", "[text][fmt]")
CHECK(MP_UNITS_STD_FMT::format("{:%N:N[.3G]}", 1.2345678 * isq::length[m]) == "1.23");
CHECK(MP_UNITS_STD_FMT::format("{:%N:N[.3G]}", 1.2345678e8 * isq::length[m]) == "1.23E+08");
}
}
}
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")
{
SECTION("default spec")
@ -984,10 +1057,10 @@ TEST_CASE("different base types with the # specifier", "[text][fmt]")
CHECK(MP_UNITS_STD_FMT::format("{:%N:N[#x]}", 42 * isq::length[m]) == "0x2a");
CHECK(MP_UNITS_STD_FMT::format("{:%N:N[#X]}", 42 * isq::length[m]) == "0X2A");
}
}
}
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 '_'; }
[[nodiscard]] std::string do_grouping() const override { return "\2"; }
@ -1021,61 +1094,10 @@ TEST_CASE("localization with the 'L' specifier", "[text][fmt][localization]")
CHECK(MP_UNITS_STD_FMT::format(grp3, "{:%N%U:N[L]}", 299'792'458 * isq::speed[m / s]) == "299'792'458m/s");
}
}
}
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,8 +43,10 @@ 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); }
SECTION("'pow<1>(q)' returns 'q'") { CHECK(pow<1>(2 * isq::length[m]) == 2 * isq::length[m]); }
@ -58,26 +60,26 @@ TEST_CASE("'pow<N>()' on quantity changes the value and the dimension accordingl
{
CHECK(pow<3>(2 * isq::length[m]) == 8 * isq::volume[m3]);
}
}
}
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")
{
REQUIRE(fmod(4. * isq::length[km], 3. * isq::length[km]) == 1. * isq::length[km]);
@ -92,10 +94,10 @@ TEST_CASE("fmod functions", "[math][fmod]")
REQUIRE(fmod(3. * isq::length[km], 2000. * isq::length[m]) == 1000 * isq::length[m]);
REQUIRE(fmod(4 * isq::length[km], 2500 * isq::length[m]) == 1500 * isq::length[m]);
}
}
}
TEST_CASE("remainder functions", "[math][remainder]")
{
SECTION("remainder functions")
{
SECTION("remainder should work on the same quantities")
{
REQUIRE(remainder(4. * isq::length[km], 3. * isq::length[km]) == 1. * isq::length[km]);
@ -110,24 +112,24 @@ TEST_CASE("remainder functions", "[math][remainder]")
REQUIRE(remainder(3. * isq::length[km], 2000. * isq::length[m]) == -1000 * isq::length[m]);
REQUIRE(remainder(4 * isq::length[km], 2750 * isq::length[m]) == 1250 * isq::length[m]);
}
}
}
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()
// 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")
{
SECTION("integral representation") { REQUIRE(abs(-1 * isq::length[m]) == 1 * isq::length[m]); }
@ -141,10 +143,10 @@ TEST_CASE("absolute functions on quantity returns the absolute value", "[math][a
SECTION("floating-point representation") { REQUIRE(abs(1. * isq::length[m]) == 1 * isq::length[m]); }
}
}
}
TEST_CASE("numeric_limits functions", "[limits]")
{
SECTION("numeric_limits functions")
{
SECTION("'epsilon' works as expected using default floating type")
{
REQUIRE(epsilon<double>(isq::length[m]).numerical_value_in(m) ==
@ -155,10 +157,10 @@ TEST_CASE("numeric_limits functions", "[limits]")
REQUIRE(epsilon<int>(isq::length[m]).numerical_value_in(m) ==
std::numeric_limits<decltype(1 * isq::length[m])::rep>::epsilon());
}
}
}
TEST_CASE("floor functions", "[floor]")
{
SECTION("floor functions")
{
SECTION("floor 1 second with target unit second should be 1 second")
{
REQUIRE(floor<si::second>(1 * isq::time[s]) == 1 * isq::time[s]);
@ -209,10 +211,10 @@ 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")
{
REQUIRE(ceil<si::second>(1 * isq::time[s]) == 1 * isq::time[s]);
@ -261,10 +263,10 @@ TEST_CASE("ceil functions", "[ceil]")
{
REQUIRE(ceil<si::second>(-999. * isq::time[ms]) == 0 * isq::time[s]);
}
}
}
TEST_CASE("round functions", "[round]")
{
SECTION("round functions")
{
SECTION("round 1 second with target unit second should be 1 second")
{
REQUIRE(round<si::second>(1 * isq::time[s]) == 1 * isq::time[s]);
@ -349,10 +351,10 @@ TEST_CASE("round functions", "[round]")
{
REQUIRE(round<si::second>(-1999. * isq::time[ms]) == -2 * isq::time[s]);
}
}
}
TEST_CASE("hypot functions", "[hypot]")
{
SECTION("hypot functions")
{
SECTION("hypot should work on the same quantities")
{
REQUIRE(hypot(3. * isq::length[km], 4. * isq::length[km]) == 5. * isq::length[km]);
@ -363,10 +365,10 @@ TEST_CASE("hypot functions", "[hypot]")
REQUIRE(hypot(3. * isq::length[km], 4000. * isq::length[m]) == 5. * isq::length[km]);
REQUIRE(hypot(2. * isq::length[km], 3000. * isq::length[m], 6. * isq::length[km]) == 7. * isq::length[km]);
}
}
}
TEST_CASE("SI trigonometric functions", "[trig][si]")
{
SECTION("SI trigonometric functions")
{
SECTION("sin")
{
REQUIRE_THAT(si::sin(0 * deg), AlmostEquals(0. * one));
@ -390,10 +392,10 @@ TEST_CASE("SI trigonometric functions", "[trig][si]")
REQUIRE_THAT(si::tan(135. * deg), AlmostEquals(-1. * one));
REQUIRE_THAT(si::tan(180. * deg), AlmostEquals(0. * one));
}
}
}
TEST_CASE("SI inverse trigonometric functions", "[inv trig][si]")
{
SECTION("SI inverse trigonometric functions")
{
SECTION("asin")
{
REQUIRE_THAT(si::asin(-1 * one), AlmostEquals(-90. * deg));
@ -414,10 +416,10 @@ TEST_CASE("SI inverse trigonometric functions", "[inv trig][si]")
REQUIRE_THAT(si::atan(0 * one), AlmostEquals(0. * deg));
REQUIRE_THAT(si::atan(1 * one), AlmostEquals(45. * deg));
}
}
}
TEST_CASE("SI atan2 functions", "[atan2][si]")
{
SECTION("SI atan2 functions")
{
SECTION("atan2 should work on the same quantities")
{
REQUIRE_THAT(si::atan2(-1. * isq::length[km], 1. * isq::length[km]), AlmostEquals(-45. * deg));
@ -430,11 +432,10 @@ TEST_CASE("SI atan2 functions", "[atan2][si]")
REQUIRE_THAT(si::atan2(0. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(0. * deg));
REQUIRE_THAT(si::atan2(1. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(45. * deg));
}
}
}
TEST_CASE("Angle trigonometric functions", "[trig][angle]")
{
SECTION("Angle trigonometric functions")
{
using namespace mp_units::angular;
using namespace mp_units::angular::unit_symbols;
using mp_units::angular::unit_symbols::deg;
@ -477,10 +478,10 @@ TEST_CASE("Angle trigonometric functions", "[trig][angle]")
REQUIRE_THAT(tan(150 * angle[grad]), AlmostEquals(-1. * one));
REQUIRE_THAT(tan(200 * angle[grad]), AlmostEquals(0. * one, 2));
}
}
}
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;
using mp_units::angular::unit_symbols::deg;
@ -505,10 +506,10 @@ TEST_CASE("Angle inverse trigonometric functions", "[inv trig][angle]")
REQUIRE_THAT(atan(0 * one), AlmostEquals(0. * angle[deg]));
REQUIRE_THAT(atan(1 * one), AlmostEquals(45. * angle[deg]));
}
}
}
TEST_CASE("Angle atan2 functions", "[atan2][angle]")
{
SECTION("Angle atan2 functions")
{
using namespace mp_units::angular;
using namespace mp_units::angular::unit_symbols;
using mp_units::angular::unit_symbols::deg;
@ -525,4 +526,5 @@ TEST_CASE("Angle atan2 functions", "[atan2][angle]")
REQUIRE_THAT(atan2(0. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(0. * angle[deg]));
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
// conversion requiring radical magnitudes
TEST_CASE("unit conversions support radical magnitudes", "[conversion][radical]")
TEST_CASE("quantity operations", "[quantity]")
{
// conversion requiring radical magnitudes
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]")
{
// Reproducing issue #474 exactly:
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);
}
}