catch_decomposer.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * Created by Phil Nash on 8/8/2017.
  3. * Copyright 2017 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_DECOMPOSER_H_INCLUDED
  9. #define TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED
  10. #include "catch_tostring.h"
  11. #include "catch_stringref.h"
  12. #include "catch_meta.hpp"
  13. #include <iosfwd>
  14. #ifdef _MSC_VER
  15. #pragma warning(push)
  16. #pragma warning(disable:4389) // '==' : signed/unsigned mismatch
  17. #pragma warning(disable:4018) // more "signed/unsigned mismatch"
  18. #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
  19. #pragma warning(disable:4180) // qualifier applied to function type has no meaning
  20. #pragma warning(disable:4800) // Forcing result to true or false
  21. #endif
  22. namespace Catch {
  23. struct ITransientExpression {
  24. auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
  25. auto getResult() const -> bool { return m_result; }
  26. virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
  27. ITransientExpression( bool isBinaryExpression, bool result )
  28. : m_isBinaryExpression( isBinaryExpression ),
  29. m_result( result )
  30. {}
  31. // We don't actually need a virtual destructor, but many static analysers
  32. // complain if it's not here :-(
  33. virtual ~ITransientExpression();
  34. bool m_isBinaryExpression;
  35. bool m_result;
  36. };
  37. void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
  38. template<typename LhsT, typename RhsT>
  39. class BinaryExpr : public ITransientExpression {
  40. LhsT m_lhs;
  41. StringRef m_op;
  42. RhsT m_rhs;
  43. void streamReconstructedExpression( std::ostream &os ) const override {
  44. formatReconstructedExpression
  45. ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
  46. }
  47. public:
  48. BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
  49. : ITransientExpression{ true, comparisonResult },
  50. m_lhs( lhs ),
  51. m_op( op ),
  52. m_rhs( rhs )
  53. {}
  54. template<typename T>
  55. auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
  56. static_assert(always_false<T>::value,
  57. "chained comparisons are not supported inside assertions, "
  58. "wrap the expression inside parentheses, or decompose it");
  59. }
  60. template<typename T>
  61. auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
  62. static_assert(always_false<T>::value,
  63. "chained comparisons are not supported inside assertions, "
  64. "wrap the expression inside parentheses, or decompose it");
  65. }
  66. template<typename T>
  67. auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
  68. static_assert(always_false<T>::value,
  69. "chained comparisons are not supported inside assertions, "
  70. "wrap the expression inside parentheses, or decompose it");
  71. }
  72. template<typename T>
  73. auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
  74. static_assert(always_false<T>::value,
  75. "chained comparisons are not supported inside assertions, "
  76. "wrap the expression inside parentheses, or decompose it");
  77. }
  78. template<typename T>
  79. auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
  80. static_assert(always_false<T>::value,
  81. "chained comparisons are not supported inside assertions, "
  82. "wrap the expression inside parentheses, or decompose it");
  83. }
  84. template<typename T>
  85. auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
  86. static_assert(always_false<T>::value,
  87. "chained comparisons are not supported inside assertions, "
  88. "wrap the expression inside parentheses, or decompose it");
  89. }
  90. template<typename T>
  91. auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
  92. static_assert(always_false<T>::value,
  93. "chained comparisons are not supported inside assertions, "
  94. "wrap the expression inside parentheses, or decompose it");
  95. }
  96. template<typename T>
  97. auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
  98. static_assert(always_false<T>::value,
  99. "chained comparisons are not supported inside assertions, "
  100. "wrap the expression inside parentheses, or decompose it");
  101. }
  102. };
  103. template<typename LhsT>
  104. class UnaryExpr : public ITransientExpression {
  105. LhsT m_lhs;
  106. void streamReconstructedExpression( std::ostream &os ) const override {
  107. os << Catch::Detail::stringify( m_lhs );
  108. }
  109. public:
  110. explicit UnaryExpr( LhsT lhs )
  111. : ITransientExpression{ false, static_cast<bool>(lhs) },
  112. m_lhs( lhs )
  113. {}
  114. };
  115. // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
  116. template<typename LhsT, typename RhsT>
  117. auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
  118. template<typename T>
  119. auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
  120. template<typename T>
  121. auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
  122. template<typename T>
  123. auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
  124. template<typename T>
  125. auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
  126. template<typename LhsT, typename RhsT>
  127. auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
  128. template<typename T>
  129. auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
  130. template<typename T>
  131. auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
  132. template<typename T>
  133. auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
  134. template<typename T>
  135. auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
  136. template<typename LhsT>
  137. class ExprLhs {
  138. LhsT m_lhs;
  139. public:
  140. explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
  141. template<typename RhsT>
  142. auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
  143. return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs };
  144. }
  145. auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
  146. return { m_lhs == rhs, m_lhs, "==", rhs };
  147. }
  148. template<typename RhsT>
  149. auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
  150. return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs };
  151. }
  152. auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
  153. return { m_lhs != rhs, m_lhs, "!=", rhs };
  154. }
  155. template<typename RhsT>
  156. auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
  157. return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
  158. }
  159. template<typename RhsT>
  160. auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
  161. return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
  162. }
  163. template<typename RhsT>
  164. auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
  165. return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
  166. }
  167. template<typename RhsT>
  168. auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
  169. return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
  170. }
  171. template <typename RhsT>
  172. auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
  173. return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs };
  174. }
  175. template <typename RhsT>
  176. auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
  177. return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs };
  178. }
  179. template <typename RhsT>
  180. auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
  181. return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs };
  182. }
  183. template<typename RhsT>
  184. auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
  185. static_assert(always_false<RhsT>::value,
  186. "operator&& is not supported inside assertions, "
  187. "wrap the expression inside parentheses, or decompose it");
  188. }
  189. template<typename RhsT>
  190. auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
  191. static_assert(always_false<RhsT>::value,
  192. "operator|| is not supported inside assertions, "
  193. "wrap the expression inside parentheses, or decompose it");
  194. }
  195. auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
  196. return UnaryExpr<LhsT>{ m_lhs };
  197. }
  198. };
  199. void handleExpression( ITransientExpression const& expr );
  200. template<typename T>
  201. void handleExpression( ExprLhs<T> const& expr ) {
  202. handleExpression( expr.makeUnaryExpr() );
  203. }
  204. struct Decomposer {
  205. template<typename T>
  206. auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {
  207. return ExprLhs<T const&>{ lhs };
  208. }
  209. auto operator <=( bool value ) -> ExprLhs<bool> {
  210. return ExprLhs<bool>{ value };
  211. }
  212. };
  213. } // end namespace Catch
  214. #ifdef _MSC_VER
  215. #pragma warning(pop)
  216. #endif
  217. #endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED