#include <limits>
#include <string>
#include <clocale>

#include "catch2_common.h"

#include <tango/internal/parse.h>

template <typename T>
void test_parse_value(T value)
{
    std::string prev_locale = std::setlocale(LC_NUMERIC, nullptr);
    std::setlocale(LC_NUMERIC, "C");
    std::string buf = std::to_string(value);
    std::setlocale(LC_NUMERIC, prev_locale.c_str());

    REQUIRE_NOTHROW(parse_as<T>(buf));
}

template <typename T>
void test_parse_int()
{
    REQUIRE_THROWS(parse_as<T>(""));
    REQUIRE_THROWS(parse_as<T>("1_"));
    REQUIRE_NOTHROW(parse_as<T>("0"));
    test_parse_value<T>(std::numeric_limits<T>::min());
    test_parse_value<T>(std::numeric_limits<T>::max());
}

template <typename T>
void test_parse_float()
{
    REQUIRE_THROWS(parse_as<T>(""));
    REQUIRE_THROWS(parse_as<T>("1.1_"));
    REQUIRE_NOTHROW(parse_as<T>("0"));
    REQUIRE_NOTHROW(parse_as<T>("0.0"));
    test_parse_value<T>(std::numeric_limits<T>::min());
    test_parse_value<T>(std::numeric_limits<T>::max());
    test_parse_value<T>(std::numeric_limits<T>::min_exponent);
    test_parse_value<T>(std::numeric_limits<T>::max_exponent);
}

SCENARIO("integers and floats can be parsed")
{
    test_parse_int<int>();
    test_parse_int<unsigned int>();
    test_parse_int<long>();
    test_parse_int<unsigned long>();
    test_parse_float<double>();
}
