Skip to content

Commit 85e3313

Browse files
authored
fix: use Catch2 custom matcher instead of function (#995)
When running the first test cases without use of the require_approx_equal helper function, a warning is issued which will be treated as an error. Using a custom Catch2 matcher fixes this.
1 parent 546e0bc commit 85e3313

File tree

1 file changed

+58
-34
lines changed

1 file changed

+58
-34
lines changed

exercises/practice/complex-numbers/complex_numbers_test.cpp

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "complex_numbers.h"
22

33
#include <cmath>
4+
#include <sstream>
45

56
#ifdef EXERCISM_TEST_SUITE
67
#include <catch2/catch.hpp>
@@ -22,12 +23,35 @@ using complex_numbers::Complex;
2223

2324
// Define a margin to use for float comparisons. Catch does not compute a good
2425
// epsilon for float values near 0.
25-
static const double eps = 0.005;
26+
static constexpr double eps = 0.005;
2627

27-
// Helper function for comparing Complex numbers with approximate float values.
28-
static void require_approx_equal(const Complex& lhs, const Complex& rhs) {
29-
REQUIRE_THAT(lhs.real(), Catch::Matchers::WithinAbs(rhs.real(), eps));
30-
REQUIRE_THAT(lhs.imag(), Catch::Matchers::WithinAbs(rhs.imag(), eps));
28+
// Custom Catch2 matcher for approximate equality of Complex numbers
29+
class ComplexApproxMatcher : public Catch::MatcherBase<Complex> {
30+
public:
31+
ComplexApproxMatcher(const Complex& expected, double epsilon)
32+
: expected{expected}, epsilon{epsilon} {}
33+
34+
bool match(const Complex& actual) const override {
35+
return std::abs(actual.real() - expected.real()) <= epsilon &&
36+
std::abs(actual.imag() - expected.imag()) <= epsilon;
37+
}
38+
39+
std::string describe() const override {
40+
std::ostringstream ss;
41+
ss << "is approximately equal to (" << expected.real() << ", "
42+
<< expected.imag() << "i) with epsilon " << epsilon;
43+
return ss.str();
44+
}
45+
46+
private:
47+
Complex expected;
48+
double epsilon;
49+
};
50+
51+
// Helper function to create the matcher
52+
inline ComplexApproxMatcher ComplexWithinAbs(const Complex& expected,
53+
double epsilon) {
54+
return ComplexApproxMatcher{expected, epsilon};
3155
}
3256

3357
TEST_CASE("Real part -> Real part of a purely real number",
@@ -78,47 +102,47 @@ TEST_CASE("Imaginary unit", "[a39b7fd6-6527-492f-8c34-609d2c913879]") {
78102
const Complex c1{0.0, 1.0};
79103
const Complex c2{0.0, 1.0};
80104

81-
require_approx_equal(Complex(-1.0, 0.0), c1 * c2);
105+
REQUIRE_THAT(c1 * c2, ComplexWithinAbs(Complex{-1.0, 0.0}, eps));
82106
}
83107

84108
TEST_CASE("Arithmetic -> Addition -> Add purely real numbers",
85109
"[9a2c8de9-f068-4f6f-b41c-82232cc6c33e]") {
86110
const Complex c1{1.0, 0.0};
87111
const Complex c2{2.0, 0.0};
88112

89-
require_approx_equal(Complex(3.0, 0.0), c1 + c2);
113+
REQUIRE_THAT(c1 + c2, ComplexWithinAbs(Complex{3.0, 0.0}, eps));
90114
}
91115

92116
TEST_CASE("Arithmetic -> Addition -> Add purely imaginary numbers",
93117
"[657c55e1-b14b-4ba7-bd5c-19db22b7d659]") {
94118
const Complex c1{0.0, 1.0};
95119
const Complex c2{0.0, 2.0};
96120

97-
require_approx_equal(Complex(0.0, 3.0), c1 + c2);
121+
REQUIRE_THAT(c1 + c2, ComplexWithinAbs(Complex{0.0, 3.0}, eps));
98122
}
99123

100124
TEST_CASE("Arithmetic -> Addition -> Add numbers with real and imaginary part",
101125
"[4e1395f5-572b-4ce8-bfa9-9a63056888da]") {
102126
const Complex c1{1.0, 2.0};
103127
const Complex c2{3.0, 4.0};
104128

105-
require_approx_equal(Complex(4.0, 6.0), c1 + c2);
129+
REQUIRE_THAT(c1 + c2, ComplexWithinAbs(Complex{4.0, 6.0}, eps));
106130
}
107131

108132
TEST_CASE("Arithmetic -> Subtraction -> Subtract purely real numbers",
109133
"[1155dc45-e4f7-44b8-af34-a91aa431475d]") {
110134
const Complex c1{1.0, 0.0};
111135
const Complex c2{2.0, 0.0};
112136

113-
require_approx_equal(Complex(-1.0, 0.0), c1 - c2);
137+
REQUIRE_THAT(c1 - c2, ComplexWithinAbs(Complex{-1.0, 0.0}, eps));
114138
}
115139

116140
TEST_CASE("Arithmetic -> Subtraction -> Subtract purely imaginary numbers",
117141
"[f95e9da8-acd5-4da4-ac7c-c861b02f774b]") {
118142
const Complex c1{0.0, 1.0};
119143
const Complex c2{0.0, 2.0};
120144

121-
require_approx_equal(Complex(0.0, -1.0), c1 - c2);
145+
REQUIRE_THAT(c1 - c2, ComplexWithinAbs(Complex{0.0, -1.0}, eps));
122146
}
123147

124148
TEST_CASE(
@@ -129,23 +153,23 @@ TEST_CASE(
129153
const Complex c1{1.0, 2.0};
130154
const Complex c2{3.0, 4.0};
131155

132-
require_approx_equal(Complex(-2.0, -2.0), c1 - c2);
156+
REQUIRE_THAT(c1 - c2, ComplexWithinAbs(Complex{-2.0, -2.0}, eps));
133157
}
134158

135159
TEST_CASE("Arithmetic -> Multiplication -> Multiply purely real numbers",
136160
"[8a0366c0-9e16-431f-9fd7-40ac46ff4ec4]") {
137161
const Complex c1{1.0, 0.0};
138162
const Complex c2{2.0, 0.0};
139163

140-
require_approx_equal(Complex(2.0, 0.0), c1 * c2);
164+
REQUIRE_THAT(c1 * c2, ComplexWithinAbs(Complex{2.0, 0.0}, eps));
141165
}
142166

143167
TEST_CASE("Arithmetic -> Multiplication -> Multiply purely imaginary numbers",
144168
"[e560ed2b-0b80-4b4f-90f2-63cefc911aaf]") {
145169
const Complex c1{0.0, 1.0};
146170
const Complex c2{0.0, 2.0};
147171

148-
require_approx_equal(Complex(-2.0, 0.0), c1 * c2);
172+
REQUIRE_THAT(c1 * c2, ComplexWithinAbs(Complex{-2.0, 0.0}, eps));
149173
}
150174

151175
TEST_CASE(
@@ -156,23 +180,23 @@ TEST_CASE(
156180
const Complex c1{1.0, 2.0};
157181
const Complex c2{3.0, 4.0};
158182

159-
require_approx_equal(Complex(-5.0, 10.0), c1 * c2);
183+
REQUIRE_THAT(c1 * c2, ComplexWithinAbs(Complex{-5.0, 10.0}, eps));
160184
}
161185

162186
TEST_CASE("Arithmetic -> Division -> Divide purely real numbers",
163187
"[b0571ddb-9045-412b-9c15-cd1d816d36c1]") {
164188
const Complex c1{1.0, 0.0};
165189
const Complex c2{2.0, 0.0};
166190

167-
require_approx_equal(Complex(0.5, 0.0), c1 / c2);
191+
REQUIRE_THAT(c1 / c2, ComplexWithinAbs(Complex{0.5, 0.0}, eps));
168192
}
169193

170194
TEST_CASE("Arithmetic -> Division -> Divide purely imaginary numbers",
171195
"[5bb4c7e4-9934-4237-93cc-5780764fdbdd]") {
172196
const Complex c1{0.0, 1.0};
173197
const Complex c2{0.0, 2.0};
174198

175-
require_approx_equal(Complex(0.5, 0.0), c1 / c2);
199+
REQUIRE_THAT(c1 / c2, ComplexWithinAbs(Complex{0.5, 0.0}, eps));
176200
}
177201

178202
TEST_CASE(
@@ -181,7 +205,7 @@ TEST_CASE(
181205
const Complex c1{1.0, 2.0};
182206
const Complex c2{3.0, 4.0};
183207

184-
require_approx_equal(Complex(0.44, 0.08), c1 / c2);
208+
REQUIRE_THAT(c1 / c2, ComplexWithinAbs(Complex{0.44, 0.08}, eps));
185209
}
186210

187211
TEST_CASE("Absolute value -> Absolute value of a positive purely real number",
@@ -230,43 +254,43 @@ TEST_CASE("Complex conjugate -> Conjugate a purely real number",
230254
"[fb2d0792-e55a-4484-9443-df1eddfc84a2]") {
231255
const Complex c{5.0, 0.0};
232256

233-
require_approx_equal(Complex(5.0, 0.0), c.conj());
257+
REQUIRE_THAT(c.conj(), ComplexWithinAbs(Complex{5.0, 0.0}, eps));
234258
}
235259

236260
TEST_CASE("Complex conjugate -> Conjugate a purely imaginary number",
237261
"[e37fe7ac-a968-4694-a460-66cb605f8691]") {
238262
const Complex c{0.0, 5.0};
239263

240-
require_approx_equal(Complex(0.0, -5.0), c.conj());
264+
REQUIRE_THAT(c.conj(), ComplexWithinAbs(Complex{0.0, -5.0}, eps));
241265
}
242266

243267
TEST_CASE(
244268
"Complex conjugate -> Conjugate a number with real and imaginary part",
245269
"[f7704498-d0be-4192-aaf5-a1f3a7f43e68]") {
246270
const Complex c{1.0, 1.0};
247271

248-
require_approx_equal(Complex(1.0, -1.0), c.conj());
272+
REQUIRE_THAT(c.conj(), ComplexWithinAbs(Complex{1.0, -1.0}, eps));
249273
}
250274

251275
TEST_CASE("Complex exponential function -> Euler's identity/formula",
252276
"[6d96d4c6-2edb-445b-94a2-7de6d4caaf60]") {
253277
const Complex c{0.0, M_PI};
254278

255-
require_approx_equal(Complex(-1.0, 0.0), c.exp());
279+
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex{-1.0, 0.0}, eps));
256280
}
257281

258282
TEST_CASE("Complex exponential function -> Exponential of 0",
259283
"[2d2c05a0-4038-4427-a24d-72f6624aa45f]") {
260284
const Complex c{0.0, 0.0};
261285

262-
require_approx_equal(Complex(1.0, 0.0), c.exp());
286+
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex{1.0, 0.0}, eps));
263287
}
264288

265289
TEST_CASE("Complex exponential function -> Exponential of a purely real number",
266290
"[ed87f1bd-b187-45d6-8ece-7e331232c809]") {
267291
const Complex c{1.0, 0.0};
268292

269-
require_approx_equal(Complex(M_E, 0.0), c.exp());
293+
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex(M_E, 0.0), eps));
270294
}
271295

272296
// Extra Credit
@@ -277,7 +301,7 @@ TEST_CASE(
277301
"[08eedacc-5a95-44fc-8789-1547b27a8702]") {
278302
const Complex c{std::log(2.0), M_PI};
279303

280-
require_approx_equal(Complex(-2.0, 0.0), c.exp());
304+
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex{-2.0, 0.0}, eps));
281305
}
282306

