1 /*
2  *  Created by Phil on 28/04/2011.
3  *  Copyright 2011 Two Blue Cubes Ltd. All rights reserved.
4  *
5  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
6  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  */
8 
9 #include "catch.hpp"
10 
11 #include <cmath>
12 
13 namespace { namespace ApproxTests {
14 
15 #ifndef APPROX_TEST_HELPERS_INCLUDED // Don't compile this more than once per TU
16 #define APPROX_TEST_HELPERS_INCLUDED
17 
divide(double a,double b)18     inline double divide( double a, double b ) {
19         return a/b;
20     }
21 
22     class StrongDoubleTypedef {
23         double d_ = 0.0;
24 
25     public:
StrongDoubleTypedef(double d)26         explicit StrongDoubleTypedef(double d) : d_(d) {}
operator double() const27         explicit operator double() const { return d_; }
28     };
29 
operator <<(std::ostream & os,StrongDoubleTypedef td)30     inline std::ostream& operator<<( std::ostream& os, StrongDoubleTypedef td ) {
31         return os << "StrongDoubleTypedef(" << static_cast<double>(td) << ")";
32     }
33 
34 #endif
35 
36 using namespace Catch::literals;
37 
38 ///////////////////////////////////////////////////////////////////////////////
39 TEST_CASE( "A comparison that uses literals instead of the normal constructor", "[Approx]" ) {
40     double d = 1.23;
41 
42     REQUIRE( d == 1.23_a );
43     REQUIRE( d != 1.22_a );
44     REQUIRE( -d == -1.23_a );
45 
46     REQUIRE( d == 1.2_a .epsilon(.1) );
47     REQUIRE( d != 1.2_a .epsilon(.001) );
48     REQUIRE( d == 1_a .epsilon(.3) );
49 }
50 
51 TEST_CASE( "Some simple comparisons between doubles", "[Approx]" ) {
52     double d = 1.23;
53 
54     REQUIRE( d == Approx( 1.23 ) );
55     REQUIRE( d != Approx( 1.22 ) );
56     REQUIRE( d != Approx( 1.24 ) );
57 
58     REQUIRE( d == 1.23_a );
59     REQUIRE( d != 1.22_a );
60 
61     REQUIRE( Approx( d ) == 1.23 );
62     REQUIRE( Approx( d ) != 1.22 );
63     REQUIRE( Approx( d ) != 1.24 );
64 
65     REQUIRE(INFINITY == Approx(INFINITY));
66 }
67 
68 ///////////////////////////////////////////////////////////////////////////////
69 TEST_CASE( "Approximate comparisons with different epsilons", "[Approx]" ) {
70     double d = 1.23;
71 
72     REQUIRE( d != Approx( 1.231 ) );
73     REQUIRE( d == Approx( 1.231 ).epsilon( 0.1 ) );
74 }
75 
76 ///////////////////////////////////////////////////////////////////////////////
77 TEST_CASE( "Less-than inequalities with different epsilons", "[Approx]" ) {
78   double d = 1.23;
79 
80   REQUIRE( d <= Approx( 1.24 ) );
81   REQUIRE( d <= Approx( 1.23 ) );
82   REQUIRE_FALSE( d <= Approx( 1.22 ) );
83   REQUIRE( d <= Approx( 1.22 ).epsilon(0.1) );
84 }
85 
86 ///////////////////////////////////////////////////////////////////////////////
87 TEST_CASE( "Greater-than inequalities with different epsilons", "[Approx]" ) {
88   double d = 1.23;
89 
90   REQUIRE( d >= Approx( 1.22 ) );
91   REQUIRE( d >= Approx( 1.23 ) );
92   REQUIRE_FALSE( d >= Approx( 1.24 ) );
93   REQUIRE( d >= Approx( 1.24 ).epsilon(0.1) );
94 }
95 
96 ///////////////////////////////////////////////////////////////////////////////
97 TEST_CASE( "Approximate comparisons with floats", "[Approx]" ) {
98     REQUIRE( 1.23f == Approx( 1.23f ) );
99     REQUIRE( 0.0f == Approx( 0.0f ) );
100 }
101 
102 ///////////////////////////////////////////////////////////////////////////////
103 TEST_CASE( "Approximate comparisons with ints", "[Approx]" ) {
104     REQUIRE( 1 == Approx( 1 ) );
105     REQUIRE( 0 == Approx( 0 ) );
106 }
107 
108 ///////////////////////////////////////////////////////////////////////////////
109 TEST_CASE( "Approximate comparisons with mixed numeric types", "[Approx]" ) {
110     const double dZero = 0;
111     const double dSmall = 0.00001;
112     const double dMedium = 1.234;
113 
114     REQUIRE( 1.0f == Approx( 1 ) );
115     REQUIRE( 0 == Approx( dZero) );
116     REQUIRE( 0 == Approx( dSmall ).margin( 0.001 ) );
117     REQUIRE( 1.234f == Approx( dMedium ) );
118     REQUIRE( dMedium == Approx( 1.234f ) );
119 }
120 
121 ///////////////////////////////////////////////////////////////////////////////
122 TEST_CASE( "Use a custom approx", "[Approx][custom]" ) {
123     double d = 1.23;
124 
125     Approx approx = Approx::custom().epsilon( 0.01 );
126 
127     REQUIRE( d == approx( 1.23 ) );
128     REQUIRE( d == approx( 1.22 ) );
129     REQUIRE( d == approx( 1.24 ) );
130     REQUIRE( d != approx( 1.25 ) );
131 
132     REQUIRE( approx( d ) == 1.23 );
133     REQUIRE( approx( d ) == 1.22 );
134     REQUIRE( approx( d ) == 1.24 );
135     REQUIRE( approx( d ) != 1.25 );
136 }
137 
138 TEST_CASE( "Approximate PI", "[Approx][PI]" ) {
139     REQUIRE( divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) );
140     REQUIRE( divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) );
141 }
142 
143 ///////////////////////////////////////////////////////////////////////////////
144 
145 TEST_CASE( "Absolute margin", "[Approx]" ) {
146     REQUIRE( 104.0 != Approx(100.0) );
147     REQUIRE( 104.0 == Approx(100.0).margin(5) );
148     REQUIRE( 104.0 == Approx(100.0).margin(4) );
149     REQUIRE( 104.0 != Approx(100.0).margin(3) );
150     REQUIRE( 100.3 != Approx(100.0) );
151     REQUIRE( 100.3 == Approx(100.0).margin(0.5) );
152 }
153 
154 TEST_CASE("Approx with exactly-representable margin", "[Approx]") {
155     CHECK( 0.25f == Approx(0.0f).margin(0.25f) );
156 
157     CHECK( 0.0f == Approx(0.25f).margin(0.25f) );
158     CHECK( 0.5f == Approx(0.25f).margin(0.25f) );
159 
160     CHECK( 245.0f == Approx(245.25f).margin(0.25f) );
161     CHECK( 245.5f == Approx(245.25f).margin(0.25f) );
162 }
163 
164 TEST_CASE("Approx setters validate their arguments", "[Approx]") {
165     REQUIRE_NOTHROW(Approx(0).margin(0));
166     REQUIRE_NOTHROW(Approx(0).margin(1234656));
167 
168     REQUIRE_THROWS_AS(Approx(0).margin(-2), std::domain_error);
169 
170     REQUIRE_NOTHROW(Approx(0).epsilon(0));
171     REQUIRE_NOTHROW(Approx(0).epsilon(1));
172 
173     REQUIRE_THROWS_AS(Approx(0).epsilon(-0.001), std::domain_error);
174     REQUIRE_THROWS_AS(Approx(0).epsilon(1.0001), std::domain_error);
175 }
176 
177 TEST_CASE("Default scale is invisible to comparison", "[Approx]") {
178     REQUIRE(101.000001 != Approx(100).epsilon(0.01));
179     REQUIRE(std::pow(10, -5) != Approx(std::pow(10, -7)));
180 }
181 
182 TEST_CASE("Epsilon only applies to Approx's value", "[Approx]") {
183     REQUIRE(101.01 != Approx(100).epsilon(0.01));
184 }
185 
186 TEST_CASE("Assorted miscellaneous tests", "[Approx]") {
187     REQUIRE(INFINITY == Approx(INFINITY));
188     REQUIRE(NAN != Approx(NAN));
189     REQUIRE_FALSE(NAN == Approx(NAN));
190 }
191 
192 TEST_CASE( "Comparison with explicitly convertible types", "[Approx]" )
193 {
194   StrongDoubleTypedef td(10.0);
195 
196   REQUIRE(td == Approx(10.0));
197   REQUIRE(Approx(10.0) == td);
198 
199   REQUIRE(td != Approx(11.0));
200   REQUIRE(Approx(11.0) != td);
201 
202   REQUIRE(td <= Approx(10.0));
203   REQUIRE(td <= Approx(11.0));
204   REQUIRE(Approx(10.0) <= td);
205   REQUIRE(Approx(9.0) <= td);
206 
207   REQUIRE(td >= Approx(9.0));
208   REQUIRE(td >= Approx(td));
209   REQUIRE(Approx(td) >= td);
210   REQUIRE(Approx(11.0) >= td);
211 
212 }
213 
214 }} // namespace ApproxTests
215