From a39c9a3e09f30796231343f5015c580f72ba4c67 Mon Sep 17 00:00:00 2001
From: Sam Yates <halfflat@gmail.com>
Date: Thu, 27 Oct 2016 22:13:39 +0200
Subject: [PATCH] Unit tests for math.hpp

* Tests for `math::pi`, `math::lerp`, `math::area_frustrum`
  and `math::volume_frustrum`
* Fix `math:pi<long double>()`.
---
 src/math.hpp             |  2 +-
 tests/unit/test_math.cpp | 72 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/src/math.hpp b/src/math.hpp
index bf964ba3..36767bcb 100644
--- a/src/math.hpp
+++ b/src/math.hpp
@@ -11,7 +11,7 @@ namespace math {
 template <typename T>
 T constexpr pi()
 {
-    return T(3.1415926535897932384626433832795);
+    return T(3.1415926535897932384626433832795l);
 }
 
 template <typename T = float>
diff --git a/tests/unit/test_math.cpp b/tests/unit/test_math.cpp
index b32bd194..5dff6c81 100644
--- a/tests/unit/test_math.cpp
+++ b/tests/unit/test_math.cpp
@@ -6,6 +6,78 @@
 
 using namespace nest::mc::math;
 
+TEST(math, pi) {
+    // check regression against long double literal in implementation
+    auto pi_ld = pi<long double>();
+    auto pi_d = pi<double>();
+
+    if (std::numeric_limits<long double>::digits>std::numeric_limits<double>::digits) {
+        EXPECT_NE(0.0, pi_ld-pi_d);
+    }
+    else {
+        EXPECT_EQ(0.0, pi_ld-pi_d);
+    }
+
+    // library quality of implementation dependent, but expect cos(pi) to be within
+    // 1 epsilon of -1.
+
+    auto eps_d = std::numeric_limits<double>::epsilon();
+    auto cos_pi_d = std::cos(pi_d);
+    EXPECT_LE(-1.0-eps_d, cos_pi_d);
+    EXPECT_GE(-1.0+eps_d, cos_pi_d);
+
+    auto eps_ld = std::numeric_limits<long double>::epsilon();
+    auto cos_pi_ld = std::cos(pi_ld);
+    EXPECT_LE(-1.0-eps_ld, cos_pi_ld);
+    EXPECT_GE(-1.0+eps_ld, cos_pi_ld);
+}
+
+TEST(math, lerp) {
+    // expect exact computation when u is zero or one
+    double a = 1.0/3;
+    double b = 11.0/7;
+
+    EXPECT_EQ(a, lerp(a, b, 0.));
+    EXPECT_EQ(b, lerp(a, b, 1.));
+
+    // expect exact computation here as well
+    EXPECT_EQ(2.75, lerp(2.0, 3.0, 0.75));
+
+    // and otherwise to be close
+    EXPECT_DOUBLE_EQ(100.101, lerp(100.1, 200.1, 0.00001));
+    EXPECT_DOUBLE_EQ(200.099, lerp(100.1, 200.1, 0.99999));
+
+    // should be able to lerp with differing types for end points and u
+    EXPECT_EQ(0.25f, lerp(0.f, 1.f, 0.25));
+}
+
+TEST(math, frustrum) {
+    // cross check against cone calculation
+    auto cone_area = [](double l, double r) {
+        return std::hypot(l,r)*r*pi<double>();
+    };
+
+    auto cone_volume = [](double l, double r) {
+        return pi<double>()*square(r)*l/3.0;
+    };
+
+    EXPECT_DOUBLE_EQ(cone_area(5.0, 1.3), area_frustrum(5.0, 0.0, 1.3));
+    EXPECT_DOUBLE_EQ(cone_volume(5.0, 1.3), volume_frustrum(5.0, 0.0, 1.3));
+
+    double r1 = 7.0;
+    double r2 = 9.0;
+    double l = 11.0;
+
+    double s = l*r2/(r2-r1);
+    double ca = cone_area(s, r2)-cone_area(s-l, r1);
+    double cv = cone_volume(s, r2)-cone_volume(s-l, r1);
+
+    EXPECT_DOUBLE_EQ(ca, area_frustrum(l, r1, r2));
+    EXPECT_DOUBLE_EQ(ca, area_frustrum(l, r2, r1));
+    EXPECT_DOUBLE_EQ(cv, volume_frustrum(l, r1, r2));
+    EXPECT_DOUBLE_EQ(cv, volume_frustrum(l, r2, r1));
+}
+
 TEST(math, infinity) {
     // check values for float, double, long double
     auto finf = infinity<float>();
-- 
GitLab