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.
13namespace test // NOLINT(modernize-concat-nested-namespaces)
14{
15//! @brief Numeric-testing-related functions in the test module.
16namespace 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
22static 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.
30class ArithmeticTestBase : public ::testing::Test
31{
32protected:
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.
66TEST_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.
72TEST_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.
78TEST_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.
84TEST_F(ArithmeticTestBase, DivisionMethod)
85{
86 ASSERT_EQ(expRes4, sut.division(fixture->getOperands().first, fixture->getOperands().second));
87}
88
89//! @brief Test base of divisor.
90class DivisorTestBase : public ::testing::Test
91{
92protected:
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.
120TEST_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.
126TEST_F(DivisorTestBase, SteinMethod)
127{
128 ASSERT_EQ(expRes, sut.stein(fixture->getNumbers().first, fixture->getNumbers().second));
129}
130
131//! @brief Test base of integral.
132class IntegralTestBase : public ::testing::Test
133{
134protected:
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.
173TEST_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.
182TEST_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.
191TEST_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.
200TEST_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.
209TEST_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.
218class PrimeTestBase : public ::testing::Test
219{
220protected:
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.
262TEST_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.
268TEST_F(PrimeTestBase, EulerMethod)
269{
270 ASSERT_EQ(expRes(), sut.euler(fixture->getUpperBound()));
271}
272} // namespace tst_num
273} // namespace test
274