You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
6.4 KiB

2 years ago
  1. /*****************************************************************************
  2. *
  3. * CLIPP - command line interfaces for modern C++
  4. *
  5. * released under MIT license
  6. *
  7. * (c) 2017-2018 André Müller; foss@andremueller-online.de
  8. *
  9. *****************************************************************************/
  10. #include <cmath>
  11. #include "testing.h"
  12. //-------------------------------------------------------------------
  13. #if defined(_MSC_VER)
  14. #if _MSC_VER < 1800
  15. namespace std {
  16. template <typename T>
  17. bool isinf(const T &x) { return !_finite(x); }
  18. }
  19. #endif
  20. #endif
  21. //-------------------------------------------------------------------
  22. template<class T, bool = std::is_arithmetic<T>::value,
  23. bool = std::is_floating_point<T>::value>
  24. struct equals {
  25. static bool result(const T& a, const T&b) {
  26. return a == b;
  27. }
  28. };
  29. template<class T>
  30. struct equals<T,true,false> {
  31. static bool result(const T& a, const T&b) {
  32. #if defined(_MSC_VER)
  33. bool ainf = a == std::numeric_limits<T>::infinity();
  34. bool binf = b == std::numeric_limits<T>::infinity();
  35. if(ainf && binf) return true;
  36. if(ainf || binf) return false;
  37. #else
  38. if(std::isinf(a) && std::isinf(b)) return true;
  39. if(std::isinf(a) || std::isinf(b)) return false;
  40. #endif
  41. return a == b;
  42. }
  43. };
  44. template<class T>
  45. struct equals<T,true,true> {
  46. static bool result(const T& a, const T&b) {
  47. if(std::isinf(a) && std::isinf(b)) return true;
  48. if(std::isinf(a) || std::isinf(b)) return false;
  49. return std::abs(a-b) < T(1e-4);
  50. }
  51. };
  52. //-------------------------------------------------------------------
  53. template<class T>
  54. void test(int lineNo, T x, const std::string& arg, T expected)
  55. {
  56. using namespace clipp;
  57. auto cli = group( value("", x) );
  58. // std::cout << lineNo << " " << x << " '" << arg << "' " << expected;
  59. run_test({ __FILE__, lineNo }, {arg.c_str()}, cli, [&]{
  60. // std::cout << " -> " << x << std::endl;
  61. return equals<T>::result(x,expected); } );
  62. }
  63. //-------------------------------------------------------------------
  64. template<class T>
  65. void test_conv(int lineNo)
  66. {
  67. test<T>(lineNo, T(0), "0", T(0) );
  68. test<T>(lineNo, T(0), "1", T(1) );
  69. test<T>(lineNo, T(0), "2", T(2) );
  70. test<T>(lineNo, T(0), "66", T(66) );
  71. test<T>(lineNo, T(0), " 0 ", T(0) );
  72. test<T>(lineNo, T(0), " 1 ", T(1) );
  73. test<T>(lineNo, T(0), " 2 ", T(2) );
  74. test<T>(lineNo, T(0), " 66 ", T(66) );
  75. constexpr auto maxv = std::numeric_limits<T>::max();
  76. test<T>(lineNo, T(0), std::to_string(maxv), maxv);
  77. test<T>(lineNo, T(0), " " + std::to_string(maxv) + " ", maxv);
  78. if(std::is_signed<T>::value) {
  79. constexpr auto minv = std::numeric_limits<T>::lowest();
  80. test<T>(lineNo, T(0), std::to_string(minv), minv);
  81. test<T>(lineNo, T(0), " " + std::to_string(minv) + " ", minv);
  82. }
  83. else {
  84. test<T>(lineNo, T(0), "-1", T(0) );
  85. test<T>(lineNo, T(0), " -1 ", T(0) );
  86. }
  87. }
  88. //-------------------------------------------------------------------
  89. template<class T, class Wide, bool = (sizeof(Wide) > sizeof(T))>
  90. struct test_clamp {
  91. static void in(int lineNo) {
  92. constexpr auto maxv = std::numeric_limits<T>::max();
  93. test<T>(lineNo, T(0), std::to_string(maxv), maxv);
  94. test<T>(lineNo, T(0), " " + std::to_string(maxv) + " ", maxv);
  95. test<T>(lineNo, T(0), std::to_string(Wide(maxv)+1), maxv);
  96. test<T>(lineNo, T(0), " " + std::to_string(Wide(maxv)+1) + " ", maxv);
  97. if(std::is_signed<T>::value) {
  98. constexpr auto minv = std::numeric_limits<T>::lowest();
  99. test<T>(lineNo, T(0), std::to_string(Wide(minv)-1), minv);
  100. test<T>(lineNo, T(0), " " + std::to_string(Wide(minv)-1) + " ", minv);
  101. }
  102. }
  103. };
  104. template<class T, class Wide>
  105. struct test_clamp<T,Wide,false> {
  106. static void in(int) {}
  107. };
  108. //-------------------------------------------------------------------
  109. int main()
  110. {
  111. try {
  112. test<bool>(__LINE__, false, "", false);
  113. test<bool>(__LINE__, false, " ", true);
  114. test<bool>(__LINE__, false, "0", true);
  115. test<bool>(__LINE__, false, "1", true);
  116. test<bool>(__LINE__, false, "a", true);
  117. test_conv<unsigned char>( __LINE__ );
  118. test_conv<unsigned short int>( __LINE__ );
  119. test_conv<unsigned int>( __LINE__ );
  120. test_conv<unsigned long int>( __LINE__ );
  121. test_conv<unsigned long long int>( __LINE__ );
  122. test_conv<short int>( __LINE__ );
  123. test_conv<int>( __LINE__ );
  124. test_conv<long int>( __LINE__ );
  125. test_conv<long long int>( __LINE__ );
  126. test_conv<float>( __LINE__ );
  127. test_conv<double>( __LINE__ );
  128. test_conv<long double>( __LINE__ );
  129. test<char>(__LINE__, 0, "", 0);
  130. test<char>(__LINE__, 0, " ", ' ');
  131. test<char>(__LINE__, 0, "0", '0');
  132. test<char>(__LINE__, 0, "1", '1');
  133. test<char>(__LINE__, 0, "a", 'a');
  134. test<char>(__LINE__, 0, "11", 11);
  135. test<char>(__LINE__, 0, "65", 65);
  136. test<char>(__LINE__, 0, "127", 127);
  137. test<char>(__LINE__, 0, "128", 127);
  138. test<char>(__LINE__, 0, "-1", -1);
  139. test<char>(__LINE__, 0, "-128", -128);
  140. test<char>(__LINE__, 0, "-129", -128);
  141. test<std::string>(__LINE__, "", "", "");
  142. test<std::string>(__LINE__, "", " ", " ");
  143. test<std::string>(__LINE__, "", "0", "0");
  144. test<std::string>(__LINE__, "", "1", "1");
  145. test<std::string>(__LINE__, "", "a", "a");
  146. test<std::string>(__LINE__, "", "ab", "ab");
  147. test<std::string>(__LINE__, "", "abc", "abc");
  148. using wide_ui_t = unsigned long long int;
  149. test_clamp<unsigned char,wide_ui_t>::in( __LINE__ );
  150. test_clamp<unsigned short int,wide_ui_t>::in( __LINE__ );
  151. test_clamp<unsigned int,wide_ui_t>::in( __LINE__ );
  152. test_clamp<unsigned long int,wide_ui_t>::in( __LINE__ );
  153. test_clamp<unsigned long long int,wide_ui_t>::in( __LINE__ );
  154. using wide_i_t = long long int;
  155. test_clamp<char,wide_i_t>::in(__LINE__);
  156. test_clamp<short int,wide_i_t>::in( __LINE__ );
  157. test_clamp<int,wide_i_t>::in( __LINE__ );
  158. test_clamp<long int,wide_i_t>::in( __LINE__ );
  159. test_clamp<long long int,wide_i_t>::in( __LINE__ );
  160. }
  161. catch(std::exception& e) {
  162. std::cerr << e.what() << std::endl;
  163. return 1;
  164. }
  165. }