mirror of
				https://github.com/red0124/ssp.git
				synced 2025-11-04 14:46:45 +01:00 
			
		
		
		
	add unit tests for conversion without the fast float library
This commit is contained in:
		
							parent
							
								
									d328f7d59d
								
							
						
					
					
						commit
						c214975ca0
					
				@ -2,7 +2,6 @@
 | 
			
		||||
 | 
			
		||||
#include "type_traits.hpp"
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <fast_float/fast_float.h>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <optional>
 | 
			
		||||
@ -11,13 +10,18 @@
 | 
			
		||||
#include <string_view>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
#ifndef SSP_DISABLE_FAST_FLOAT
 | 
			
		||||
#include <fast_float/fast_float.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <charconv>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace ss {
 | 
			
		||||
 | 
			
		||||
////////////////
 | 
			
		||||
// number converters
 | 
			
		||||
////////////////
 | 
			
		||||
 | 
			
		||||
#define SSP_DISABLE_FAST_FLOAT
 | 
			
		||||
#ifndef SSP_DISABLE_FAST_FLOAT
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
@ -38,20 +42,11 @@ template <typename T>
 | 
			
		||||
std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
 | 
			
		||||
    const char* const begin, const char* const end) {
 | 
			
		||||
    T ret;
 | 
			
		||||
    try {
 | 
			
		||||
        if constexpr (std::is_same_v<T, float>) {
 | 
			
		||||
            ret = std::stof(std::string{begin, end});
 | 
			
		||||
        }
 | 
			
		||||
        if constexpr (std::is_same_v<T, double>) {
 | 
			
		||||
            ret = std::stod(std::string{begin, end});
 | 
			
		||||
        }
 | 
			
		||||
        if constexpr (std::is_same_v<T, long double>) {
 | 
			
		||||
            ret = std::stold(std::string{begin, end});
 | 
			
		||||
        }
 | 
			
		||||
    } catch (...) {
 | 
			
		||||
    auto [ptr, ec] = std::from_chars(begin, end, ret);
 | 
			
		||||
 | 
			
		||||
    if (ec != std::errc() || ptr != end) {
 | 
			
		||||
        return std::nullopt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ test_sources = files([
 | 
			
		||||
      'test_converter.cpp',
 | 
			
		||||
      'test_parser.cpp',
 | 
			
		||||
      'test_extractions.cpp',
 | 
			
		||||
      'test_extractions_without_fast_float.cpp',
 | 
			
		||||
      ])
 | 
			
		||||
 | 
			
		||||
doctest_proj = subproject('doctest')
 | 
			
		||||
 | 
			
		||||
@ -2,23 +2,6 @@
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <ss/extract.hpp>
 | 
			
		||||
 | 
			
		||||
#define CHECK_FLOATING_CONVERSION(input, type)                                 \
 | 
			
		||||
    {                                                                          \
 | 
			
		||||
        auto eps = std::numeric_limits<type>::min();                           \
 | 
			
		||||
        std::string s = #input;                                                \
 | 
			
		||||
        auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size());            \
 | 
			
		||||
        REQUIRE(t.has_value());                                                \
 | 
			
		||||
        CHECK_LT(std::abs(t.value() - type(input)), eps);                      \
 | 
			
		||||
    }                                                                          \
 | 
			
		||||
    {                                                                          \
 | 
			
		||||
        /* check negative too */                                               \
 | 
			
		||||
        auto eps = std::numeric_limits<type>::min();                           \
 | 
			
		||||
        auto s = std::string("-") + #input;                                    \
 | 
			
		||||
        auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size());            \
 | 
			
		||||
        REQUIRE(t.has_value());                                                \
 | 
			
		||||
        CHECK_LT(std::abs(t.value() - type(-input)), eps);                     \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
TEST_CASE("testing extract functions for floating point values") {
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(123.456, float);
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(123.456, double);
 | 
			
		||||
@ -70,13 +53,6 @@ TEST_CASE("extract test functions for decimal values") {
 | 
			
		||||
    CHECK_DECIMAL_CONVERSION(1234567891011, ull);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define CHECK_INVALID_CONVERSION(input, type)                                  \
 | 
			
		||||
    {                                                                          \
 | 
			
		||||
        std::string s = input;                                                 \
 | 
			
		||||
        auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size());            \
 | 
			
		||||
        CHECK_FALSE(t.has_value());                                            \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
TEST_CASE("extract test functions for numbers with invalid inputs") {
 | 
			
		||||
    // negative unsigned value
 | 
			
		||||
    CHECK_INVALID_CONVERSION("-1234", ul);
 | 
			
		||||
@ -200,15 +176,6 @@ TEST_CASE("extract test functions for std::optional") {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define REQUIRE_VARIANT(var, el, type)                                         \
 | 
			
		||||
    {                                                                          \
 | 
			
		||||
        auto ptr = std::get_if<type>(&var);                                    \
 | 
			
		||||
        REQUIRE(ptr);                                                          \
 | 
			
		||||
        REQUIRE_EQ(el, *ptr);                                                  \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define CHECK_NOT_VARIANT(var, type) CHECK(!std::holds_alternative<type>(var));
 | 
			
		||||
 | 
			
		||||
TEST_CASE("extract test functions for std::variant") {
 | 
			
		||||
    {
 | 
			
		||||
        std::string s = "22";
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										132
									
								
								test/test_extractions_without_fast_float.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								test/test_extractions_without_fast_float.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,132 @@
 | 
			
		||||
#include "test_helpers.hpp"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
#define SSP_DISABLE_FAST_FLOAT
 | 
			
		||||
#include <ss/extract.hpp>
 | 
			
		||||
 | 
			
		||||
TEST_CASE(
 | 
			
		||||
    "testing extract functions for floating point values without fast float") {
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(123.456, float);
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(123.456, double);
 | 
			
		||||
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(69, float);
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(69, double);
 | 
			
		||||
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(420., float);
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(420., double);
 | 
			
		||||
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(0.123, float);
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(0.123, double);
 | 
			
		||||
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(123e4, float);
 | 
			
		||||
    CHECK_FLOATING_CONVERSION(123e4, double);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("extract test functions for numbers with invalid inputs without fast "
 | 
			
		||||
          "float") {
 | 
			
		||||
    // floating pint for int
 | 
			
		||||
    CHECK_INVALID_CONVERSION("123.4", int);
 | 
			
		||||
 | 
			
		||||
    // random input for float
 | 
			
		||||
    CHECK_INVALID_CONVERSION("xxx1", float);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("extract test functions for std::variant without fast float") {
 | 
			
		||||
    {
 | 
			
		||||
        std::string s = "22";
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<int, double, std::string> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, double);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, std::string);
 | 
			
		||||
            REQUIRE_VARIANT(var, 22, int);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<double, int, std::string> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, std::string);
 | 
			
		||||
            REQUIRE_VARIANT(var, 22, double);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<std::string, double, int> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, double);
 | 
			
		||||
            REQUIRE_VARIANT(var, "22", std::string);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<int> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            REQUIRE_VARIANT(var, 22, int);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        std::string s = "22.2";
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<int, double, std::string> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, std::string);
 | 
			
		||||
            REQUIRE_VARIANT(var, 22.2, double);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<double, int, std::string> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, std::string);
 | 
			
		||||
            REQUIRE_VARIANT(var, 22.2, double);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<std::string, double, int> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, double);
 | 
			
		||||
            REQUIRE_VARIANT(var, "22.2", std::string);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        std::string s = "2.2.2";
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<int, double, std::string> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, double);
 | 
			
		||||
            REQUIRE_VARIANT(var, "2.2.2", std::string);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<double, std::string, int> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, double);
 | 
			
		||||
            REQUIRE_VARIANT(var, "2.2.2", std::string);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<std::string, double, int> var;
 | 
			
		||||
            REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, double);
 | 
			
		||||
            REQUIRE_VARIANT(var, "2.2.2", std::string);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<int, double> var;
 | 
			
		||||
            REQUIRE_FALSE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
 | 
			
		||||
            REQUIRE_VARIANT(var, int{}, int);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, double);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<double, int> var;
 | 
			
		||||
            REQUIRE_FALSE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
 | 
			
		||||
            REQUIRE_VARIANT(var, double{}, double);
 | 
			
		||||
            CHECK_NOT_VARIANT(var, int);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            std::variant<int> var;
 | 
			
		||||
            REQUIRE_FALSE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
 | 
			
		||||
 | 
			
		||||
            REQUIRE_VARIANT(var, int{}, int);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -46,3 +46,36 @@ struct buffer {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
[[maybe_unused]] inline buffer buff;
 | 
			
		||||
 | 
			
		||||
#define CHECK_FLOATING_CONVERSION(input, type)                                 \
 | 
			
		||||
    {                                                                          \
 | 
			
		||||
        auto eps = std::numeric_limits<type>::min();                           \
 | 
			
		||||
        std::string s = #input;                                                \
 | 
			
		||||
        auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size());            \
 | 
			
		||||
        REQUIRE(t.has_value());                                                \
 | 
			
		||||
        CHECK_LT(std::abs(t.value() - type(input)), eps);                      \
 | 
			
		||||
    }                                                                          \
 | 
			
		||||
    {                                                                          \
 | 
			
		||||
        /* check negative too */                                               \
 | 
			
		||||
        auto eps = std::numeric_limits<type>::min();                           \
 | 
			
		||||
        auto s = std::string("-") + #input;                                    \
 | 
			
		||||
        auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size());            \
 | 
			
		||||
        REQUIRE(t.has_value());                                                \
 | 
			
		||||
        CHECK_LT(std::abs(t.value() - type(-input)), eps);                     \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define CHECK_INVALID_CONVERSION(input, type)                                  \
 | 
			
		||||
    {                                                                          \
 | 
			
		||||
        std::string s = input;                                                 \
 | 
			
		||||
        auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size());            \
 | 
			
		||||
        CHECK_FALSE(t.has_value());                                            \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define REQUIRE_VARIANT(var, el, type)                                         \
 | 
			
		||||
    {                                                                          \
 | 
			
		||||
        auto ptr = std::get_if<type>(&var);                                    \
 | 
			
		||||
        REQUIRE(ptr);                                                          \
 | 
			
		||||
        REQUIRE_EQ(el, *ptr);                                                  \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define CHECK_NOT_VARIANT(var, type) CHECK(!std::holds_alternative<type>(var));
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user