refactor: modules support redesigned
This commit is contained in:
1 parent
b582e200a0
commit
0eaf6e2e56
129 files changed
+271
-838
No files matched your search
@@ -0,0 +1,46 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018 Mateusz Pusz
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
find_package(Catch2 3 CONFIG REQUIRED)
|
||||
|
||||
add_executable(unit_tests_runtime distribution_test.cpp fmt_test.cpp math_test.cpp)
|
||||
if(${projectPrefix}BUILD_CXX_MODULES)
|
||||
target_compile_definitions(unit_tests_runtime PUBLIC ${projectPrefix}MODULES)
|
||||
endif()
|
||||
target_link_libraries(unit_tests_runtime PRIVATE mp-units::mp-units Catch2::Catch2WithMain)
|
||||
|
||||
if(${projectPrefix}BUILD_LA)
|
||||
find_package(wg21_linear_algebra CONFIG REQUIRED)
|
||||
target_sources(unit_tests_runtime PRIVATE linear_algebra_test.cpp)
|
||||
target_link_libraries(unit_tests_runtime PRIVATE wg21_linear_algebra::wg21_linear_algebra)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
target_compile_options(
|
||||
unit_tests_runtime PRIVATE /wd4244 # 'conversion' conversion from 'type1' to 'type2', possible loss of data
|
||||
)
|
||||
endif()
|
||||
|
||||
include(Catch)
|
||||
catch_discover_tests(unit_tests_runtime)
|
||||
@@ -0,0 +1,63 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <catch2/matchers/catch_matchers_templated.hpp>
|
||||
#include <mp-units/compat_fmt_macros.h>
|
||||
#include <algorithm>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/quantity.h>
|
||||
#endif
|
||||
|
||||
namespace mp_units {
|
||||
|
||||
template<Quantity T>
|
||||
struct AlmostEqualsMatcher : Catch::Matchers::MatcherGenericBase {
|
||||
AlmostEqualsMatcher(const T& target) : target_{target} {}
|
||||
|
||||
template<std::convertible_to<T> U>
|
||||
requires std::same_as<typename T::rep, typename U::rep> && treat_as_floating_point<typename T::rep>
|
||||
bool match(const U& other) const
|
||||
{
|
||||
using std::abs;
|
||||
using common = std::common_type_t<T, U>;
|
||||
const auto x = common(target_).numerical_value_in(common::unit);
|
||||
const auto y = common(other).numerical_value_in(common::unit);
|
||||
const auto maxXYOne = std::max({typename T::rep{1}, abs(x), abs(y)});
|
||||
return abs(x - y) <= std::numeric_limits<typename T::rep>::epsilon() * maxXYOne;
|
||||
}
|
||||
|
||||
std::string describe() const override { return "almost equals: " + MP_UNITS_STD_FMT::format("{}", target_); }
|
||||
|
||||
private:
|
||||
const T& target_;
|
||||
};
|
||||
|
||||
template<Quantity T>
|
||||
AlmostEqualsMatcher<T> AlmostEquals(const T& target)
|
||||
{
|
||||
return {target};
|
||||
}
|
||||
|
||||
} // namespace mp_units
|
||||
@@ -0,0 +1,654 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <array>
|
||||
#include <initializer_list>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/ostream.h>
|
||||
#include <mp-units/random.h>
|
||||
#include <mp-units/systems/si/unit_symbols.h>
|
||||
#include <mp-units/systems/si/units.h>
|
||||
#endif
|
||||
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
TEST_CASE("uniform_int_distribution")
|
||||
{
|
||||
using rep = std::int64_t;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::uniform_int_distribution<q>();
|
||||
|
||||
CHECK(dist.a() == q::zero());
|
||||
CHECK(dist.b() == q::max());
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep a = 2;
|
||||
constexpr rep b = 5;
|
||||
|
||||
auto stl_dist = std::uniform_int_distribution(a, b);
|
||||
auto units_dist = mp_units::uniform_int_distribution(a * si::metre, b * si::metre);
|
||||
|
||||
CHECK(units_dist.a() == stl_dist.a() * si::metre);
|
||||
CHECK(units_dist.b() == stl_dist.b() * si::metre);
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("uniform_real_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::uniform_real_distribution<q>();
|
||||
|
||||
CHECK(dist.a() == q::zero());
|
||||
CHECK(dist.b() == q::one());
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep a = 2.0;
|
||||
constexpr rep b = 5.0;
|
||||
|
||||
auto stl_dist = std::uniform_real_distribution(a, b);
|
||||
auto units_dist = mp_units::uniform_real_distribution(a * si::metre, b * si::metre);
|
||||
|
||||
CHECK(units_dist.a() == stl_dist.a() * si::metre);
|
||||
CHECK(units_dist.b() == stl_dist.b() * si::metre);
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("binomial_distribution")
|
||||
{
|
||||
using rep = std::int64_t;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::binomial_distribution<q>();
|
||||
|
||||
CHECK(dist.p() == 0.5);
|
||||
CHECK(dist.t() == q::one());
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep t = 5;
|
||||
constexpr double p = 0.25;
|
||||
|
||||
auto stl_dist = std::binomial_distribution(t, p);
|
||||
auto units_dist = mp_units::binomial_distribution(t * si::metre, p);
|
||||
|
||||
CHECK(units_dist.p() == stl_dist.p());
|
||||
CHECK(units_dist.t() == stl_dist.t() * si::metre);
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("negative_binomial_distribution")
|
||||
{
|
||||
using rep = std::int64_t;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::negative_binomial_distribution<q>();
|
||||
|
||||
CHECK(dist.p() == 0.5);
|
||||
CHECK(dist.k() == q::one());
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep k = 5;
|
||||
constexpr double p = 0.25;
|
||||
|
||||
auto stl_dist = std::negative_binomial_distribution(k, p);
|
||||
auto units_dist = mp_units::negative_binomial_distribution(k * si::metre, p);
|
||||
|
||||
CHECK(units_dist.p() == stl_dist.p());
|
||||
CHECK(units_dist.k() == stl_dist.k() * si::metre);
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("geometric_distribution")
|
||||
{
|
||||
using rep = std::int64_t;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::geometric_distribution<q>();
|
||||
|
||||
CHECK(dist.p() == 0.5);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr double p = 0.25;
|
||||
|
||||
auto stl_dist = std::geometric_distribution<rep>(p);
|
||||
auto units_dist = mp_units::geometric_distribution<q>(p);
|
||||
|
||||
CHECK(units_dist.p() == stl_dist.p());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("poisson_distribution")
|
||||
{
|
||||
using rep = std::int64_t;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::poisson_distribution<q>();
|
||||
|
||||
CHECK(dist.mean() == 1.0);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr double mean = 5.0;
|
||||
|
||||
auto stl_dist = std::poisson_distribution<rep>(mean);
|
||||
auto units_dist = mp_units::poisson_distribution<q>(mean);
|
||||
|
||||
CHECK(units_dist.mean() == stl_dist.mean());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("exponential_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::exponential_distribution<q>();
|
||||
|
||||
CHECK(dist.lambda() == 1.0);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr double lambda = 2.0;
|
||||
|
||||
auto stl_dist = std::exponential_distribution<rep>(lambda);
|
||||
auto units_dist = mp_units::exponential_distribution<q>(lambda);
|
||||
|
||||
CHECK(units_dist.lambda() == stl_dist.lambda());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gamma_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::gamma_distribution<q>();
|
||||
|
||||
CHECK(dist.alpha() == 1.0);
|
||||
CHECK(dist.beta() == 1.0);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr double alpha = 5.0;
|
||||
constexpr double beta = 2.0;
|
||||
|
||||
auto stl_dist = std::gamma_distribution<rep>(alpha, beta);
|
||||
auto units_dist = mp_units::gamma_distribution<q>(alpha, beta);
|
||||
|
||||
CHECK(units_dist.alpha() == stl_dist.alpha());
|
||||
CHECK(units_dist.beta() == stl_dist.beta());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("weibull_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::weibull_distribution<q>();
|
||||
|
||||
CHECK(dist.a() == 1.0);
|
||||
CHECK(dist.b() == 1.0);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep a = 5.0;
|
||||
constexpr rep b = 2.0;
|
||||
|
||||
auto stl_dist = std::weibull_distribution(a, b);
|
||||
auto units_dist = mp_units::weibull_distribution<q>(a, b);
|
||||
|
||||
CHECK(units_dist.a() == stl_dist.a());
|
||||
CHECK(units_dist.b() == stl_dist.b());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("extreme_value_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::extreme_value_distribution<q>();
|
||||
|
||||
CHECK(dist.a() == q::zero());
|
||||
CHECK(dist.b() == 1.0);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep a = 5.0;
|
||||
constexpr rep b = 2.0;
|
||||
|
||||
auto stl_dist = std::extreme_value_distribution(a, b);
|
||||
auto units_dist = mp_units::extreme_value_distribution<q>(a * si::metre, b);
|
||||
|
||||
CHECK(units_dist.a() == stl_dist.a() * si::metre);
|
||||
CHECK(units_dist.b() == stl_dist.b());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("normal_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::normal_distribution<q>();
|
||||
|
||||
CHECK(dist.mean() == q::zero());
|
||||
CHECK(dist.stddev() == q::one());
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep mean = 5.0;
|
||||
constexpr rep stddev = 2.0;
|
||||
|
||||
auto stl_dist = std::normal_distribution(mean, stddev);
|
||||
auto units_dist = mp_units::normal_distribution(mean * si::metre, stddev * si::metre);
|
||||
|
||||
CHECK(units_dist.mean() == stl_dist.mean() * si::metre);
|
||||
CHECK(units_dist.stddev() == stl_dist.stddev() * si::metre);
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("lognormal_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::lognormal_distribution<q>();
|
||||
|
||||
CHECK(dist.m() == q::zero());
|
||||
CHECK(dist.s() == q::one());
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep m = 5.0;
|
||||
constexpr rep s = 2.0;
|
||||
|
||||
auto stl_dist = std::lognormal_distribution(m, s);
|
||||
auto units_dist = mp_units::lognormal_distribution(m * si::metre, s * si::metre);
|
||||
|
||||
CHECK(units_dist.m() == stl_dist.m() * si::metre);
|
||||
CHECK(units_dist.s() == stl_dist.s() * si::metre);
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("chi_squared_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::chi_squared_distribution<q>();
|
||||
|
||||
CHECK(dist.n() == 1.0);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep n = 5.0;
|
||||
|
||||
auto stl_dist = std::chi_squared_distribution(n);
|
||||
auto units_dist = mp_units::chi_squared_distribution<q>(n);
|
||||
|
||||
CHECK(units_dist.n() == stl_dist.n());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("cauchy_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::cauchy_distribution<q>();
|
||||
|
||||
CHECK(dist.a() == q::zero());
|
||||
CHECK(dist.b() == q::one());
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep a = 5.0;
|
||||
constexpr rep b = 2.0;
|
||||
|
||||
auto stl_dist = std::cauchy_distribution(a, b);
|
||||
auto units_dist = mp_units::cauchy_distribution(a * si::metre, b * si::metre);
|
||||
|
||||
CHECK(units_dist.a() == stl_dist.a() * si::metre);
|
||||
CHECK(units_dist.b() == stl_dist.b() * si::metre);
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("fisher_f_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::fisher_f_distribution<q>();
|
||||
|
||||
CHECK(dist.m() == 1.0);
|
||||
CHECK(dist.n() == 1.0);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep m = 5.0;
|
||||
constexpr rep n = 2.0;
|
||||
|
||||
auto stl_dist = std::fisher_f_distribution<rep>(m, n);
|
||||
auto units_dist = mp_units::fisher_f_distribution<q>(m, n);
|
||||
|
||||
CHECK(units_dist.m() == stl_dist.m());
|
||||
CHECK(units_dist.n() == stl_dist.n());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("student_t_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto dist = mp_units::student_t_distribution<q>();
|
||||
|
||||
CHECK(dist.n() == 1.0);
|
||||
}
|
||||
|
||||
SECTION("parametrized")
|
||||
{
|
||||
constexpr rep n = 2.0;
|
||||
|
||||
auto stl_dist = std::student_t_distribution<rep>(n);
|
||||
auto units_dist = mp_units::student_t_distribution<q>(n);
|
||||
|
||||
CHECK(units_dist.n() == stl_dist.n());
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("discrete_distribution")
|
||||
{
|
||||
using rep = std::int64_t;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto stl_dist = std::discrete_distribution<rep>();
|
||||
auto units_dist = mp_units::discrete_distribution<q>();
|
||||
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
CHECK(units_dist.probabilities() == stl_dist.probabilities());
|
||||
}
|
||||
|
||||
SECTION("parametrized_input_it")
|
||||
{
|
||||
constexpr std::array<double, 3> weights = {1.0, 2.0, 3.0};
|
||||
|
||||
auto stl_dist = std::discrete_distribution<rep>(weights.cbegin(), weights.cend());
|
||||
auto units_dist = mp_units::discrete_distribution<q>(weights.cbegin(), weights.cend());
|
||||
|
||||
CHECK(units_dist.probabilities() == stl_dist.probabilities());
|
||||
}
|
||||
|
||||
SECTION("parametrized_initializer_list")
|
||||
{
|
||||
std::initializer_list<double> weights = {1.0, 2.0, 3.0};
|
||||
|
||||
auto stl_dist = std::discrete_distribution<rep>(weights);
|
||||
auto units_dist = mp_units::discrete_distribution<q>(weights);
|
||||
|
||||
CHECK(units_dist.probabilities() == stl_dist.probabilities());
|
||||
}
|
||||
|
||||
SECTION("parametrized_range")
|
||||
{
|
||||
constexpr std::size_t count = 3;
|
||||
constexpr double xmin = 1, xmax = 3;
|
||||
|
||||
auto stl_dist = std::discrete_distribution<rep>(count, xmin, xmax, [](double val) { return val; });
|
||||
auto units_dist = mp_units::discrete_distribution<q>(count, xmin, xmax, [](double val) { return val; });
|
||||
|
||||
CHECK(units_dist.probabilities() == stl_dist.probabilities());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("piecewise_constant_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
std::vector<rep> intervals_rep_vec = {1.0, 2.0, 3.0};
|
||||
std::vector<q> intervals_qty_vec = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
3.0 * isq::length[si::metre]};
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto stl_dist = std::piecewise_constant_distribution<rep>();
|
||||
auto units_dist = mp_units::piecewise_constant_distribution<q>();
|
||||
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
CHECK(stl_dist.intervals().size() == 2);
|
||||
CHECK(units_dist.intervals().size() == 2);
|
||||
CHECK(stl_dist.densities().size() == 1);
|
||||
CHECK(units_dist.densities().size() == 1);
|
||||
}
|
||||
|
||||
SECTION("parametrized_input_it")
|
||||
{
|
||||
constexpr std::array<rep, 3> intervals_rep = {1.0, 2.0, 3.0};
|
||||
constexpr std::array<q, 3> intervals_qty = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
3.0 * isq::length[si::metre]};
|
||||
constexpr std::array<rep, 3> weights = {1.0, 2.0, 3.0};
|
||||
|
||||
auto stl_dist =
|
||||
std::piecewise_constant_distribution<rep>(intervals_rep.cbegin(), intervals_rep.cend(), weights.cbegin());
|
||||
auto units_dist =
|
||||
mp_units::piecewise_constant_distribution<q>(intervals_qty.cbegin(), intervals_qty.cend(), weights.cbegin());
|
||||
|
||||
CHECK(stl_dist.intervals() == intervals_rep_vec);
|
||||
CHECK(units_dist.intervals() == intervals_qty_vec);
|
||||
CHECK(units_dist.densities() == stl_dist.densities());
|
||||
}
|
||||
|
||||
SECTION("parametrized_initializer_list")
|
||||
{
|
||||
std::initializer_list<rep> intervals_rep = {1.0, 2.0, 3.0};
|
||||
std::initializer_list<q> intervals_qty = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
3.0 * isq::length[si::metre]};
|
||||
|
||||
auto stl_dist = std::piecewise_constant_distribution<rep>(intervals_rep, [](rep val) { return val; });
|
||||
auto units_dist = mp_units::piecewise_constant_distribution<q>(
|
||||
intervals_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); });
|
||||
|
||||
CHECK(units_dist.intervals() == intervals_qty_vec);
|
||||
CHECK(units_dist.densities() == stl_dist.densities());
|
||||
}
|
||||
|
||||
SECTION("parametrized_range")
|
||||
{
|
||||
constexpr std::size_t nw = 2;
|
||||
constexpr rep xmin_rep = 1.0, xmax_rep = 3.0;
|
||||
constexpr q xmin_qty = 1.0 * isq::length[si::metre], xmax_qty = 3.0 * isq::length[si::metre];
|
||||
|
||||
auto stl_dist = std::piecewise_constant_distribution<rep>(nw, xmin_rep, xmax_rep, [](rep val) { return val; });
|
||||
auto units_dist = mp_units::piecewise_constant_distribution<q>(
|
||||
nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); });
|
||||
|
||||
CHECK(units_dist.intervals() == intervals_qty_vec);
|
||||
CHECK(units_dist.densities() == stl_dist.densities());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("piecewise_linear_distribution")
|
||||
{
|
||||
using rep = long double;
|
||||
using q = quantity<isq::length[si::metre], rep>;
|
||||
|
||||
std::vector<rep> intervals_rep_vec = {1.0, 2.0, 3.0};
|
||||
std::vector<q> intervals_qty_vec = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
3.0 * isq::length[si::metre]};
|
||||
|
||||
SECTION("default")
|
||||
{
|
||||
auto stl_dist = std::piecewise_linear_distribution<rep>();
|
||||
auto units_dist = mp_units::piecewise_linear_distribution<q>();
|
||||
|
||||
CHECK(units_dist.min() == stl_dist.min() * si::metre);
|
||||
CHECK(units_dist.max() == stl_dist.max() * si::metre);
|
||||
CHECK(stl_dist.intervals().size() == 2);
|
||||
CHECK(units_dist.intervals().size() == 2);
|
||||
CHECK(stl_dist.densities().size() == 2);
|
||||
CHECK(units_dist.densities().size() == 2);
|
||||
}
|
||||
|
||||
SECTION("parametrized_input_it")
|
||||
{
|
||||
constexpr std::array<rep, 3> intervals_rep = {1.0, 2.0, 3.0};
|
||||
constexpr std::array<q, 3> intervals_qty = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
3.0 * isq::length[si::metre]};
|
||||
constexpr std::array<rep, 3> weights = {1.0, 2.0, 3.0};
|
||||
|
||||
auto stl_dist =
|
||||
std::piecewise_linear_distribution<rep>(intervals_rep.cbegin(), intervals_rep.cend(), weights.cbegin());
|
||||
auto units_dist =
|
||||
mp_units::piecewise_linear_distribution<q>(intervals_qty.cbegin(), intervals_qty.cend(), weights.cbegin());
|
||||
|
||||
CHECK(stl_dist.intervals() == intervals_rep_vec);
|
||||
CHECK(units_dist.intervals() == intervals_qty_vec);
|
||||
CHECK(units_dist.densities() == stl_dist.densities());
|
||||
}
|
||||
|
||||
SECTION("parametrized_initializer_list")
|
||||
{
|
||||
std::initializer_list<rep> intervals_rep = {1.0, 2.0, 3.0};
|
||||
std::initializer_list<q> intervals_qty = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
3.0 * isq::length[si::metre]};
|
||||
|
||||
auto stl_dist = std::piecewise_linear_distribution<rep>(intervals_rep, [](rep val) { return val; });
|
||||
auto units_dist = mp_units::piecewise_linear_distribution<q>(
|
||||
intervals_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); });
|
||||
|
||||
CHECK(units_dist.intervals() == intervals_qty_vec);
|
||||
CHECK(units_dist.densities() == stl_dist.densities());
|
||||
}
|
||||
|
||||
SECTION("parametrized_range")
|
||||
{
|
||||
constexpr std::size_t nw = 2;
|
||||
constexpr rep xmin_rep = 1.0, xmax_rep = 3.0;
|
||||
constexpr q xmin_qty = 1.0 * isq::length[si::metre], xmax_qty = 3.0 * isq::length[si::metre];
|
||||
|
||||
auto stl_dist = std::piecewise_linear_distribution<rep>(nw, xmin_rep, xmax_rep, [](rep val) { return val; });
|
||||
auto units_dist = mp_units::piecewise_linear_distribution<q>(
|
||||
nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); });
|
||||
|
||||
CHECK(units_dist.intervals() == intervals_qty_vec);
|
||||
CHECK(units_dist.densities() == stl_dist.densities());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,904 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_exception.hpp>
|
||||
#include <mp-units/compat_fmt_macros.h>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <locale>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/customization_points.h>
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/ostream.h>
|
||||
#include <mp-units/systems/cgs/cgs.h>
|
||||
#include <mp-units/systems/isq/mechanics.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/si/si.h>
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline 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]")
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
SECTION("quantity with a predefined unit")
|
||||
{
|
||||
SECTION("integral representation")
|
||||
{
|
||||
const auto q = 60 * isq::power[W];
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "60 W"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
||||
}
|
||||
|
||||
SECTION("floating-point representation")
|
||||
{
|
||||
const auto q = 1023.5 * isq::pressure[Pa];
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "1023.5 Pa"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("quantity with a predefined prefixed unit")
|
||||
{
|
||||
const auto q = 125 * isq::time[us];
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "125 µs"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
||||
}
|
||||
|
||||
SECTION("quantity with a derived unit")
|
||||
{
|
||||
SECTION("coherent derived unit")
|
||||
{
|
||||
SECTION("acceleration")
|
||||
{
|
||||
const auto q = 20 * isq::length[m] / (2 * isq::time[s]) / (1 * isq::time[s]);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "10 m/s²"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("volume")
|
||||
{
|
||||
const auto q = 2 * isq::length[m] * (1 * isq::length[m]) * (1 * isq::length[m]);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "2 m³"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("surface tension")
|
||||
{
|
||||
const auto q = 20 * isq::force[N] / (2 * isq::length[m]);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "10 N/m"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("scaled derived unit")
|
||||
{
|
||||
SECTION("speed")
|
||||
{
|
||||
const auto q = 20 * isq::length[km] / (2 * isq::time[h]);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "10 km/h"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("angular impulse")
|
||||
{
|
||||
const auto q = 123 * isq::angular_impulse[N * m * s];
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "123 N m s"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("compressibility")
|
||||
{
|
||||
const auto q = 123 * isq::compressibility[one / Pa];
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "123 1/Pa"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("angular acceleration")
|
||||
{
|
||||
const auto q = 123 * isq::angular_acceleration[rad / s2];
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "123 rad/s²"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("dimensionless quantity")
|
||||
{
|
||||
SECTION("one with ratio == 1")
|
||||
{
|
||||
const auto q = 4 * isq::length[m] / (2 * isq::length[m]);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "2"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == "2 "); }
|
||||
}
|
||||
|
||||
SECTION("one with ratio.exp != 0")
|
||||
{
|
||||
const auto q = 4 * isq::length[km] / (2 * isq::length[m]);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "2 km/m"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == "2 km/m"); }
|
||||
}
|
||||
|
||||
SECTION("percents")
|
||||
{
|
||||
const auto q = value_cast<percent>(15. * isq::length[m] / (100. * isq::length[m]));
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "15 %"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
||||
}
|
||||
|
||||
SECTION("radians")
|
||||
{
|
||||
const auto q = 42 * rad;
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "42 rad"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("no space before unit symbol")
|
||||
{
|
||||
SECTION("degree")
|
||||
{
|
||||
const auto q = 42 * deg;
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "42°"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == "42 °"); }
|
||||
}
|
||||
|
||||
SECTION("arcminute")
|
||||
{
|
||||
const auto q = 42 * arcmin;
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "42′"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == "42 ′"); }
|
||||
}
|
||||
|
||||
SECTION("arcsecond")
|
||||
{
|
||||
const auto q = 42 * arcsec;
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "42″"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == "42 ″"); }
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("8-bit integers")
|
||||
{
|
||||
SECTION("signed positive")
|
||||
{
|
||||
const auto q = std::int8_t{42} * si::second;
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "42 s"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
||||
}
|
||||
|
||||
SECTION("signed negative")
|
||||
{
|
||||
const auto q = std::int8_t{-42} * si::second;
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "-42 s"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
||||
}
|
||||
|
||||
SECTION("unsigned")
|
||||
{
|
||||
const auto q = std::uint8_t{42} * si::second;
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "42 s"); }
|
||||
|
||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||
|
||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("format string with only %Q should print quantity value only", "[text][fmt]")
|
||||
{
|
||||
SECTION("integral representation")
|
||||
{
|
||||
SECTION("positive value") { CHECK(MP_UNITS_STD_FMT::format("{:%Q}", 123 * isq::speed[km / h]) == "123"); }
|
||||
|
||||
SECTION("negative value")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q}", 5 * isq::length[m] - 10 * isq::length[m]) == "-5");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("floating-point representation")
|
||||
{
|
||||
SECTION("positive value")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q}", 221. * isq::length[km] / (2 * isq::time[h])) == "110.5");
|
||||
}
|
||||
|
||||
SECTION("negative value")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q}", 3.14 * isq::length[m] - 10 * isq::length[m]) == "-6.86");
|
||||
}
|
||||
|
||||
SECTION("nan")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q}", std::numeric_limits<double>::quiet_NaN() * isq::length[m]) == "nan");
|
||||
}
|
||||
|
||||
SECTION("inf")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q}", std::numeric_limits<double>::infinity() * isq::length[m]) == "inf");
|
||||
}
|
||||
|
||||
SECTION("-inf")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Q}", -std::numeric_limits<double>::infinity() * isq::length[m]) == "-inf");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("format string with only %q should print quantity unit symbol only", "[text][fmt]")
|
||||
{
|
||||
SECTION("Text encoding")
|
||||
{
|
||||
SECTION("Unicode text output")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Uq}", 123 * isq::speed[km / h]) == "km/h");
|
||||
// TODO enable this when resistance is defined
|
||||
// CHECK(MP_UNITS_STD_FMT::format("{:%Uq}", 123 * isq::resistance[kilo<ohm>]) == "kΩ");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Uq}", 123 * isq::time[us]) == "µs");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Uq}", 123 * isq::acceleration[m / s2]) == "m/s²");
|
||||
}
|
||||
|
||||
SECTION("Unicode text output is used by default")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::speed[km / h]) == "km/h");
|
||||
// CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::resistance[kilo<ohm>]) == "kΩ");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::time[us]) == "µs");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::acceleration[m / s2]) == "m/s²");
|
||||
}
|
||||
|
||||
SECTION("ASCII text output")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Aq}", 123 * isq::speed[km / h]) == "km/h");
|
||||
// CHECK(MP_UNITS_STD_FMT::format("{:%Aq}", 123 * isq::resistance[kilo<ohm>]) == "kohm");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Aq}", 123 * isq::time[us]) == "us");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%Aq}", 123 * isq::acceleration[m / s2]) == "m/s^2");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Solidus")
|
||||
{
|
||||
SECTION("Solidus for only one element in denominator")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%oq}", 123 * isq::speed[km / h]) == "km/h");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%oq}", 123 * isq::acceleration[m / s2]) == "m/s²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%oq}", 123 * isq::pressure[kg / m / s2]) == "kg m⁻¹ s⁻²");
|
||||
}
|
||||
|
||||
SECTION("Solidus for only one element in denominator is used by default")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::speed[km / h]) == "km/h");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::acceleration[m / s2]) == "m/s²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::pressure[kg / m / s2]) == "kg m⁻¹ s⁻²");
|
||||
}
|
||||
|
||||
SECTION("Always use solidus")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%aq}", 123 * isq::speed[km / h]) == "km/h");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%aq}", 123 * isq::acceleration[m / s2]) == "m/s²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%aq}", 123 * isq::pressure[kg / m / s2]) == "kg/(m s²)");
|
||||
}
|
||||
|
||||
SECTION("Never use solidus")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%nq}", 123 * isq::speed[km / h]) == "km h⁻¹");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%nq}", 123 * isq::acceleration[m / s2]) == "m s⁻²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%nq}", 123 * isq::pressure[kg / m / s2]) == "kg m⁻¹ s⁻²");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Separator")
|
||||
{
|
||||
SECTION("Space")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%sq}", 123 * isq::force[kg * m / s2]) == "kg m/s²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%sq}", 123 * isq::pressure[kg / m / s2]) == "kg m⁻¹ s⁻²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%asq}", 123 * isq::pressure[kg / m / s2]) == "kg/(m s²)");
|
||||
}
|
||||
|
||||
SECTION("Space is used by default")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::force[kg * m / s2]) == "kg m/s²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%q}", 123 * isq::pressure[kg / m / s2]) == "kg m⁻¹ s⁻²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%aq}", 123 * isq::pressure[kg / m / s2]) == "kg/(m s²)");
|
||||
}
|
||||
|
||||
SECTION("Dot")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%dq}", 123 * isq::force[kg * m / s2]) == "kg⋅m/s²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%dq}", 123 * isq::pressure[kg / m / s2]) == "kg⋅m⁻¹⋅s⁻²");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%adq}", 123 * isq::pressure[kg / m / s2]) == "kg/(m⋅s²)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("unknown unit modifiers should throw", "[text][fmt][exception]")
|
||||
{
|
||||
auto q = 1 * isq::length[m];
|
||||
|
||||
SECTION("only the invalid modifier")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%xq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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("{:%xUdaq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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("{:%Udaxq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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("{:%Udxaq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error, Catch::Matchers::Message("invalid unit modifier specified"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("repeated unit modifiers should throw", "[text][fmt][exception]")
|
||||
{
|
||||
auto q = 1 * isq::length[m];
|
||||
|
||||
SECTION("text encoding")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%UdaUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'UA' unit modifiers may be used in the format spec"));
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%dUaUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'UA' unit modifiers may be used in the format spec"));
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%dUUaq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'UA' unit modifiers may be used in the format spec"));
|
||||
}
|
||||
|
||||
SECTION("solidus")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%aUdaq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'oan' unit modifiers may be used in the format spec"));
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%daUaq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'oan' unit modifiers may be used in the format spec"));
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%daaUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'oan' unit modifiers may be used in the format spec"));
|
||||
}
|
||||
|
||||
SECTION("separator")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%dUadq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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("{:%dadUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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("{:%addUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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]")
|
||||
{
|
||||
auto q = 1 * isq::length[m];
|
||||
|
||||
SECTION("text encoding")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%UdaAq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'UA' unit modifiers may be used in the format spec"));
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%dAaUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'UA' unit modifiers may be used in the format spec"));
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%dAUaq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'UA' unit modifiers may be used in the format spec"));
|
||||
}
|
||||
|
||||
SECTION("solidus")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%aUdnq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'oan' unit modifiers may be used in the format spec"));
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%dnUaq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'oan' unit modifiers may be used in the format spec"));
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%daoUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("only one of 'oan' unit modifiers may be used in the format spec"));
|
||||
}
|
||||
|
||||
SECTION("separator")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%dUasq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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("{:%sadUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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("{:%adsUq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
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 ASCII encoding should throw", "[text][fmt][exception]")
|
||||
{
|
||||
auto q = 1 * isq::length[m];
|
||||
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%dAaq}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("half_high_dot unit separator allowed only for Unicode encoding"));
|
||||
}
|
||||
|
||||
TEST_CASE("%q and %Q can be put anywhere in a format string", "[text][fmt]")
|
||||
{
|
||||
SECTION("no space") { CHECK(MP_UNITS_STD_FMT::format("{:%Q%q}", 123 * isq::speed[km / h]) == "123km/h"); }
|
||||
|
||||
SECTION("separator") { CHECK(MP_UNITS_STD_FMT::format("{:%Q###%q}", 123 * isq::speed[km / h]) == "123###km/h"); }
|
||||
|
||||
SECTION("opposite order") { CHECK(MP_UNITS_STD_FMT::format("{:%q %Q}", 123 * isq::speed[km / h]) == "km/h 123"); }
|
||||
}
|
||||
|
||||
TEST_CASE("fill and align specification", "[text][fmt][ostream]")
|
||||
{
|
||||
SECTION("ostream")
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
SECTION("width = 10")
|
||||
{
|
||||
os << "|" << std::setw(10) << 123 * isq::length[m] << "|";
|
||||
CHECK(os.str() == "| 123 m|");
|
||||
}
|
||||
|
||||
SECTION("width = 10, align = right")
|
||||
{
|
||||
os << "|" << std::setw(10) << std::right << 123 * isq::length[m] << "|";
|
||||
CHECK(os.str() == "| 123 m|");
|
||||
}
|
||||
|
||||
SECTION("width = 10, align = left")
|
||||
{
|
||||
os << "|" << std::setw(10) << std::left << 123 * isq::length[m] << "|";
|
||||
CHECK(os.str() == "|123 m |");
|
||||
}
|
||||
|
||||
SECTION("width = 10, fill = *")
|
||||
{
|
||||
os << "|" << std::setw(10) << std::setfill('*') << 123 * isq::length[m] << "|";
|
||||
CHECK(os.str() == "|*****123 m|");
|
||||
}
|
||||
|
||||
SECTION("width = 10, fill = *, align = right")
|
||||
{
|
||||
os << "|" << std::setw(10) << std::setfill('*') << std::right << 123 * isq::length[m] << "|";
|
||||
CHECK(os.str() == "|*****123 m|");
|
||||
}
|
||||
|
||||
SECTION("width = 10, fill = *, align = left")
|
||||
{
|
||||
os << "|" << std::setw(10) << std::setfill('*') << std::left << 123 * isq::length[m] << "|";
|
||||
CHECK(os.str() == "|123 m*****|");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("default format {} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:0}|", 123 * isq::length[m]) == "|123 m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:10}|", 123 * isq::length[m]) == "| 123 m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:<10}|", 123 * isq::length[m]) == "|123 m |");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:>10}|", 123 * isq::length[m]) == "| 123 m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:^10}|", 123 * isq::length[m]) == "| 123 m |");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*<10}|", 123 * isq::length[m]) == "|123 m*****|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*>10}|", 123 * isq::length[m]) == "|*****123 m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*^10}|", 123 * isq::length[m]) == "|**123 m***|");
|
||||
}
|
||||
|
||||
SECTION("full format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:0%Q%q}|", 123 * isq::length[m]) == "|123m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:10%Q%q}|", 123 * isq::length[m]) == "| 123m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:<10%Q%q}|", 123 * isq::length[m]) == "|123m |");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:>10%Q%q}|", 123 * isq::length[m]) == "| 123m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:^10%Q%q}|", 123 * isq::length[m]) == "| 123m |");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*<10%Q%q}|", 123 * isq::length[m]) == "|123m******|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*>10%Q%q}|", 123 * isq::length[m]) == "|******123m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*^10%Q%q}|", 123 * isq::length[m]) == "|***123m***|");
|
||||
}
|
||||
|
||||
SECTION("value only format {:%Q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:0%Q}|", 123 * isq::length[m]) == "|123|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:10%Q}|", 123 * isq::length[m]) == "| 123|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:<10%Q}|", 123 * isq::length[m]) == "|123 |");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:>10%Q}|", 123 * isq::length[m]) == "| 123|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:^10%Q}|", 123 * isq::length[m]) == "| 123 |");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*<10%Q}|", 123 * isq::length[m]) == "|123*******|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*>10%Q}|", 123 * isq::length[m]) == "|*******123|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*^10%Q}|", 123 * isq::length[m]) == "|***123****|");
|
||||
}
|
||||
|
||||
SECTION("symbol only format {:%q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:0%q}|", 123 * isq::length[m]) == "|m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:10%q}|", 123 * isq::length[m]) == "| m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:<10%q}|", 123 * isq::length[m]) == "|m |");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:>10%q}|", 123 * isq::length[m]) == "| m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:^10%q}|", 123 * isq::length[m]) == "| m |");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*<10%q}|", 123 * isq::length[m]) == "|m*********|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*>10%q}|", 123 * isq::length[m]) == "|*********m|");
|
||||
CHECK(MP_UNITS_STD_FMT::format("|{:*^10%q}|", 123 * isq::length[m]) == "|****m*****|");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("sign specification", "[text][fmt]")
|
||||
{
|
||||
auto inf = std::numeric_limits<double>::infinity() * si::metre;
|
||||
auto nan = std::numeric_limits<double>::quiet_NaN() * si::metre;
|
||||
|
||||
SECTION("full format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", 1 * isq::length[m]) == "1m,+1m,1m, 1m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", -1 * isq::length[m]) == "-1m,-1m,-1m,-1m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", inf) == "infm,+infm,infm, infm");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", nan) == "nanm,+nanm,nanm, nanm");
|
||||
}
|
||||
|
||||
SECTION("value only format {:%Q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", 1 * isq::length[m]) == "1,+1,1, 1");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", -1 * isq::length[m]) == "-1,-1,-1,-1");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", inf) == "inf,+inf,inf, inf");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", nan) == "nan,+nan,nan, nan");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("precision specification", "[text][fmt]")
|
||||
{
|
||||
SECTION("full format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.0Q %q}", 1.2345 * isq::length[m]) == "1 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.1Q %q}", 1.2345 * isq::length[m]) == "1.2 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.2Q %q}", 1.2345 * isq::length[m]) == "1.23 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3Q %q}", 1.2345 * isq::length[m]) == "1.234 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.4Q %q}", 1.2345 * isq::length[m]) == "1.2345 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.5Q %q}", 1.2345 * isq::length[m]) == "1.23450 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.10Q %q}", 1.2345 * isq::length[m]) == "1.2345000000 m");
|
||||
}
|
||||
|
||||
SECTION("value only format {:%Q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.0Q}", 1.2345 * isq::length[m]) == "1");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.1Q}", 1.2345 * isq::length[m]) == "1.2");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.2Q}", 1.2345 * isq::length[m]) == "1.23");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3Q}", 1.2345 * isq::length[m]) == "1.234");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.4Q}", 1.2345 * isq::length[m]) == "1.2345");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.5Q}", 1.2345 * isq::length[m]) == "1.23450");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.10Q}", 1.2345 * isq::length[m]) == "1.2345000000");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("precision specification for integral representation should throw", "[text][fmt][exception]")
|
||||
{
|
||||
auto q = 1 * isq::length[m];
|
||||
|
||||
SECTION("full format {:%Q %q} on a quantity")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%.1Q %q}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("precision not allowed for integral quantity representation"));
|
||||
}
|
||||
|
||||
SECTION("value only format {:%Q} on a quantity")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(MP_UNITS_STD_FMT::vformat("{:%.1Q}", MP_UNITS_STD_FMT::make_format_args(q)),
|
||||
MP_UNITS_STD_FMT::format_error,
|
||||
Catch::Matchers::Message("precision not allowed for integral quantity representation"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("type specification", "[text][fmt]")
|
||||
{
|
||||
SECTION("full format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%bQ %q}", 42 * isq::length[m]) == "101010 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%BQ %q}", 42 * isq::length[m]) == "101010 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%dQ %q}", 42 * isq::length[m]) == "42 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%oQ %q}", 42 * isq::length[m]) == "52 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%xQ %q}", 42 * isq::length[m]) == "2a m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%XQ %q}", 42 * isq::length[m]) == "2A m");
|
||||
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%aQ %q}", 1.2345678 * isq::length[m]) == "0x1.3c0ca2a5b1d5dp+0 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3aQ %q}", 1.2345678 * isq::length[m]) == "0x1.3c1p+0 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%AQ %q}", 1.2345678 * isq::length[m]) == "0X1.3C0CA2A5B1D5DP+0 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3AQ %q}", 1.2345678 * isq::length[m]) == "0X1.3C1P+0 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%eQ %q}", 1.2345678 * isq::length[m]) == "1.234568e+00 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3eQ %q}", 1.2345678 * isq::length[m]) == "1.235e+00 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%EQ %q}", 1.2345678 * isq::length[m]) == "1.234568E+00 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3EQ %q}", 1.2345678 * isq::length[m]) == "1.235E+00 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%gQ %q}", 1.2345678 * isq::length[m]) == "1.23457 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%gQ %q}", 1.2345678e8 * isq::length[m]) == "1.23457e+08 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3gQ %q}", 1.2345678 * isq::length[m]) == "1.23 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3gQ %q}", 1.2345678e8 * isq::length[m]) == "1.23e+08 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%GQ %q}", 1.2345678 * isq::length[m]) == "1.23457 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%GQ %q}", 1.2345678e8 * isq::length[m]) == "1.23457E+08 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3GQ %q}", 1.2345678 * isq::length[m]) == "1.23 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3GQ %q}", 1.2345678e8 * isq::length[m]) == "1.23E+08 m");
|
||||
}
|
||||
|
||||
SECTION("value only format {:%Q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%bQ}", 42 * isq::length[m]) == "101010");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%BQ}", 42 * isq::length[m]) == "101010");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%dQ}", 42 * isq::length[m]) == "42");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%oQ}", 42 * isq::length[m]) == "52");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%xQ}", 42 * isq::length[m]) == "2a");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%XQ}", 42 * isq::length[m]) == "2A");
|
||||
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%aQ}", 1.2345678 * isq::length[m]) == "0x1.3c0ca2a5b1d5dp+0");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3aQ}", 1.2345678 * isq::length[m]) == "0x1.3c1p+0");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%AQ}", 1.2345678 * isq::length[m]) == "0X1.3C0CA2A5B1D5DP+0");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3AQ}", 1.2345678 * isq::length[m]) == "0X1.3C1P+0");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%eQ}", 1.2345678 * isq::length[m]) == "1.234568e+00");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3eQ}", 1.2345678 * isq::length[m]) == "1.235e+00");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%EQ}", 1.2345678 * isq::length[m]) == "1.234568E+00");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3EQ}", 1.2345678 * isq::length[m]) == "1.235E+00");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%gQ}", 1.2345678 * isq::length[m]) == "1.23457");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%gQ}", 1.2345678e8 * isq::length[m]) == "1.23457e+08");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3gQ}", 1.2345678 * isq::length[m]) == "1.23");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3gQ}", 1.2345678e8 * isq::length[m]) == "1.23e+08");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%GQ}", 1.2345678 * isq::length[m]) == "1.23457");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%GQ}", 1.2345678e8 * isq::length[m]) == "1.23457E+08");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3GQ}", 1.2345678 * isq::length[m]) == "1.23");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%.3GQ}", 1.2345678e8 * isq::length[m]) == "1.23E+08");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("different base types with the # specifier", "[text][fmt]")
|
||||
{
|
||||
SECTION("full format {:%Q %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#bQ %q}", 42 * isq::length[m]) == "0b101010 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#BQ %q}", 42 * isq::length[m]) == "0B101010 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#oQ %q}", 42 * isq::length[m]) == "052 m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#xQ %q}", 42 * isq::length[m]) == "0x2a m");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#XQ %q}", 42 * isq::length[m]) == "0X2A m");
|
||||
}
|
||||
|
||||
SECTION("value only format {:%Q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#bQ}", 42 * isq::length[m]) == "0b101010");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#BQ}", 42 * isq::length[m]) == "0B101010");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#oQ}", 42 * isq::length[m]) == "052");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#xQ}", 42 * isq::length[m]) == "0x2a");
|
||||
CHECK(MP_UNITS_STD_FMT::format("{:%#XQ}", 42 * isq::length[m]) == "0X2A");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("localization with the 'L' specifier", "[text][fmt][localization]")
|
||||
{
|
||||
struct group2 : std::numpunct<char> {
|
||||
char do_thousands_sep() const override { return '_'; }
|
||||
std::string do_grouping() const override { return "\2"; }
|
||||
};
|
||||
|
||||
struct group3 : std::numpunct<char> {
|
||||
char do_thousands_sep() const override { return '\''; }
|
||||
std::string do_grouping() const override { return "\3"; }
|
||||
};
|
||||
|
||||
std::locale grp2{std::locale::classic(), new group2};
|
||||
std::locale grp3{std::locale::classic(), new group3};
|
||||
|
||||
SECTION("full format {:%LQ %q} on a quantity")
|
||||
{
|
||||
CHECK(MP_UNITS_STD_FMT::format(grp2, "{:%LQ %q}", 299'792'458 * isq::speed[m / s]) == "2_99_79_24_58 m/s");
|
||||
CHECK(MP_UNITS_STD_FMT::format(grp3, "{:%LQ %q}", 299'792'458 * isq::speed[m / s]) == "299'792'458 m/s");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("value_cast", "[text][ostream]")
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
SECTION("int to double representation")
|
||||
{
|
||||
const auto q = 121 * isq::length[km] / (2 * isq::time[h]);
|
||||
|
||||
SECTION("original")
|
||||
{
|
||||
os << q;
|
||||
CHECK(os.str() == "60 km/h");
|
||||
}
|
||||
|
||||
SECTION("int")
|
||||
{
|
||||
os << value_cast<int>(q);
|
||||
CHECK(os.str() == "60 km/h");
|
||||
}
|
||||
|
||||
SECTION("double")
|
||||
{
|
||||
os << value_cast<double>(q);
|
||||
CHECK(os.str() == "60 km/h");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("double to int representation")
|
||||
{
|
||||
const auto q = 121. * isq::length[km] / (2 * isq::time[h]);
|
||||
|
||||
SECTION("original")
|
||||
{
|
||||
os << q;
|
||||
CHECK(os.str() == "60.5 km/h");
|
||||
}
|
||||
|
||||
SECTION("int")
|
||||
{
|
||||
os << value_cast<int>(q);
|
||||
CHECK(os.str() == "60 km/h");
|
||||
}
|
||||
|
||||
SECTION("double")
|
||||
{
|
||||
os << value_cast<double>(q);
|
||||
CHECK(os.str() == "60.5 km/h");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <mp-units/compat_fmt_macros.h>
|
||||
#include <cmath>
|
||||
#include <matrix>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/customization_points.h>
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/math.h>
|
||||
#include <mp-units/ostream.h>
|
||||
#include <mp-units/systems/isq/mechanics.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/si/si.h>
|
||||
#endif
|
||||
|
||||
template<typename Rep = double>
|
||||
using vector = STD_LA::fixed_size_column_vector<Rep, 3>;
|
||||
|
||||
template<class Rep>
|
||||
inline constexpr bool mp_units::treat_as_floating_point<vector<Rep>> = mp_units::treat_as_floating_point<Rep>;
|
||||
|
||||
template<typename Rep>
|
||||
inline constexpr bool mp_units::is_vector<vector<Rep>> = true;
|
||||
|
||||
template<typename Rep>
|
||||
std::ostream& operator<<(std::ostream& os, const vector<Rep>& v)
|
||||
{
|
||||
os << "|";
|
||||
for (auto i = 0U; i < v.size(); ++i) {
|
||||
os << MP_UNITS_STD_FMT::format(" {:>9}", v(i));
|
||||
}
|
||||
os << " |";
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace mp_units;
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
|
||||
template<QuantitySpec auto QS, QuantityOf<QS> Q>
|
||||
requires(Q::quantity_spec.character == quantity_character::vector) && (QS.character == quantity_character::scalar)
|
||||
[[nodiscard]] constexpr QuantityOf<QS> auto get_magnitude(const Q& q)
|
||||
{
|
||||
const auto& v = q.numerical_value_ref_in(q.unit);
|
||||
return hypot(v(0) * QS[Q::unit], v(1) * QS[Q::unit], v(2) * QS[Q::unit]);
|
||||
}
|
||||
|
||||
template<QuantitySpec auto QS, QuantityOf<QS> T>
|
||||
requires(T::quantity_spec.character == quantity_character::vector) && (QS.character == quantity_character::scalar)
|
||||
[[nodiscard]] constexpr QuantityOf<QS> auto get_magnitude(const vector<T>& v)
|
||||
{
|
||||
return hypot(QS(v(0)), QS(v(1)), QS(v(2)));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
[[nodiscard]] constexpr vector<decltype(T{} * U{})> cross_product(const vector<T>& a, const vector<U>& b)
|
||||
{
|
||||
return {a(1) * b(2) - a(2) * b(1), a(2) * b(0) - a(0) * b(2), a(0) * b(1) - a(1) * b(0)};
|
||||
}
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires is_vector<typename Q1::rep> && is_vector<typename Q2::rep> &&
|
||||
requires(typename Q1::rep v1, typename Q2::rep v2) { cross_product(v1, v2); }
|
||||
[[nodiscard]] constexpr QuantityOf<Q1::quantity_spec * Q2::quantity_spec> auto cross_product(const Q1& q1, const Q2& q2)
|
||||
{
|
||||
return cross_product(q1.numerical_value_ref_in(q1.unit), q2.numerical_value_ref_in(q2.unit)) *
|
||||
(Q1::reference * Q2::reference);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("vector quantity", "[la]")
|
||||
{
|
||||
SECTION("cast of unit")
|
||||
{
|
||||
SECTION("non-truncating")
|
||||
{
|
||||
const auto v = vector<int>{3, 2, 1} * isq::position_vector[km];
|
||||
CHECK(v.numerical_value_in(m) == vector<int>{3000, 2000, 1000});
|
||||
}
|
||||
|
||||
SECTION("truncating")
|
||||
{
|
||||
const auto v = vector<int>{1001, 1002, 1003} * isq::position_vector[m];
|
||||
CHECK(v.force_numerical_value_in(km) == vector<int>{1, 1, 1});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("to scalar magnitude")
|
||||
{
|
||||
const auto v = vector<int>{2, 3, 6} * isq::velocity[km / h];
|
||||
const auto speed = get_magnitude<isq::speed>(v);
|
||||
CHECK(speed.numerical_value_ref_in(km / h) == 7);
|
||||
}
|
||||
|
||||
SECTION("multiply by scalar value")
|
||||
{
|
||||
const auto v = vector<int>{1, 2, 3} * isq::position_vector[m];
|
||||
|
||||
SECTION("integral")
|
||||
{
|
||||
SECTION("scalar on LHS") { CHECK((2 * v).numerical_value_in(m) == vector<int>{2, 4, 6}); }
|
||||
SECTION("scalar on RHS") { CHECK((v * 2).numerical_value_in(m) == vector<int>{2, 4, 6}); }
|
||||
}
|
||||
|
||||
SECTION("floating-point")
|
||||
{
|
||||
SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value_in(m) == vector<double>{0.5, 1., 1.5}); }
|
||||
SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value_in(m) == vector<double>{0.5, 1., 1.5}); }
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("divide by scalar value")
|
||||
{
|
||||
const auto v = vector<int>{2, 4, 6} * isq::position_vector[m];
|
||||
|
||||
SECTION("integral") { CHECK((v / 2).numerical_value_in(m) == vector<int>{1, 2, 3}); }
|
||||
SECTION("floating-point") { CHECK((v / 0.5).numerical_value_in(m) == vector<double>{4., 8., 12.}); }
|
||||
}
|
||||
|
||||
SECTION("add")
|
||||
{
|
||||
const auto v = vector<int>{1, 2, 3} * isq::position_vector[m];
|
||||
|
||||
SECTION("same unit")
|
||||
{
|
||||
const auto u = vector<int>{3, 2, 1} * isq::position_vector[m];
|
||||
CHECK((v + u).numerical_value_in(m) == vector<int>{4, 4, 4});
|
||||
}
|
||||
SECTION("different units")
|
||||
{
|
||||
const auto u = vector<int>{3, 2, 1} * isq::position_vector[km];
|
||||
CHECK((v + u).numerical_value_in(m) == vector<int>{3001, 2002, 1003});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("subtract")
|
||||
{
|
||||
const auto v = vector<int>{1, 2, 3} * isq::position_vector[m];
|
||||
|
||||
SECTION("same unit")
|
||||
{
|
||||
const auto u = vector<int>{3, 2, 1} * isq::position_vector[m];
|
||||
CHECK((v - u).numerical_value_in(m) == vector<int>{-2, 0, 2});
|
||||
}
|
||||
SECTION("different units")
|
||||
{
|
||||
const auto u = vector<int>{3, 2, 1} * isq::position_vector[km];
|
||||
CHECK((v - u).numerical_value_in(m) == vector<int>{-2999, -1998, -997});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("multiply by scalar quantity")
|
||||
{
|
||||
const auto v = vector<int>{1, 2, 3} * isq::velocity[m / s];
|
||||
|
||||
SECTION("integral")
|
||||
{
|
||||
const auto mass = 2 * isq::mass[kg];
|
||||
|
||||
SECTION("derived_quantity_spec")
|
||||
{
|
||||
SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_in(kg * m / s) == vector<int>{2, 4, 6}); }
|
||||
SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_in(kg * m / s) == vector<int>{2, 4, 6}); }
|
||||
}
|
||||
SECTION("quantity_cast to momentum")
|
||||
{
|
||||
SECTION("scalar on LHS")
|
||||
{
|
||||
CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value_in(N * s) == vector<int>{2, 4, 6});
|
||||
}
|
||||
SECTION("scalar on RHS")
|
||||
{
|
||||
CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value_in(N * s) == vector<int>{2, 4, 6});
|
||||
}
|
||||
}
|
||||
SECTION("quantity of momentum")
|
||||
{
|
||||
SECTION("scalar on LHS")
|
||||
{
|
||||
const quantity<isq::momentum[N * s], vector<int>> momentum = mass * v;
|
||||
CHECK(momentum.numerical_value_ref_in(N * s) == vector<int>{2, 4, 6});
|
||||
}
|
||||
SECTION("scalar on RHS")
|
||||
{
|
||||
const quantity<isq::momentum[N * s], vector<int>> momentum = v * mass;
|
||||
CHECK(momentum.numerical_value_ref_in(N * s) == vector<int>{2, 4, 6});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("floating-point")
|
||||
{
|
||||
const auto mass = 0.5 * isq::mass[kg];
|
||||
|
||||
SECTION("derived_quantity_spec")
|
||||
{
|
||||
SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_in(kg * m / s) == vector<double>{0.5, 1., 1.5}); }
|
||||
SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_in(kg * m / s) == vector<double>{0.5, 1., 1.5}); }
|
||||
}
|
||||
SECTION("quantity_cast to momentum")
|
||||
{
|
||||
SECTION("scalar on LHS")
|
||||
{
|
||||
CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value_in(N * s) == vector<double>{0.5, 1., 1.5});
|
||||
}
|
||||
SECTION("scalar on RHS")
|
||||
{
|
||||
CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value_in(N * s) == vector<double>{0.5, 1., 1.5});
|
||||
}
|
||||
}
|
||||
SECTION("quantity of momentum")
|
||||
{
|
||||
SECTION("scalar on LHS")
|
||||
{
|
||||
const quantity<isq::momentum[N * s], vector<double>> momentum = mass * v;
|
||||
CHECK(momentum.numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5});
|
||||
}
|
||||
SECTION("scalar on RHS")
|
||||
{
|
||||
const quantity<isq::momentum[N * s], vector<double>> momentum = v * mass;
|
||||
CHECK(momentum.numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("divide by scalar quantity")
|
||||
{
|
||||
const auto pos = vector<int>{30, 20, 10} * isq::position_vector[km];
|
||||
|
||||
SECTION("integral")
|
||||
{
|
||||
const auto dur = 2 * isq::duration[h];
|
||||
|
||||
SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_in(km / h) == vector<int>{15, 10, 5}); }
|
||||
SECTION("quantity_cast to velocity")
|
||||
{
|
||||
CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value_in(km / h) == vector<int>{15, 10, 5});
|
||||
}
|
||||
SECTION("quantity of velocity")
|
||||
{
|
||||
const quantity<isq::velocity[km / h], vector<int>> v = pos / dur;
|
||||
CHECK(v.numerical_value_ref_in(km / h) == vector<int>{15, 10, 5});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("floating-point")
|
||||
{
|
||||
const auto dur = 0.5 * isq::duration[h];
|
||||
|
||||
SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_in(km / h) == vector<double>{60, 40, 20}); }
|
||||
SECTION("quantity_cast to velocity")
|
||||
{
|
||||
CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value_in(km / h) == vector<double>{60, 40, 20});
|
||||
}
|
||||
SECTION("quantity of velocity")
|
||||
{
|
||||
const quantity<isq::velocity[km / h], vector<double>> v = pos / dur;
|
||||
CHECK(v.numerical_value_ref_in(km / h) == vector<double>{60, 40, 20});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("cross product with a vector quantity")
|
||||
{
|
||||
const auto r = vector<int>{3, 0, 0} * isq::position_vector[m];
|
||||
const auto f = vector<int>{0, 10, 0} * isq::force[N];
|
||||
|
||||
CHECK(cross_product(r, f) == vector<int>{0, 0, 30} * isq::moment_of_force[N * m]);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
TEST_CASE("vector of quantities", "[la]")
|
||||
{
|
||||
SECTION("cast of unit")
|
||||
{
|
||||
SECTION("non-truncating")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[km], int>> v = {3 * km, 2 * km, 1 * km};
|
||||
|
||||
CHECK(vector<quantity<isq::position_vector[m], int>>(v) ==
|
||||
vector<quantity<isq::position_vector[m], int>>{3000 * m, 2000 * m, 1000 * m});
|
||||
}
|
||||
|
||||
// truncating not possible (no way to apply quantity_cast to sub-components of a vector)
|
||||
}
|
||||
|
||||
SECTION("to scalar magnitude")
|
||||
{
|
||||
const vector<quantity<isq::velocity[km / h], int>> v = {2 * km / h, 3 * km / h, 6 * km / h};
|
||||
const auto speed = get_magnitude<isq::speed>(v);
|
||||
CHECK(speed.numerical_value_ref_in(km / h) == 7);
|
||||
}
|
||||
|
||||
SECTION("multiply by scalar value")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], int>> v = {1 * m, 2 * m, 3 * m};
|
||||
|
||||
SECTION("integral")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], int>> result = {2 * m, 4 * m, 6 * m};
|
||||
|
||||
SECTION("scalar on LHS") { CHECK(2 * v == result); }
|
||||
SECTION("scalar on RHS") { CHECK(v * 2 == result); }
|
||||
}
|
||||
|
||||
SECTION("floating-point")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], double>> result = {0.5 * m, 1. * m, 1.5 * m};
|
||||
|
||||
SECTION("scalar on LHS") { CHECK(0.5 * v == result); }
|
||||
SECTION("scalar on RHS") { CHECK(v * 0.5 == result); }
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("divide by scalar value")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], int>> v = {2 * m, 4 * m, 6 * m};
|
||||
|
||||
SECTION("integral") { CHECK(v / 2 == vector<quantity<isq::position_vector[m], int>>{1 * m, 2 * m, 3 * m}); }
|
||||
SECTION("floating-point")
|
||||
{
|
||||
CHECK(v / 0.5 == vector<quantity<isq::position_vector[m], double>>{4. * m, 8. * m, 12. * m});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("add")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], int>> v = {1 * m, 2 * m, 3 * m};
|
||||
|
||||
SECTION("same unit")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], int>> u = {3 * m, 2 * m, 1 * m};
|
||||
|
||||
CHECK(v + u == vector<quantity<isq::position_vector[m], int>>{4 * m, 4 * m, 4 * m});
|
||||
}
|
||||
SECTION("different units")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[km], int>> u = {3 * km, 2 * km, 1 * km};
|
||||
|
||||
CHECK(v + u == vector<quantity<isq::position_vector[m], int>>{3001 * m, 2002 * m, 1003 * m});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("subtract")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], int>> v = {1 * m, 2 * m, 3 * m};
|
||||
|
||||
SECTION("same unit")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], int>> u = {3 * m, 2 * m, 1 * m};
|
||||
CHECK(v - u == vector<quantity<isq::position_vector[m], int>>{-2 * m, 0 * m, 2 * m});
|
||||
}
|
||||
SECTION("different units")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[km], int>> u = {3 * km, 2 * km, 1 * km};
|
||||
CHECK(v - u == vector<quantity<isq::position_vector[m], int>>{-2999 * m, -1998 * m, -997 * m});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("multiply by scalar quantity")
|
||||
{
|
||||
const vector<quantity<isq::velocity[m / s], int>> v = {1 * m / s, 2 * m / s, 3 * m / s};
|
||||
|
||||
SECTION("integral")
|
||||
{
|
||||
const auto mass = 2 * isq::mass[kg];
|
||||
const auto result = vector<quantity<isq::momentum[N * s], int>>{2 * N * s, 4 * N * s, 6 * N * s};
|
||||
|
||||
SECTION("derived_quantity_spec")
|
||||
{
|
||||
SECTION("scalar on LHS") { CHECK(mass * v == result); }
|
||||
SECTION("scalar on RHS") { CHECK(v * mass == result); }
|
||||
}
|
||||
|
||||
// no way to apply quantity_cast to sub-components
|
||||
|
||||
SECTION("quantity of momentum")
|
||||
{
|
||||
SECTION("scalar on LHS")
|
||||
{
|
||||
const vector<quantity<isq::momentum[N * s], int>> momentum = mass * v;
|
||||
CHECK(momentum == result);
|
||||
}
|
||||
SECTION("scalar on RHS")
|
||||
{
|
||||
const vector<quantity<isq::momentum[N * s], int>> momentum = v * mass;
|
||||
CHECK(momentum == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("floating-point")
|
||||
{
|
||||
const auto mass = 0.5 * isq::mass[kg];
|
||||
const auto result = vector<quantity<isq::momentum[N * s], double>>{0.5 * N * s, 1. * N * s, 1.5 * N * s};
|
||||
|
||||
SECTION("derived_quantity_spec")
|
||||
{
|
||||
SECTION("scalar on LHS") { CHECK(mass * v == result); }
|
||||
SECTION("scalar on RHS") { CHECK(v * mass == result); }
|
||||
}
|
||||
|
||||
// no way to apply quantity_cast to sub-components
|
||||
|
||||
SECTION("quantity of momentum")
|
||||
{
|
||||
SECTION("scalar on LHS")
|
||||
{
|
||||
const vector<quantity<isq::momentum[N * s], double>> momentum = mass * v;
|
||||
CHECK(momentum == result);
|
||||
}
|
||||
SECTION("scalar on RHS")
|
||||
{
|
||||
const vector<quantity<isq::momentum[N * s], double>> momentum = v * mass;
|
||||
CHECK(momentum == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("divide by scalar quantity")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[km], int>> pos = {30 * km, 20 * km, 10 * km};
|
||||
|
||||
SECTION("integral")
|
||||
{
|
||||
const auto dur = 2 * isq::duration[h];
|
||||
|
||||
SECTION("derived_quantity_spec")
|
||||
{
|
||||
CHECK(pos / dur == vector<quantity<isq::velocity[km / h], int>>{15 * km / h, 10 * km / h, 5 * km / h});
|
||||
}
|
||||
|
||||
// no way to apply quantity_cast to sub-components
|
||||
|
||||
SECTION("quantity of velocity")
|
||||
{
|
||||
const vector<quantity<isq::velocity[km / h], int>> v = pos / dur;
|
||||
CHECK(v == vector<quantity<isq::velocity[km / h], int>>{15 * km / h, 10 * km / h, 5 * km / h});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("floating-point")
|
||||
{
|
||||
const auto dur = 0.5 * isq::duration[h];
|
||||
|
||||
SECTION("derived_quantity_spec")
|
||||
{
|
||||
CHECK(pos / dur == vector<quantity<isq::velocity[km / h], double>>{60. * km / h, 40. * km / h, 20. * km / h});
|
||||
}
|
||||
|
||||
// no way to apply quantity_cast to sub-components
|
||||
|
||||
SECTION("quantity of velocity")
|
||||
{
|
||||
const vector<quantity<isq::velocity[km / h], double>> v = pos / dur;
|
||||
CHECK(v == vector<quantity<isq::velocity[km / h], double>>{60. * km / h, 40. * km / h, 20. * km / h});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("cross product with a vector of quantities")
|
||||
{
|
||||
const vector<quantity<isq::position_vector[m], int>> r = {3 * m, 0 * m, 0 * m};
|
||||
const vector<quantity<isq::force[N], int>> f = {0 * N, 10 * N, 0 * N};
|
||||
|
||||
CHECK(cross_product(r, f) == vector<quantity<isq::moment_of_force[N * m], int>>{0 * N * m, 0 * N * m, 30 * N * m});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "almost_equals.h"
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <limits>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/math.h>
|
||||
#include <mp-units/ostream.h>
|
||||
#include <mp-units/systems/angular/angular.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/si/si.h>
|
||||
#endif
|
||||
|
||||
using namespace mp_units;
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
|
||||
// classical
|
||||
|
||||
TEST_CASE("'pow<N>()' on quantity changes the value and the dimension accordingly", "[math][pow]")
|
||||
{
|
||||
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]); }
|
||||
|
||||
SECTION("'pow<2>(q)' squares both the value and a dimension")
|
||||
{
|
||||
CHECK(pow<2>(2 * isq::length[m]) == 4 * isq::area[m2]);
|
||||
}
|
||||
|
||||
SECTION("'pow<3>(q)' cubes both the value and a dimension")
|
||||
{
|
||||
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]")
|
||||
{
|
||||
REQUIRE(sqrt(4 * isq::area[m2]) == 2 * isq::length[m]);
|
||||
}
|
||||
|
||||
TEST_CASE("'cbrt()' on quantity changes the value and the dimension accordingly", "[math][cbrt]")
|
||||
{
|
||||
REQUIRE(cbrt(8 * isq::volume[m3]) == 2 * isq::length[m]);
|
||||
}
|
||||
|
||||
TEST_CASE("'fma()' on quantity changes the value and the dimension accordingly", "[math][fma]")
|
||||
{
|
||||
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("'isfinite()' accepts dimensioned arguments", "[math][isfinite]") { REQUIRE(isfinite(4.0 * isq::length[m])); }
|
||||
|
||||
TEST_CASE("'isinf()' accepts dimensioned arguments", "[math][isinf]") { REQUIRE(!isinf(4.0 * isq::length[m])); }
|
||||
|
||||
TEST_CASE("'isnan()' accepts dimensioned arguments", "[math][isnan]") { REQUIRE(!isnan(4.0 * isq::length[m])); }
|
||||
|
||||
|
||||
TEST_CASE("'pow<Num, Den>()' on quantity changes the value and the dimension accordingly", "[math][pow]")
|
||||
{
|
||||
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("'abs()' on a negative quantity returns the abs")
|
||||
{
|
||||
SECTION("integral representation") { REQUIRE(abs(-1 * isq::length[m]) == 1 * isq::length[m]); }
|
||||
|
||||
SECTION("floating-point representation") { REQUIRE(abs(-1. * isq::length[m]) == 1 * isq::length[m]); }
|
||||
}
|
||||
|
||||
SECTION("'abs()' on a positive quantity returns the abs")
|
||||
{
|
||||
SECTION("integral representation") { REQUIRE(abs(1 * isq::length[m]) == 1 * isq::length[m]); }
|
||||
|
||||
SECTION("floating-point representation") { REQUIRE(abs(1. * isq::length[m]) == 1 * isq::length[m]); }
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("numeric_limits functions", "[limits]")
|
||||
{
|
||||
SECTION("'epsilon' works as expected using default floating type")
|
||||
{
|
||||
REQUIRE(epsilon<double>(isq::length[m]).numerical_value_in(m) ==
|
||||
std::numeric_limits<decltype(1. * isq::length[m])::rep>::epsilon());
|
||||
}
|
||||
SECTION("'epsilon' works as expected using integers")
|
||||
{
|
||||
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 1 second with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(1 * isq::time[s]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor 1000 milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(1000 * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor 1001 milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(1001 * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor 1999 milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(1999 * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor -1000 milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(-1000 * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor -999 milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(-999 * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor 1.3 seconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(1.3 * isq::time[s]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor -1.3 seconds with target unit second should be -2 seconds")
|
||||
{
|
||||
REQUIRE(floor<si::second>(-1.3 * isq::time[s]) == -2 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor 1001. milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(1001. * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor 1999. milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(1999. * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor -1000. milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(-1000. * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("floor -999. milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(floor<si::second>(-999. * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
|
||||
// TODO Add tests for `N`, `kN` and `kg * m / s2` i `kg * km / s2`
|
||||
}
|
||||
|
||||
TEST_CASE("ceil functions", "[ceil]")
|
||||
{
|
||||
SECTION("ceil 1 second with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(1 * isq::time[s]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil 1000 milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(1000 * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil 1001 milliseconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(1001 * isq::time[ms]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil 1999 milliseconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(1999 * isq::time[ms]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil -1000 milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(-1000 * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil -999 milliseconds with target unit second should be 0 seconds")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(-999 * isq::time[ms]) == 0 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil 1.3 seconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(1.3 * isq::time[s]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil -1.3 seconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(-1.3 * isq::time[s]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil 1001. milliseconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(1001. * isq::time[ms]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil 1999. milliseconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(1999. * isq::time[ms]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil -1000. milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(-1000. * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("ceil -999. milliseconds with target unit second should be 0 seconds")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(-999. * isq::time[ms]) == 0 * isq::time[s]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("round functions", "[round]")
|
||||
{
|
||||
SECTION("round 1 second with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(1 * isq::time[s]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1000 milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(1000 * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1001 milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(1001 * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1499 milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(1499 * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1500 milliseconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(round<si::second>(1500 * isq::time[ms]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1999 milliseconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(round<si::second>(1999 * isq::time[ms]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1000 milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1000 * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1001 milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1001 * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1499 milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1499 * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1500 milliseconds with target unit second should be -2 seconds")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1500 * isq::time[ms]) == -2 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1999 milliseconds with target unit second should be -2 seconds")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1999 * isq::time[ms]) == -2 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1000. milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(1000. * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1001. milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(1001. * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1499. milliseconds with target unit second should be 1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(1499. * isq::time[ms]) == 1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1500. milliseconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(round<si::second>(1500. * isq::time[ms]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("round 1999. milliseconds with target unit second should be 2 seconds")
|
||||
{
|
||||
REQUIRE(round<si::second>(1999. * isq::time[ms]) == 2 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1000. milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1000. * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1001. milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1001. * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1499. milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1499. * isq::time[ms]) == -1 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1500. milliseconds with target unit second should be -2 seconds")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1500. * isq::time[ms]) == -2 * isq::time[s]);
|
||||
}
|
||||
SECTION("round -1999. milliseconds with target unit second should be -2 seconds")
|
||||
{
|
||||
REQUIRE(round<si::second>(-1999. * isq::time[ms]) == -2 * isq::time[s]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("hypot functions", "[hypot]")
|
||||
{
|
||||
SECTION("hypot should work on the same quantities")
|
||||
{
|
||||
REQUIRE(hypot(3. * isq::length[km], 4. * isq::length[km]) == 5. * isq::length[km]);
|
||||
REQUIRE(hypot(2. * isq::length[km], 3. * isq::length[km], 6. * isq::length[km]) == 7. * isq::length[km]);
|
||||
}
|
||||
SECTION("hypot should work with different units of the same dimension")
|
||||
{
|
||||
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("sin")
|
||||
{
|
||||
REQUIRE_THAT(si::sin(0 * deg), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(si::sin(90 * deg), AlmostEquals(1. * one));
|
||||
REQUIRE_THAT(si::sin(180 * deg), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(si::sin(270 * deg), AlmostEquals(-1. * one));
|
||||
}
|
||||
|
||||
SECTION("cos")
|
||||
{
|
||||
REQUIRE_THAT(si::cos(0 * deg), AlmostEquals(1. * one));
|
||||
REQUIRE_THAT(si::cos(90 * deg), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(si::cos(180 * deg), AlmostEquals(-1. * one));
|
||||
REQUIRE_THAT(si::cos(270 * deg), AlmostEquals(0. * one));
|
||||
}
|
||||
|
||||
SECTION("tan")
|
||||
{
|
||||
REQUIRE_THAT(si::tan(0 * deg), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(si::tan(45. * deg), AlmostEquals(1. * one));
|
||||
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("asin")
|
||||
{
|
||||
REQUIRE_THAT(si::asin(-1 * one), AlmostEquals(-90. * deg));
|
||||
REQUIRE_THAT(si::asin(0 * one), AlmostEquals(0. * deg));
|
||||
REQUIRE_THAT(si::asin(1 * one), AlmostEquals(90. * deg));
|
||||
}
|
||||
|
||||
SECTION("acos")
|
||||
{
|
||||
REQUIRE_THAT(si::asin(-1 * one), AlmostEquals(-90. * deg));
|
||||
REQUIRE_THAT(si::asin(0 * one), AlmostEquals(0. * deg));
|
||||
REQUIRE_THAT(si::asin(1 * one), AlmostEquals(90. * deg));
|
||||
}
|
||||
|
||||
SECTION("atan")
|
||||
{
|
||||
REQUIRE_THAT(si::atan(-1 * one), AlmostEquals(-45. * deg));
|
||||
REQUIRE_THAT(si::atan(0 * one), AlmostEquals(0. * deg));
|
||||
REQUIRE_THAT(si::atan(1 * one), AlmostEquals(45. * deg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Angle trigonometric functions", "[trig][angle]")
|
||||
{
|
||||
using namespace mp_units::angular;
|
||||
using namespace mp_units::angular::unit_symbols;
|
||||
using mp_units::angular::unit_symbols::deg;
|
||||
|
||||
SECTION("sin")
|
||||
{
|
||||
REQUIRE_THAT(sin(0 * angle[deg]), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(sin(90 * angle[deg]), AlmostEquals(1. * one));
|
||||
REQUIRE_THAT(sin(180 * angle[deg]), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(sin(270 * angle[deg]), AlmostEquals(-1. * one));
|
||||
|
||||
REQUIRE_THAT(sin(0 * angle[grad]), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(sin(100 * angle[grad]), AlmostEquals(1. * one));
|
||||
REQUIRE_THAT(sin(200 * angle[grad]), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(sin(300 * angle[grad]), AlmostEquals(-1. * one));
|
||||
}
|
||||
|
||||
SECTION("cos")
|
||||
{
|
||||
REQUIRE_THAT(cos(0 * angle[deg]), AlmostEquals(1. * one));
|
||||
REQUIRE_THAT(cos(90 * angle[deg]), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(cos(180 * angle[deg]), AlmostEquals(-1. * one));
|
||||
REQUIRE_THAT(cos(270 * angle[deg]), AlmostEquals(0. * one));
|
||||
|
||||
REQUIRE_THAT(cos(0 * angle[grad]), AlmostEquals(1. * one));
|
||||
REQUIRE_THAT(cos(100 * angle[grad]), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(cos(200 * angle[grad]), AlmostEquals(-1. * one));
|
||||
REQUIRE_THAT(cos(300 * angle[grad]), AlmostEquals(0. * one));
|
||||
}
|
||||
|
||||
SECTION("tan")
|
||||
{
|
||||
REQUIRE_THAT(tan(0 * angle[deg]), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(tan(45 * angle[deg]), AlmostEquals(1. * one));
|
||||
REQUIRE_THAT(tan(135 * angle[deg]), AlmostEquals(-1. * one));
|
||||
REQUIRE_THAT(tan(180 * angle[deg]), AlmostEquals(0. * one));
|
||||
|
||||
REQUIRE_THAT(tan(0 * angle[grad]), AlmostEquals(0. * one));
|
||||
REQUIRE_THAT(tan(50 * angle[grad]), AlmostEquals(1. * one));
|
||||
REQUIRE_THAT(tan(150 * angle[grad]), AlmostEquals(-1. * one));
|
||||
REQUIRE_THAT(tan(200 * angle[grad]), AlmostEquals(0. * one));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Angle inverse trigonometric functions", "[inv trig][angle]")
|
||||
{
|
||||
using namespace mp_units::angular;
|
||||
using namespace mp_units::angular::unit_symbols;
|
||||
using mp_units::angular::unit_symbols::deg;
|
||||
|
||||
SECTION("asin")
|
||||
{
|
||||
REQUIRE_THAT(asin(-1 * one), AlmostEquals(-90. * angle[deg]));
|
||||
REQUIRE_THAT(asin(0 * one), AlmostEquals(0. * angle[deg]));
|
||||
REQUIRE_THAT(asin(1 * one), AlmostEquals(90. * angle[deg]));
|
||||
}
|
||||
|
||||
SECTION("acos")
|
||||
{
|
||||
REQUIRE_THAT(asin(-1 * one), AlmostEquals(-90. * angle[deg]));
|
||||
REQUIRE_THAT(asin(0 * one), AlmostEquals(0. * angle[deg]));
|
||||
REQUIRE_THAT(asin(1 * one), AlmostEquals(90. * angle[deg]));
|
||||
}
|
||||
|
||||
SECTION("atan")
|
||||
{
|
||||
REQUIRE_THAT(atan(-1 * one), AlmostEquals(-45. * angle[deg]));
|
||||
REQUIRE_THAT(atan(0 * one), AlmostEquals(0. * angle[deg]));
|
||||
REQUIRE_THAT(atan(1 * one), AlmostEquals(45. * angle[deg]));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user