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 
66 ///////////////////////////////////////////////////////////////////////////////
67 TEST_CASE( "Approximate comparisons with different epsilons", "[Approx]" ) {
68     double d = 1.23;
69 
70     REQUIRE( d != Approx( 1.231 ) );
71     REQUIRE( d == Approx( 1.231 ).epsilon( 0.1 ) );
72 }
73 
74 ///////////////////////////////////////////////////////////////////////////////
75 TEST_CASE( "Less-than inequalities with different epsilons", "[Approx]" ) {
76   double d = 1.23;
77 
78   REQUIRE( d <= Approx( 1.24 ) );
79   REQUIRE( d <= Approx( 1.23 ) );
80   REQUIRE_FALSE( d <= Approx( 1.22 ) );
81   REQUIRE( d <= Approx( 1.22 ).epsilon(0.1) );
82 }
83 
84 ///////////////////////////////////////////////////////////////////////////////
85 TEST_CASE( "Greater-than inequalities with different epsilons", "[Approx]" ) {
86   double d = 1.23;
87 
88   REQUIRE( d >= Approx( 1.22 ) );
89   REQUIRE( d >= Approx( 1.23 ) );
90   REQUIRE_FALSE( d >= Approx( 1.24 ) );
91   REQUIRE( d >= Approx( 1.24 ).epsilon(0.1) );
92 }
93 
94 ///////////////////////////////////////////////////////////////////////////////
95 TEST_CASE( "Approximate comparisons with floats", "[Approx]" ) {
96     REQUIRE( 1.23f == Approx( 1.23f ) );
97     REQUIRE( 0.0f == Approx( 0.0f ) );
98 }
99 
100 ///////////////////////////////////////////////////////////////////////////////
101 TEST_CASE( "Approximate comparisons with ints", "[Approx]" ) {
102     REQUIRE( 1 == Approx( 1 ) );
103     REQUIRE( 0 == Approx( 0 ) );
104 }
105 
106 ///////////////////////////////////////////////////////////////////////////////
107 TEST_CASE( "Approximate comparisons with mixed numeric types", "[Approx]" ) {
108     const double dZero = 0;
109     const double dSmall = 0.00001;
110     const double dMedium = 1.234;
111 
112     REQUIRE( 1.0f == Approx( 1 ) );
113     REQUIRE( 0 == Approx( dZero) );
114     REQUIRE( 0 == Approx( dSmall ).margin( 0.001 ) );
115     REQUIRE( 1.234f == Approx( dMedium ) );
116     REQUIRE( dMedium == Approx( 1.234f ) );
117 }
118 
119 ///////////////////////////////////////////////////////////////////////////////
120 TEST_CASE( "Use a custom approx", "[Approx][custom]" ) {
121     double d = 1.23;
122 
123     Approx approx = Approx::custom().epsilon( 0.01 );
124 
125     REQUIRE( d == approx( 1.23 ) );
126     REQUIRE( d == approx( 1.22 ) );
127     REQUIRE( d == approx( 1.24 ) );
128     REQUIRE( d != approx( 1.25 ) );
129 
130     REQUIRE( approx( d ) == 1.23 );
131     REQUIRE( approx( d ) == 1.22 );
132     REQUIRE( approx( d ) == 1.24 );
133     REQUIRE( approx( d ) != 1.25 );
134 }
135 
136 TEST_CASE( "Approximate PI", "[Approx][PI]" ) {
137     REQUIRE( divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) );
138     REQUIRE( divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) );
139 }
140 
141 ///////////////////////////////////////////////////////////////////////////////
142 
143 TEST_CASE( "Absolute margin", "[Approx]" ) {
144     REQUIRE( 104.0 != Approx(100.0) );
145     REQUIRE( 104.0 == Approx(100.0).margin(5) );
146     REQUIRE( 104.0 == Approx(100.0).margin(4) );
147     REQUIRE( 104.0 != Approx(100.0).margin(3) );
148     REQUIRE( 100.3 != Approx(100.0) );
149     REQUIRE( 100.3 == Approx(100.0).margin(0.5) );
150 }
151 
152 TEST_CASE("Approx with exactly-representable margin", "[Approx]") {
153     CHECK( 0.25f == Approx(0.0f).margin(0.25f) );
154 
155     CHECK( 0.0f == Approx(0.25f).margin(0.25f) );
156     CHECK( 0.5f == Approx(0.25f).margin(0.25f) );
157 
158     CHECK( 245.0f == Approx(245.25f).margin(0.25f) );
159     CHECK( 245.5f == Approx(245.25f).margin(0.25f) );
160 }
161 
162 TEST_CASE("Approx setters validate their arguments", "[Approx]") {
163     REQUIRE_NOTHROW(Approx(0).margin(0));
164     REQUIRE_NOTHROW(Approx(0).margin(1234656));
165 
166     REQUIRE_THROWS_AS(Approx(0).margin(-2), std::domain_error);
167 
168     REQUIRE_NOTHROW(Approx(0).epsilon(0));
169     REQUIRE_NOTHROW(Approx(0).epsilon(1));
170 
171     REQUIRE_THROWS_AS(Approx(0).epsilon(-0.001), std::domain_error);
172     REQUIRE_THROWS_AS(Approx(0).epsilon(1.0001), std::domain_error);
173 }
174 
175 TEST_CASE("Default scale is invisible to comparison", "[Approx]") {
176     REQUIRE(101.000001 != Approx(100).epsilon(0.01));
177     REQUIRE(std::pow(10, -5) != Approx(std::pow(10, -7)));
178 }
179 
180 TEST_CASE("Epsilon only applies to Approx's value", "[Approx]") {
181     REQUIRE(101.01 != Approx(100).epsilon(0.01));
182 }
183 
184 TEST_CASE("Assorted miscellaneous tests", "[Approx][approvals]") {
185     REQUIRE(INFINITY == Approx(INFINITY));
186     REQUIRE(-INFINITY != Approx(INFINITY));
187     REQUIRE(1 != Approx(INFINITY));
188     REQUIRE(INFINITY != Approx(1));
189     REQUIRE(NAN != Approx(NAN));
190     REQUIRE_FALSE(NAN == Approx(NAN));
191 }
192 
193 TEST_CASE( "Comparison with explicitly convertible types", "[Approx]" )
194 {
195   StrongDoubleTypedef td(10.0);
196 
197   REQUIRE(td == Approx(10.0));
198   REQUIRE(Approx(10.0) == td);
199 
200   REQUIRE(td != Approx(11.0));
201   REQUIRE(Approx(11.0) != td);
202 
203   REQUIRE(td <= Approx(10.0));
204   REQUIRE(td <= Approx(11.0));
205   REQUIRE(Approx(10.0) <= td);
206   REQUIRE(Approx(9.0) <= td);
207 
208   REQUIRE(td >= Approx(9.0));
209   REQUIRE(td >= Approx(td));
210   REQUIRE(Approx(td) >= td);
211   REQUIRE(Approx(11.0) >= td);
212 
213 }
214 
215 }} // namespace ApproxTests
216