283307
TEST_CASE(
@@ -287,7 +311,7 @@ TEST_CASE(
287311
"[d2de4375-7537-479a-aa0e-d474f4f09859]") {
288312
const Complex c{std::log(2.0) / 2.0, M_PI / 4.0};
289313

290-
require_approx_equal(Complex(1.0, 1.0), c.exp());
314+
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex{1.0, 1.0}, eps));
291315
}
292316

293317
TEST_CASE(
@@ -297,7 +321,7 @@ TEST_CASE(
297321
"[06d793bf-73bd-4b02-b015-3030b2c952ec]") {
298322
const Complex c{1.0, 2.0};
299323

300-
require_approx_equal(Complex(6.0, 2.0), c + 5.0);
324+
REQUIRE_THAT(c + 5.0, ComplexWithinAbs(Complex{6.0, 2.0}, eps));
301325
}
302326

303327
TEST_CASE(
@@ -307,7 +331,7 @@ TEST_CASE(
307331
"[d77dbbdf-b8df-43f6-a58d-3acb96765328]") {
308332
const Complex c{1.0, 2.0};
309333

310-
require_approx_equal(Complex(6.0, 2.0), 5.0 + c);
334+
REQUIRE_THAT(5.0 + c, ComplexWithinAbs(Complex{6.0, 2.0}, eps));
311335
}
312336

313337
TEST_CASE(
@@ -317,7 +341,7 @@ TEST_CASE(
317341
"[20432c8e-8960-4c40-ba83-c9d910ff0a0f]") {
318342
const Complex c{5.0, 7.0};
319343

320-
require_approx_equal(Complex(1.0, 7.0), c - 4.0);
344+
REQUIRE_THAT(c - 4.0, ComplexWithinAbs(Complex{1.0, 7.0}, eps));
321345
}
322346

323347
TEST_CASE(
@@ -327,7 +351,7 @@ TEST_CASE(
327351
"[b4b38c85-e1bf-437d-b04d-49bba6e55000]") {
328352
const Complex c{5.0, 7.0};
329353

330-
require_approx_equal(Complex(-1.0, -7.0), 4.0 - c);
354+
REQUIRE_THAT(4.0 - c, ComplexWithinAbs(Complex{-1.0, -7.0}, eps));
331355
}
332356

333357
TEST_CASE(
@@ -337,7 +361,7 @@ TEST_CASE(
337361
"[dabe1c8c-b8f4-44dd-879d-37d77c4d06bd]") {
338362
const Complex c{2.0, 5.0};
339363

340-
require_approx_equal(Complex(10.0, 25.0), c * 5.0);
364+
REQUIRE_THAT(c * 5.0, ComplexWithinAbs(Complex{10.0, 25.0}, eps));
341365
}
342366

343367
TEST_CASE(
@@ -347,7 +371,7 @@ TEST_CASE(
347371
"[6c81b8c8-9851-46f0-9de5-d96d314c3a28]") {
348372
const Complex c{2.0, 5.0};
349373

350-
require_approx_equal(Complex(10.0, 25.0), 5.0 * c);
374+
REQUIRE_THAT(5.0 * c, ComplexWithinAbs(Complex{10.0, 25.0}, eps));
351375
}
352376

353377
TEST_CASE(
@@ -357,7 +381,7 @@ TEST_CASE(
357381
"[8a400f75-710e-4d0c-bcb4-5e5a00c78aa0]") {
358382
const Complex c{10.0, 100.0};
359383

360-
require_approx_equal(Complex(1.0, 10.0), c / 10.0);
384+
REQUIRE_THAT(c / 10.0, ComplexWithinAbs(Complex{1.0, 10.0}, eps));
361385
}
362386

363387
TEST_CASE(
@@ -367,7 +391,7 @@ TEST_CASE(
367391
"[9a867d1b-d736-4c41-a41e-90bd148e9d5e]") {
368392
const Complex c{1.0, 1.0};
369393

370-
require_approx_equal(Complex(2.5, -2.5), 5.0 / c);
394+
REQUIRE_THAT(5.0 / c, ComplexWithinAbs(Complex{2.5, -2.5}, eps));
371395
}
372396

373397
#endif

0 commit comments

Comments
 (0)