Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 58 additions & 34 deletions exercises/practice/complex-numbers/complex_numbers_test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "complex_numbers.h"

#include <cmath>
#include <sstream>

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

// Define a margin to use for float comparisons. Catch does not compute a good
// epsilon for float values near 0.
static const double eps = 0.005;
static constexpr double eps = 0.005;

// Helper function for comparing Complex numbers with approximate float values.
static void require_approx_equal(const Complex& lhs, const Complex& rhs) {
REQUIRE_THAT(lhs.real(), Catch::Matchers::WithinAbs(rhs.real(), eps));
REQUIRE_THAT(lhs.imag(), Catch::Matchers::WithinAbs(rhs.imag(), eps));
// Custom Catch2 matcher for approximate equality of Complex numbers
class ComplexApproxMatcher : public Catch::MatcherBase<Complex> {
public:
ComplexApproxMatcher(const Complex& expected, double epsilon)
: expected{expected}, epsilon{epsilon} {}

bool match(const Complex& actual) const override {
return std::abs(actual.real() - expected.real()) <= epsilon &&
std::abs(actual.imag() - expected.imag()) <= epsilon;
}

std::string describe() const override {
std::ostringstream ss;
ss << "is approximately equal to (" << expected.real() << ", "
<< expected.imag() << "i) with epsilon " << epsilon;
return ss.str();
}

private:
Complex expected;
double epsilon;
};

// Helper function to create the matcher
inline ComplexApproxMatcher ComplexWithinAbs(const Complex& expected,
double epsilon) {
return ComplexApproxMatcher{expected, epsilon};
}

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

require_approx_equal(Complex(-1.0, 0.0), c1 * c2);
REQUIRE_THAT(c1 * c2, ComplexWithinAbs(Complex{-1.0, 0.0}, eps));
}

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

require_approx_equal(Complex(3.0, 0.0), c1 + c2);
REQUIRE_THAT(c1 + c2, ComplexWithinAbs(Complex{3.0, 0.0}, eps));
}

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

require_approx_equal(Complex(0.0, 3.0), c1 + c2);
REQUIRE_THAT(c1 + c2, ComplexWithinAbs(Complex{0.0, 3.0}, eps));
}

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

require_approx_equal(Complex(4.0, 6.0), c1 + c2);
REQUIRE_THAT(c1 + c2, ComplexWithinAbs(Complex{4.0, 6.0}, eps));
}

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

require_approx_equal(Complex(-1.0, 0.0), c1 - c2);
REQUIRE_THAT(c1 - c2, ComplexWithinAbs(Complex{-1.0, 0.0}, eps));
}

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

require_approx_equal(Complex(0.0, -1.0), c1 - c2);
REQUIRE_THAT(c1 - c2, ComplexWithinAbs(Complex{0.0, -1.0}, eps));
}

TEST_CASE(
Expand All @@ -129,23 +153,23 @@ TEST_CASE(
const Complex c1{1.0, 2.0};
const Complex c2{3.0, 4.0};

require_approx_equal(Complex(-2.0, -2.0), c1 - c2);
REQUIRE_THAT(c1 - c2, ComplexWithinAbs(Complex{-2.0, -2.0}, eps));
}

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

require_approx_equal(Complex(2.0, 0.0), c1 * c2);
REQUIRE_THAT(c1 * c2, ComplexWithinAbs(Complex{2.0, 0.0}, eps));
}

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

require_approx_equal(Complex(-2.0, 0.0), c1 * c2);
REQUIRE_THAT(c1 * c2, ComplexWithinAbs(Complex{-2.0, 0.0}, eps));
}

TEST_CASE(
Expand All @@ -156,23 +180,23 @@ TEST_CASE(
const Complex c1{1.0, 2.0};
const Complex c2{3.0, 4.0};

require_approx_equal(Complex(-5.0, 10.0), c1 * c2);
REQUIRE_THAT(c1 * c2, ComplexWithinAbs(Complex{-5.0, 10.0}, eps));
}

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

require_approx_equal(Complex(0.5, 0.0), c1 / c2);
REQUIRE_THAT(c1 / c2, ComplexWithinAbs(Complex{0.5, 0.0}, eps));
}

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

require_approx_equal(Complex(0.5, 0.0), c1 / c2);
REQUIRE_THAT(c1 / c2, ComplexWithinAbs(Complex{0.5, 0.0}, eps));
}

TEST_CASE(
Expand All @@ -181,7 +205,7 @@ TEST_CASE(
const Complex c1{1.0, 2.0};
const Complex c2{3.0, 4.0};

require_approx_equal(Complex(0.44, 0.08), c1 / c2);
REQUIRE_THAT(c1 / c2, ComplexWithinAbs(Complex{0.44, 0.08}, eps));
}

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

require_approx_equal(Complex(5.0, 0.0), c.conj());
REQUIRE_THAT(c.conj(), ComplexWithinAbs(Complex{5.0, 0.0}, eps));
}

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

require_approx_equal(Complex(0.0, -5.0), c.conj());
REQUIRE_THAT(c.conj(), ComplexWithinAbs(Complex{0.0, -5.0}, eps));
}

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

require_approx_equal(Complex(1.0, -1.0), c.conj());
REQUIRE_THAT(c.conj(), ComplexWithinAbs(Complex{1.0, -1.0}, eps));
}

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

require_approx_equal(Complex(-1.0, 0.0), c.exp());
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex{-1.0, 0.0}, eps));
}

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

require_approx_equal(Complex(1.0, 0.0), c.exp());
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex{1.0, 0.0}, eps));
}

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

require_approx_equal(Complex(M_E, 0.0), c.exp());
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex(M_E, 0.0), eps));
}

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

require_approx_equal(Complex(-2.0, 0.0), c.exp());
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex{-2.0, 0.0}, eps));
}

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

require_approx_equal(Complex(1.0, 1.0), c.exp());
REQUIRE_THAT(c.exp(), ComplexWithinAbs(Complex{1.0, 1.0}, eps));
}

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

require_approx_equal(Complex(6.0, 2.0), c + 5.0);
REQUIRE_THAT(c + 5.0, ComplexWithinAbs(Complex{6.0, 2.0}, eps));
}

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

require_approx_equal(Complex(6.0, 2.0), 5.0 + c);
REQUIRE_THAT(5.0 + c, ComplexWithinAbs(Complex{6.0, 2.0}, eps));
}

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

require_approx_equal(Complex(1.0, 7.0), c - 4.0);
REQUIRE_THAT(c - 4.0, ComplexWithinAbs(Complex{1.0, 7.0}, eps));
}

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

require_approx_equal(Complex(-1.0, -7.0), 4.0 - c);
REQUIRE_THAT(4.0 - c, ComplexWithinAbs(Complex{-1.0, -7.0}, eps));
}

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

require_approx_equal(Complex(10.0, 25.0), c * 5.0);
REQUIRE_THAT(c * 5.0, ComplexWithinAbs(Complex{10.0, 25.0}, eps));
}

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

require_approx_equal(Complex(10.0, 25.0), 5.0 * c);
REQUIRE_THAT(5.0 * c, ComplexWithinAbs(Complex{10.0, 25.0}, eps));
}

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

require_approx_equal(Complex(1.0, 10.0), c / 10.0);
REQUIRE_THAT(c / 10.0, ComplexWithinAbs(Complex{1.0, 10.0}, eps));
}

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

require_approx_equal(Complex(2.5, -2.5), 5.0 / c);
REQUIRE_THAT(5.0 / c, ComplexWithinAbs(Complex{2.5, -2.5}, eps));
}

#endif
Loading