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 #include <stdexcept> 15 16 namespace Catch { 17 namespace Detail { 18 19 class Approx { 20 private: 21 bool equalityComparisonImpl(double other) const; 22 23 public: 24 explicit Approx ( double value ); 25 26 static Approx custom(); 27 28 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> operator()29 Approx operator()( T const& value ) { 30 Approx approx( static_cast<double>(value) ); 31 approx.epsilon( m_epsilon ); 32 approx.margin( m_margin ); 33 approx.scale( m_scale ); 34 return approx; 35 } 36 37 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> Approx(T const & value)38 explicit Approx( T const& value ): Approx(static_cast<double>(value)) 39 {} 40 41 42 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 43 friend bool operator == ( const T& lhs, Approx const& rhs ) { 44 auto lhs_v = static_cast<double>(lhs); 45 return rhs.equalityComparisonImpl(lhs_v); 46 } 47 48 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 49 friend bool operator == ( Approx const& lhs, const T& rhs ) { 50 return operator==( rhs, lhs ); 51 } 52 53 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 54 friend bool operator != ( T const& lhs, Approx const& rhs ) { 55 return !operator==( lhs, rhs ); 56 } 57 58 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 59 friend bool operator != ( Approx const& lhs, T const& rhs ) { 60 return !operator==( rhs, lhs ); 61 } 62 63 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 64 friend bool operator <= ( T const& lhs, Approx const& rhs ) { 65 return static_cast<double>(lhs) < rhs.m_value || lhs == rhs; 66 } 67 68 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 69 friend bool operator <= ( Approx const& lhs, T const& rhs ) { 70 return lhs.m_value < static_cast<double>(rhs) || lhs == rhs; 71 } 72 73 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 74 friend bool operator >= ( T const& lhs, Approx const& rhs ) { 75 return static_cast<double>(lhs) > rhs.m_value || lhs == rhs; 76 } 77 78 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 79 friend bool operator >= ( Approx const& lhs, T const& rhs ) { 80 return lhs.m_value > static_cast<double>(rhs) || lhs == rhs; 81 } 82 83 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> epsilon(T const & newEpsilon)84 Approx& epsilon( T const& newEpsilon ) { 85 double epsilonAsDouble = static_cast<double>(newEpsilon); 86 if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) { 87 throw std::domain_error 88 ( "Invalid Approx::epsilon: " + 89 Catch::Detail::stringify( epsilonAsDouble ) + 90 ", Approx::epsilon has to be between 0 and 1" ); 91 } 92 m_epsilon = epsilonAsDouble; 93 return *this; 94 } 95 96 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> margin(T const & newMargin)97 Approx& margin( T const& newMargin ) { 98 double marginAsDouble = static_cast<double>(newMargin); 99 if( marginAsDouble < 0 ) { 100 throw std::domain_error 101 ( "Invalid Approx::margin: " + 102 Catch::Detail::stringify( marginAsDouble ) + 103 ", Approx::Margin has to be non-negative." ); 104 105 } 106 m_margin = marginAsDouble; 107 return *this; 108 } 109 110 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> scale(T const & newScale)111 Approx& scale( T const& newScale ) { 112 m_scale = static_cast<double>(newScale); 113 return *this; 114 } 115 116 std::string toString() const; 117 118 private: 119 double m_epsilon; 120 double m_margin; 121 double m_scale; 122 double m_value; 123 }; 124 } 125 126 template<> 127 struct StringMaker<Catch::Detail::Approx> { 128 static std::string convert(Catch::Detail::Approx const& value); 129 }; 130 131 } // end namespace Catch 132 133 #endif // TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED 134