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

/*****************************************************************************
*
* CLIPP - command line interfaces for modern C++
*
* released under MIT license
*
* (c) 2017-2018 André Müller; foss@andremueller-online.de
*
*****************************************************************************/
#include <cmath>
#include "testing.h"
//-------------------------------------------------------------------
#if defined(_MSC_VER)
#if _MSC_VER < 1800
namespace std {
template <typename T>
bool isinf(const T &x) { return !_finite(x); }
}
#endif
#endif
//-------------------------------------------------------------------
template<class T, bool = std::is_arithmetic<T>::value,
bool = std::is_floating_point<T>::value>
struct equals {
static bool result(const T& a, const T&b) {
return a == b;
}
};
template<class T>
struct equals<T,true,false> {
static bool result(const T& a, const T&b) {
#if defined(_MSC_VER)
bool ainf = a == std::numeric_limits<T>::infinity();
bool binf = b == std::numeric_limits<T>::infinity();
if(ainf && binf) return true;
if(ainf || binf) return false;
#else
if(std::isinf(a) && std::isinf(b)) return true;
if(std::isinf(a) || std::isinf(b)) return false;
#endif
return a == b;
}
};
template<class T>
struct equals<T,true,true> {
static bool result(const T& a, const T&b) {
if(std::isinf(a) && std::isinf(b)) return true;
if(std::isinf(a) || std::isinf(b)) return false;
return std::abs(a-b) < T(1e-4);
}
};
//-------------------------------------------------------------------
template<class T>
void test(int lineNo, T x, const std::string& arg, T expected)
{
using namespace clipp;
auto cli = group( value("", x) );
// std::cout << lineNo << " " << x << " '" << arg << "' " << expected;
run_test({ __FILE__, lineNo }, {arg.c_str()}, cli, [&]{
// std::cout << " -> " << x << std::endl;
return equals<T>::result(x,expected); } );
}
//-------------------------------------------------------------------
template<class T>
void test_conv(int lineNo)
{
test<T>(lineNo, T(0), "0", T(0) );
test<T>(lineNo, T(0), "1", T(1) );
test<T>(lineNo, T(0), "2", T(2) );
test<T>(lineNo, T(0), "66", T(66) );
test<T>(lineNo, T(0), " 0 ", T(0) );
test<T>(lineNo, T(0), " 1 ", T(1) );
test<T>(lineNo, T(0), " 2 ", T(2) );
test<T>(lineNo, T(0), " 66 ", T(66) );
constexpr auto maxv = std::numeric_limits<T>::max();
test<T>(lineNo, T(0), std::to_string(maxv), maxv);
test<T>(lineNo, T(0), " " + std::to_string(maxv) + " ", maxv);
if(std::is_signed<T>::value) {
constexpr auto minv = std::numeric_limits<T>::lowest();
test<T>(lineNo, T(0), std::to_string(minv), minv);
test<T>(lineNo, T(0), " " + std::to_string(minv) + " ", minv);
}
else {
test<T>(lineNo, T(0), "-1", T(0) );
test<T>(lineNo, T(0), " -1 ", T(0) );
}
}
//-------------------------------------------------------------------
template<class T, class Wide, bool = (sizeof(Wide) > sizeof(T))>
struct test_clamp {
static void in(int lineNo) {
constexpr auto maxv = std::numeric_limits<T>::max();
test<T>(lineNo, T(0), std::to_string(maxv), maxv);
test<T>(lineNo, T(0), " " + std::to_string(maxv) + " ", maxv);
test<T>(lineNo, T(0), std::to_string(Wide(maxv)+1), maxv);
test<T>(lineNo, T(0), " " + std::to_string(Wide(maxv)+1) + " ", maxv);
if(std::is_signed<T>::value) {
constexpr auto minv = std::numeric_limits<T>::lowest();
test<T>(lineNo, T(0), std::to_string(Wide(minv)-1), minv);
test<T>(lineNo, T(0), " " + std::to_string(Wide(minv)-1) + " ", minv);
}
}
};
template<class T, class Wide>
struct test_clamp<T,Wide,false> {
static void in(int) {}
};
//-------------------------------------------------------------------
int main()
{
try {
test<bool>(__LINE__, false, "", false);
test<bool>(__LINE__, false, " ", true);
test<bool>(__LINE__, false, "0", true);
test<bool>(__LINE__, false, "1", true);
test<bool>(__LINE__, false, "a", true);
test_conv<unsigned char>( __LINE__ );
test_conv<unsigned short int>( __LINE__ );
test_conv<unsigned int>( __LINE__ );
test_conv<unsigned long int>( __LINE__ );
test_conv<unsigned long long int>( __LINE__ );
test_conv<short int>( __LINE__ );
test_conv<int>( __LINE__ );
test_conv<long int>( __LINE__ );
test_conv<long long int>( __LINE__ );
test_conv<float>( __LINE__ );
test_conv<double>( __LINE__ );
test_conv<long double>( __LINE__ );
test<char>(__LINE__, 0, "", 0);
test<char>(__LINE__, 0, " ", ' ');
test<char>(__LINE__, 0, "0", '0');
test<char>(__LINE__, 0, "1", '1');
test<char>(__LINE__, 0, "a", 'a');
test<char>(__LINE__, 0, "11", 11);
test<char>(__LINE__, 0, "65", 65);
test<char>(__LINE__, 0, "127", 127);
test<char>(__LINE__, 0, "128", 127);
test<char>(__LINE__, 0, "-1", -1);
test<char>(__LINE__, 0, "-128", -128);
test<char>(__LINE__, 0, "-129", -128);
test<std::string>(__LINE__, "", "", "");
test<std::string>(__LINE__, "", " ", " ");
test<std::string>(__LINE__, "", "0", "0");
test<std::string>(__LINE__, "", "1", "1");
test<std::string>(__LINE__, "", "a", "a");
test<std::string>(__LINE__, "", "ab", "ab");
test<std::string>(__LINE__, "", "abc", "abc");
using wide_ui_t = unsigned long long int;
test_clamp<unsigned char,wide_ui_t>::in( __LINE__ );
test_clamp<unsigned short int,wide_ui_t>::in( __LINE__ );
test_clamp<unsigned int,wide_ui_t>::in( __LINE__ );
test_clamp<unsigned long int,wide_ui_t>::in( __LINE__ );
test_clamp<unsigned long long int,wide_ui_t>::in( __LINE__ );
using wide_i_t = long long int;
test_clamp<char,wide_i_t>::in(__LINE__);
test_clamp<short int,wide_i_t>::in( __LINE__ );
test_clamp<int,wide_i_t>::in( __LINE__ );
test_clamp<long int,wide_i_t>::in( __LINE__ );
test_clamp<long long int,wide_i_t>::in( __LINE__ );
}
catch(std::exception& e) {
std::cerr << e.what() << std::endl;
return 1;
}
}