1 /*
2  *  Created by Phil on 28/04/2011.
3  *  Copyright 2010 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 #ifndef TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
9 #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
10 
11 #include "catch_tostring.h"
12 
13 #include <type_traits>
14 
15 namespace Catch {
16 namespace Detail {
17 
18     class Approx {
19     private:
20         bool equalityComparisonImpl(double other) const;
21         // Validates the new margin (margin >= 0)
22         // out-of-line to avoid including stdexcept in the header
23         void setMargin(double margin);
24         // Validates the new epsilon (0 < epsilon < 1)
25         // out-of-line to avoid including stdexcept in the header
26         void setEpsilon(double epsilon);
27 
28     public:
29         explicit Approx ( double value );
30 
31         static Approx custom();
32 
33         Approx operator-() const;
34 
35         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator()36         Approx operator()( T const& value ) {
37             Approx approx( static_cast<double>(value) );
38             approx.m_epsilon = m_epsilon;
39             approx.m_margin = m_margin;
40             approx.m_scale = m_scale;
41             return approx;
42         }
43 
44         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx(T const & value)45         explicit Approx( T const& value ): Approx(static_cast<double>(value))
46         {}
47 
48 
49         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
50         friend bool operator == ( const T& lhs, Approx const& rhs ) {
51             auto lhs_v = static_cast<double>(lhs);
52             return rhs.equalityComparisonImpl(lhs_v);
53         }
54 
55         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
56         friend bool operator == ( Approx const& lhs, const T& rhs ) {
57             return operator==( rhs, lhs );
58         }
59 
60         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
61         friend bool operator != ( T const& lhs, Approx const& rhs ) {
62             return !operator==( lhs, rhs );
63         }
64 
65         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
66         friend bool operator != ( Approx const& lhs, T const& rhs ) {
67             return !operator==( rhs, lhs );
68         }
69 
70         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
71         friend bool operator <= ( T const& lhs, Approx const& rhs ) {
72             return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
73         }
74 
75         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
76         friend bool operator <= ( Approx const& lhs, T const& rhs ) {
77             return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
78         }
79 
80         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
81         friend bool operator >= ( T const& lhs, Approx const& rhs ) {
82             return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
83         }
84 
85         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
86         friend bool operator >= ( Approx const& lhs, T const& rhs ) {
87             return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
88         }
89 
90         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
epsilon(T const & newEpsilon)91         Approx& epsilon( T const& newEpsilon ) {
92             double epsilonAsDouble = static_cast<double>(newEpsilon);
93             setEpsilon(epsilonAsDouble);
94             return *this;
95         }
96 
97         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
margin(T const & newMargin)98         Approx& margin( T const& newMargin ) {
99             double marginAsDouble = static_cast<double>(newMargin);
100             setMargin(marginAsDouble);
101             return *this;
102         }
103 
104         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
scale(T const & newScale)105         Approx& scale( T const& newScale ) {
106             m_scale = static_cast<double>(newScale);
107             return *this;
108         }
109 
110         std::string toString() const;
111 
112     private:
113         double m_epsilon;
114         double m_margin;
115         double m_scale;
116         double m_value;
117     };
118 } // end namespace Detail
119 
120 namespace literals {
121     Detail::Approx operator "" _a(long double val);
122     Detail::Approx operator "" _a(unsigned long long val);
123 } // end namespace literals
124 
125 template<>
126 struct StringMaker<Catch::Detail::Approx> {
127     static std::string convert(Catch::Detail::Approx const& value);
128 };
129 
130 } // end namespace Catch
131 
132 #endif // TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
133