| 1 | //! @file test_numeric.cpp |
| 2 | //! @author ryftchen |
| 3 | //! @brief The definitions (test_numeric) in the test module. |
| 4 | //! @version 0.1.0 |
| 5 | //! @copyright Copyright (c) 2022-2025 ryftchen. All rights reserved. |
| 6 | |
| 7 | #include <gtest/gtest.h> |
| 8 | #include <syncstream> |
| 9 | |
| 10 | #include "application/example/include/apply_numeric.hpp" |
| 11 | |
| 12 | //! @brief The test module. |
| 13 | namespace test // NOLINT(modernize-concat-nested-namespaces) |
| 14 | { |
| 15 | //! @brief Numeric-testing-related functions in the test module. |
| 16 | namespace tst_num |
| 17 | { |
| 18 | //! @brief Print the progress of the numeric task tests. |
| 19 | //! @param title - task title |
| 20 | //! @param state - task state |
| 21 | //! @param align - alignment width |
| 22 | static void printTaskProgress(const std::string_view title, const std::string_view state, const std::uint8_t align = 50) |
| 23 | { |
| 24 | std::osyncstream(std::cout) << "TEST NUMERIC: " << std::setiosflags(std::ios_base::left) << std::setfill('.') |
| 25 | << std::setw(align) << title << state << std::resetiosflags(mask: std::ios_base::left) |
| 26 | << std::setfill(' ') << std::endl; |
| 27 | } |
| 28 | |
| 29 | //! @brief Test base of arithmetic. |
| 30 | class ArithmeticTestBase : public ::testing::Test |
| 31 | { |
| 32 | protected: |
| 33 | //! @brief Alias for the input builder. |
| 34 | using InputBuilder = application::app_num::arithmetic::InputBuilder; |
| 35 | //! @brief Set up the test case. |
| 36 | static void SetUpTestSuite() |
| 37 | { |
| 38 | printTaskProgress(title, state: "BEGIN" ); |
| 39 | namespace input = application::app_num::arithmetic::input; |
| 40 | fixture = std::make_unique<InputBuilder>(args: input::operandA, args: input::operandB); |
| 41 | } |
| 42 | //! @brief Tear down the test case. |
| 43 | static void TearDownTestSuite() |
| 44 | { |
| 45 | printTaskProgress(title, state: "END" ); |
| 46 | fixture.reset(); |
| 47 | } |
| 48 | |
| 49 | //! @brief Test title. |
| 50 | inline static const std::string_view title{numeric::arithmetic::description()}; |
| 51 | //! @brief System under test. |
| 52 | [[no_unique_address]] const numeric::arithmetic::Arithmetic sut{}; |
| 53 | //! @brief Fixture data. |
| 54 | inline static std::unique_ptr<InputBuilder> fixture{}; |
| 55 | //! @brief Expected result 1. |
| 56 | static constexpr std::int32_t expRes1{0}; |
| 57 | //! @brief Expected result 2. |
| 58 | static constexpr std::int32_t expRes2{92680}; |
| 59 | //! @brief Expected result 3. |
| 60 | static constexpr std::int32_t expRes3{-2147395600}; |
| 61 | //! @brief Expected result 4. |
| 62 | static constexpr std::int32_t expRes4{-1}; |
| 63 | }; |
| 64 | |
| 65 | //! @brief Test for the addition method in the calculation of arithmetic. |
| 66 | TEST_F(ArithmeticTestBase, AdditionMethod) |
| 67 | { |
| 68 | ASSERT_EQ(expRes1, sut.addition(fixture->getOperands().first, fixture->getOperands().second)); |
| 69 | } |
| 70 | |
| 71 | //! @brief Test for the subtraction method in the calculation of arithmetic. |
| 72 | TEST_F(ArithmeticTestBase, SubtractionMethod) |
| 73 | { |
| 74 | ASSERT_EQ(expRes2, sut.subtraction(fixture->getOperands().first, fixture->getOperands().second)); |
| 75 | } |
| 76 | |
| 77 | //! @brief Test for the multiplication method in the calculation of arithmetic. |
| 78 | TEST_F(ArithmeticTestBase, MultiplicationMethod) |
| 79 | { |
| 80 | ASSERT_EQ(expRes3, sut.multiplication(fixture->getOperands().first, fixture->getOperands().second)); |
| 81 | } |
| 82 | |
| 83 | //! @brief Test for the division method in the calculation of arithmetic. |
| 84 | TEST_F(ArithmeticTestBase, DivisionMethod) |
| 85 | { |
| 86 | ASSERT_EQ(expRes4, sut.division(fixture->getOperands().first, fixture->getOperands().second)); |
| 87 | } |
| 88 | |
| 89 | //! @brief Test base of divisor. |
| 90 | class DivisorTestBase : public ::testing::Test |
| 91 | { |
| 92 | protected: |
| 93 | //! @brief Alias for the input builder. |
| 94 | using InputBuilder = application::app_num::divisor::InputBuilder; |
| 95 | //! @brief Set up the test case. |
| 96 | static void SetUpTestSuite() |
| 97 | { |
| 98 | printTaskProgress(title, state: "BEGIN" ); |
| 99 | namespace input = application::app_num::divisor::input; |
| 100 | fixture = std::make_unique<InputBuilder>(args: input::numberA, args: input::numberB); |
| 101 | } |
| 102 | //! @brief Tear down the test case. |
| 103 | static void TearDownTestSuite() |
| 104 | { |
| 105 | printTaskProgress(title, state: "END" ); |
| 106 | fixture.reset(); |
| 107 | } |
| 108 | |
| 109 | //! @brief Test title. |
| 110 | inline static const std::string_view title{numeric::divisor::description()}; |
| 111 | //! @brief System under test. |
| 112 | [[no_unique_address]] const numeric::divisor::Divisor sut{}; |
| 113 | //! @brief Fixture data. |
| 114 | inline static std::unique_ptr<InputBuilder> fixture{}; |
| 115 | //! @brief Expected result. |
| 116 | const std::set<std::int32_t> expRes{1, 2, 3, 5, 6, 7, 10, 14, 15, 21, 30, 35, 42, 70, 105, 210}; |
| 117 | }; |
| 118 | |
| 119 | //! @brief Test for the Euclidean method in the calculation of divisor. |
| 120 | TEST_F(DivisorTestBase, EuclideanMethod) |
| 121 | { |
| 122 | ASSERT_EQ(expRes, sut.euclidean(fixture->getNumbers().first, fixture->getNumbers().second)); |
| 123 | } |
| 124 | |
| 125 | //! @brief Test for the Stein method in the calculation of divisor. |
| 126 | TEST_F(DivisorTestBase, SteinMethod) |
| 127 | { |
| 128 | ASSERT_EQ(expRes, sut.stein(fixture->getNumbers().first, fixture->getNumbers().second)); |
| 129 | } |
| 130 | |
| 131 | //! @brief Test base of integral. |
| 132 | class IntegralTestBase : public ::testing::Test |
| 133 | { |
| 134 | protected: |
| 135 | //! @brief Alias for the input builder. |
| 136 | using InputBuilder = application::app_num::integral::InputBuilder; |
| 137 | //! @brief Set up the test case. |
| 138 | static void SetUpTestSuite() |
| 139 | { |
| 140 | printTaskProgress(title, state: "BEGIN" ); |
| 141 | using application::app_num::integral::input::CylindricalBessel; |
| 142 | fixture = std::make_unique<InputBuilder>( |
| 143 | args: CylindricalBessel{}, args: CylindricalBessel::range1, args: CylindricalBessel::range2, args: CylindricalBessel::exprDescr); |
| 144 | } |
| 145 | //! @brief Tear down the test case. |
| 146 | static void TearDownTestSuite() |
| 147 | { |
| 148 | printTaskProgress(title, state: "END" ); |
| 149 | fixture.reset(); |
| 150 | } |
| 151 | |
| 152 | //! @brief Test title. |
| 153 | inline static const std::string_view title{numeric::integral::description()}; |
| 154 | //! @brief System under test. |
| 155 | //! @tparam SUT - type of system under test |
| 156 | //! @return system under test |
| 157 | template <typename SUT> |
| 158 | static std::unique_ptr<numeric::integral::Integral> sut() |
| 159 | { |
| 160 | return std::make_unique<SUT>(fixture->getExpression()); |
| 161 | } |
| 162 | //! @brief Fixture data. |
| 163 | inline static std::unique_ptr<InputBuilder> fixture{}; |
| 164 | //! @brief Expected result. |
| 165 | static constexpr double expRes{1.05838}; |
| 166 | //! @brief Allowable absolute error. |
| 167 | static constexpr double absErr{0.1 * ((expRes < 0.0) ? -expRes : expRes)}; |
| 168 | //! @brief Default precision. |
| 169 | static constexpr double defPrec{numeric::integral::epsilon}; |
| 170 | }; |
| 171 | |
| 172 | //! @brief Test for the trapezoidal method in the calculation of integral. |
| 173 | TEST_F(IntegralTestBase, TrapezoidalMethod) |
| 174 | { |
| 175 | const auto result = |
| 176 | (*sut<numeric::integral::Trapezoidal>())(fixture->getRanges().first, fixture->getRanges().second, defPrec); |
| 177 | EXPECT_GT(result, expRes - absErr); |
| 178 | EXPECT_LT(result, expRes + absErr); |
| 179 | } |
| 180 | |
| 181 | //! @brief Test for the adaptive Simpson's 1/3 method in the calculation of integral. |
| 182 | TEST_F(IntegralTestBase, AdaptiveSimpsonMethod) |
| 183 | { |
| 184 | const auto result = |
| 185 | (*sut<numeric::integral::Simpson>())(fixture->getRanges().first, fixture->getRanges().second, defPrec); |
| 186 | EXPECT_GT(result, expRes - absErr); |
| 187 | EXPECT_LT(result, expRes + absErr); |
| 188 | } |
| 189 | |
| 190 | //! @brief Test for the Romberg method in the calculation of integral. |
| 191 | TEST_F(IntegralTestBase, RombergMethod) |
| 192 | { |
| 193 | const auto result = |
| 194 | (*sut<numeric::integral::Romberg>())(fixture->getRanges().first, fixture->getRanges().second, defPrec); |
| 195 | EXPECT_GT(result, expRes - absErr); |
| 196 | EXPECT_LT(result, expRes + absErr); |
| 197 | } |
| 198 | |
| 199 | //! @brief Test for the Gauss-Legendre's 5-points method in the calculation of integral. |
| 200 | TEST_F(IntegralTestBase, GaussLegendreMethod) |
| 201 | { |
| 202 | const auto result = |
| 203 | (*sut<numeric::integral::Gauss>())(fixture->getRanges().first, fixture->getRanges().second, defPrec); |
| 204 | EXPECT_GT(result, expRes - absErr); |
| 205 | EXPECT_LT(result, expRes + absErr); |
| 206 | } |
| 207 | |
| 208 | //! @brief Test for the Monte-Carlo method in the calculation of integral. |
| 209 | TEST_F(IntegralTestBase, MonteCarloMethod) |
| 210 | { |
| 211 | const auto result = |
| 212 | (*sut<numeric::integral::MonteCarlo>())(fixture->getRanges().first, fixture->getRanges().second, defPrec); |
| 213 | EXPECT_GT(result, expRes - absErr); |
| 214 | EXPECT_LT(result, expRes + absErr); |
| 215 | } |
| 216 | |
| 217 | //! @brief Test base of prime. |
| 218 | class PrimeTestBase : public ::testing::Test |
| 219 | { |
| 220 | protected: |
| 221 | //! @brief Alias for the input builder. |
| 222 | using InputBuilder = application::app_num::prime::InputBuilder; |
| 223 | //! @brief Set up the test case. |
| 224 | static void SetUpTestSuite() |
| 225 | { |
| 226 | printTaskProgress(title, state: "BEGIN" ); |
| 227 | namespace input = application::app_num::prime::input; |
| 228 | fixture = std::make_unique<InputBuilder>(args: input::upperBound); |
| 229 | } |
| 230 | //! @brief Tear down the test case. |
| 231 | static void TearDownTestSuite() |
| 232 | { |
| 233 | printTaskProgress(title, state: "END" ); |
| 234 | fixture.reset(); |
| 235 | } |
| 236 | |
| 237 | //! @brief Test title. |
| 238 | inline static const std::string_view title{numeric::prime::description()}; |
| 239 | //! @brief System under test. |
| 240 | [[no_unique_address]] const numeric::prime::Prime sut{}; |
| 241 | //! @brief Fixture data. |
| 242 | inline static std::unique_ptr<InputBuilder> fixture{}; |
| 243 | //! @brief Expected result. |
| 244 | //! @return expected result |
| 245 | static constexpr auto expRes() |
| 246 | { |
| 247 | // NOLINTBEGIN(readability-magic-numbers) |
| 248 | return std::vector<std::uint32_t>{ |
| 249 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, |
| 250 | 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, |
| 251 | 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, |
| 252 | 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, |
| 253 | 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, |
| 254 | 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, |
| 255 | 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, |
| 256 | 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997}; |
| 257 | // NOLINTEND(readability-magic-numbers) |
| 258 | } |
| 259 | }; |
| 260 | |
| 261 | //! @brief Test for the Eratosthenes method in the calculation of prime. |
| 262 | TEST_F(PrimeTestBase, EratosthenesMethod) |
| 263 | { |
| 264 | ASSERT_EQ(expRes(), sut.eratosthenes(fixture->getUpperBound())); |
| 265 | } |
| 266 | |
| 267 | //! @brief Test for the Euler method in the calculation of prime. |
| 268 | TEST_F(PrimeTestBase, EulerMethod) |
| 269 | { |
| 270 | ASSERT_EQ(expRes(), sut.euler(fixture->getUpperBound())); |
| 271 | } |
| 272 | } // namespace tst_num |
| 273 | } // namespace test |
| 274 | |