Merge pull request #236 from fastfloat/issue235

Verify and fix issue 235
This commit is contained in:
Daniel Lemire 2024-01-28 11:43:35 -05:00 committed by GitHub
commit a642af5235
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 177 additions and 138 deletions

16
.github/workflows/ubuntu22-sanitize.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Ubuntu 22.04 CI Sanitized (GCC 11)
on: [push, pull_request]
jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DFASTFLOAT_TEST=ON -D FASTFLOAT_SANITIZE=ON .. &&
cmake --build . &&
ctest --output-on-failure

View File

@ -27,8 +27,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
auto answer =
fast_float::from_chars(input_d.data(), input_d.data() + input_d.size(), result_d, format);
std::string input_f = fdp.ConsumeRandomLengthString(128);
double result_f = 0.0;
float result_f = 0.0;
answer =
fast_float::from_chars(input_f.data(), input_f.data() + input_f.size(), result_f, format);
int result_i = 0;
std::string input_i = fdp.ConsumeRandomLengthString(128);
answer =
fast_float::from_chars(input_i.data(), input_i.data() + input_i.size(), result_i);
return 0;
}

View File

@ -442,8 +442,7 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
template <typename T, typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value, int base)
{
from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value, int base) {
from_chars_result_t<UC> answer;
UC const* const first = p;
@ -463,9 +462,11 @@ from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value,
}
UC const* const start_num = p;
while (*p == UC('0')) {
while (p!= pend && *p == UC('0')) {
++p;
}
const bool has_leading_zeros = p > start_num;
UC const* const start_digits = p;

View File

@ -232,8 +232,7 @@ from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
template <typename T, typename UC, typename>
FASTFLOAT_CONSTEXPR20
from_chars_result_t<UC> from_chars(UC const* first, UC const* last, T& value, int base) noexcept
{
from_chars_result_t<UC> from_chars(UC const* first, UC const* last, T& value, int base) noexcept {
static_assert (is_supported_char_type<UC>(), "only char, wchar_t, char16_t and char32_t are supported");
from_chars_result_t<UC> answer;

View File

@ -10,7 +10,7 @@ option(FASTFLOAT_SUPPLEMENTAL_TESTS "Run supplemental tests" ON)
if (NOT SYSTEM_DOCTEST)
FetchContent_Declare(doctest
GIT_REPOSITORY https://github.com/onqtam/doctest.git
GIT_TAG v2.4.10)
GIT_TAG v2.4.11)
endif()
if (FASTFLOAT_SUPPLEMENTAL_TESTS)
FetchContent_Declare(supplemental_test_files
@ -81,6 +81,7 @@ fast_float_add_cpp_test(long_test)
fast_float_add_cpp_test(powersoffive_hardround)
fast_float_add_cpp_test(string_test)
fast_float_add_cpp_test(fast_int)
target_compile_features(fast_int PRIVATE cxx_std_17)
fast_float_add_cpp_test(json_fmt)
fast_float_add_cpp_test(fortran)

View File

@ -1,11 +1,33 @@
#ifndef __cplusplus
#error fastfloat requires a C++ compiler
#endif
// We want to enable the tests only for C++17 and above.
#ifndef FASTFLOAT_CPLUSPLUS
#if defined(_MSVC_LANG) && !defined(__clang__)
#define FASTFLOAT_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG)
#else
#define FASTFLOAT_CPLUSPLUS __cplusplus
#endif
#endif
#if FASTFLOAT_CPLUSPLUS >= 201703L
#include <cstdlib>
#include <iostream>
#include <vector>
#include <iomanip>
#include <string_view>
#include <cstring>
#include "fast_float/fast_float.h"
#include <cstdint>
template <class T>
std::string quoted(T& s) {
return "\""+std::string(s)+"\"";
}
/*
all tests conducted are to check fast_float::from_chars functionality with int and unsigned
test cases include:
@ -26,414 +48,391 @@ within range base tests - max/min numbers are still within int/unsigned bit size
leading zeros tests - ignores all zeroes in front of valid number after converted from base
*/
int main()
{
int main() {
// int basic test
const std::vector<int> int_basic_test_expected { 0, 10, -40, 1001, 9 };
const std::vector<std::string> int_basic_test { "0", "10 ", "-40", "1001 with text", "9.999" };
const std::vector<std::string_view> int_basic_test { "0", "10 ", "-40", "1001 with text", "9.999" };
for (std::size_t i = 0; i < int_basic_test.size(); ++i)
{
for (std::size_t i = 0; i < int_basic_test.size(); ++i) {
const auto& f = int_basic_test[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc()) {
if (answer.ec == std::errc::invalid_argument) {
std::cerr << "could not convert to int for input: " << std::quoted(f) << " because of invalid arguement" << std::endl;
std::cerr << "could not convert to int for input: " << quoted(f) << " because of invalid arguement" << std::endl;
}
else if (answer.ec == std::errc::result_out_of_range) {
std::cerr << "could not convert to int for input: " << std::quoted(f) << " because it's out of range" << std::endl;
std::cerr << "could not convert to int for input: " << quoted(f) << " because it's out of range" << std::endl;
}
else {
std::cerr << "could not convert to int for input: " << std::quoted(f) << " because of an unknown error" << std::endl;
std::cerr << "could not convert to int for input: " << quoted(f) << " because of an unknown error" << std::endl;
}
return EXIT_FAILURE;
}
else if (result != int_basic_test_expected[i]) {
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << int_basic_test_expected[i] << std::endl;
std::cerr << "result " << quoted(f) << " did not match with expected int: " << int_basic_test_expected[i] << std::endl;
return EXIT_FAILURE;
}
}
// unsigned basic test
const std::vector<unsigned> unsigned_basic_test_expected { 0, 10, 1001, 9 };
const std::vector<std::string> unsigned_basic_test { "0", "10 ", "1001 with text", "9.999" };
const std::vector<std::string_view> unsigned_basic_test { "0", "10 ", "1001 with text", "9.999" };
for (std::size_t i = 0; i < unsigned_basic_test.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_basic_test.size(); ++i) {
const auto& f = unsigned_basic_test[i];
unsigned result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc()) {
std::cerr << "could not convert to unsigned for input: " << std::quoted(f) << std::endl;
std::cerr << "could not convert to unsigned for input: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
else if (result != unsigned_basic_test_expected[i]) {
std::cerr << "result " << std::quoted(f) << " did not match with expected unsigned: " << unsigned_basic_test_expected[i] << std::endl;
std::cerr << "result " << quoted(f) << " did not match with expected unsigned: " << unsigned_basic_test_expected[i] << std::endl;
return EXIT_FAILURE;
}
}
// int invalid error test
const std::vector<std::string> int_invalid_argument_test{ "text", "text with 1002", "+50", " 50" };
const std::vector<std::string_view> int_invalid_argument_test{ "text", "text with 1002", "+50", " 50" };
for (std::size_t i = 0; i < int_invalid_argument_test.size(); ++i)
{
for (std::size_t i = 0; i < int_invalid_argument_test.size(); ++i) {
const auto& f = int_invalid_argument_test[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::invalid_argument) {
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// unsigned invalid error test
const std::vector<std::string> unsigned_invalid_argument_test{ "text", "text with 1002", "+50", " 50", "-50" };
const std::vector<std::string_view> unsigned_invalid_argument_test{ "text", "text with 1002", "+50", " 50", "-50" };
for (std::size_t i = 0; i < unsigned_invalid_argument_test.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_invalid_argument_test.size(); ++i) {
const auto& f = unsigned_invalid_argument_test[i];
unsigned result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::invalid_argument) {
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// int out of range error test #1 (8 bit)
const std::vector<std::string> int_out_of_range_test_1{ "2000000000000000000000", "128", "-129"};
const std::vector<std::string_view> int_out_of_range_test_1{ "2000000000000000000000", "128", "-129"};
for (std::size_t i = 0; i < int_out_of_range_test_1.size(); ++i)
{
for (std::size_t i = 0; i < int_out_of_range_test_1.size(); ++i) {
const auto& f = int_out_of_range_test_1[i];
int8_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// int out of range error test #2 (16 bit)
const std::vector<std::string> int_out_of_range_test_2{ "2000000000000000000000", "32768", "-32769"};
const std::vector<std::string_view> int_out_of_range_test_2{ "2000000000000000000000", "32768", "-32769"};
for (std::size_t i = 0; i < int_out_of_range_test_2.size(); ++i)
{
for (std::size_t i = 0; i < int_out_of_range_test_2.size(); ++i) {
const auto& f = int_out_of_range_test_2[i];
int16_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// int out of range error test #3 (32 bit)
const std::vector<std::string> int_out_of_range_test_3{ "2000000000000000000000", "2147483648", "-2147483649"};
const std::vector<std::string_view> int_out_of_range_test_3{ "2000000000000000000000", "2147483648", "-2147483649"};
for (std::size_t i = 0; i < int_out_of_range_test_3.size(); ++i)
{
for (std::size_t i = 0; i < int_out_of_range_test_3.size(); ++i) {
const auto& f = int_out_of_range_test_3[i];
int32_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// int out of range error test #4 (64 bit)
const std::vector<std::string> int_out_of_range_test_4{ "2000000000000000000000", "9223372036854775808", "-9223372036854775809"};
const std::vector<std::string_view> int_out_of_range_test_4{ "2000000000000000000000", "9223372036854775808", "-9223372036854775809"};
for (std::size_t i = 0; i < int_out_of_range_test_4.size(); ++i)
{
for (std::size_t i = 0; i < int_out_of_range_test_4.size(); ++i) {
const auto& f = int_out_of_range_test_4[i];
int64_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// unsigned out of range error test #1 (8 bit)
const std::vector<std::string> unsigned_out_of_range_test_1{ "2000000000000000000000", "256" };
const std::vector<std::string_view> unsigned_out_of_range_test_1{ "2000000000000000000000", "256" };
for (std::size_t i = 0; i < unsigned_out_of_range_test_1.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_out_of_range_test_1.size(); ++i) {
const auto& f = unsigned_out_of_range_test_1[i];
uint8_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// unsigned out of range error test #2 (16 bit)
const std::vector<std::string> unsigned_out_of_range_test_2{ "2000000000000000000000", "65536" };
const std::vector<std::string_view> unsigned_out_of_range_test_2{ "2000000000000000000000", "65536" };
for (std::size_t i = 0; i < unsigned_out_of_range_test_2.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_out_of_range_test_2.size(); ++i) {
const auto& f = unsigned_out_of_range_test_2[i];
uint16_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// unsigned out of range error test #3 (32 bit)
const std::vector<std::string> unsigned_out_of_range_test_3{ "2000000000000000000000", "4294967296" };
const std::vector<std::string_view> unsigned_out_of_range_test_3{ "2000000000000000000000", "4294967296" };
for (std::size_t i = 0; i < unsigned_out_of_range_test_3.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_out_of_range_test_3.size(); ++i) {
const auto& f = unsigned_out_of_range_test_3[i];
uint32_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// unsigned out of range error test #4 (64 bit)
const std::vector<std::string> unsigned_out_of_range_test_4{ "2000000000000000000000", "18446744073709551616" };
const std::vector<std::string_view> unsigned_out_of_range_test_4{ "2000000000000000000000", "18446744073709551616" };
for (std::size_t i = 0; i < unsigned_out_of_range_test_4.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_out_of_range_test_4.size(); ++i) {
const auto& f = unsigned_out_of_range_test_4[i];
uint64_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// int pointer test #1 (only numbers)
const std::vector<std::string> int_pointer_test_1 { "0", "010", "-40" };
const std::vector<std::string_view> int_pointer_test_1 { "0", "010", "-40" };
for (std::size_t i = 0; i < int_pointer_test_1.size(); ++i)
{
for (std::size_t i = 0; i < int_pointer_test_1.size(); ++i) {
const auto& f = int_pointer_test_1[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
if (answer.ec != std::errc()) {
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
else if (strcmp(answer.ptr, "") != 0) {
std::cerr << "ptr of result " << std::quoted(f) << " did not match with expected ptr: " << std::quoted("") << std::endl;
std::cerr << "ptr of result " << quoted(f) << " did not match with expected ptr: " << quoted("") << std::endl;
return EXIT_FAILURE;
}
}
// int pointer test #2 (string behind numbers)
const std::string int_pointer_test_2 = "1001 with text";
const std::string_view int_pointer_test_2 = "1001 with text";
const auto& f2 = int_pointer_test_2;
int result2;
auto answer2 = fast_float::from_chars(f2.data(), f2.data() + f2.size(), result2);
if (strcmp(answer2.ptr, " with text") != 0) {
std::cerr << "ptr of result " << std::quoted(f2) << " did not match with expected ptr: " << std::quoted(" with text") << std::endl;
std::cerr << "ptr of result " << quoted(f2) << " did not match with expected ptr: " << quoted(" with text") << std::endl;
return EXIT_FAILURE;
}
// int pointer test #3 (string with newline behind numbers)
const std::string int_pointer_test_3 = "1001 with text\n";
const std::string_view int_pointer_test_3 = "1001 with text\n";
const auto& f3 = int_pointer_test_3;
int result3;
auto answer3 = fast_float::from_chars(f3.data(), f3.data() + f3.size(), result3);
if (strcmp(answer3.ptr, " with text\n") != 0) {
std::cerr << "ptr of result " << std::quoted(f3) << " did not match with expected ptr: " << std::quoted(" with text") << std::endl;
std::cerr << "ptr of result " << quoted(f3) << " did not match with expected ptr: " << quoted(" with text") << std::endl;
return EXIT_FAILURE;
}
// int pointer test #4 (float)
const std::string int_pointer_test_4 = "9.999";
const std::string_view int_pointer_test_4 = "9.999";
const auto& f4 = int_pointer_test_4;
int result4;
auto answer4 = fast_float::from_chars(f4.data(), f4.data() + f4.size(), result4);
if (strcmp(answer4.ptr, ".999") != 0) {
std::cerr << "ptr of result " << std::quoted(f4) << " did not match with expected ptr: " << std::quoted(".999") << std::endl;
std::cerr << "ptr of result " << quoted(f4) << " did not match with expected ptr: " << quoted(".999") << std::endl;
return EXIT_FAILURE;
}
// int pointer test #5 (invalid int)
const std::string int_pointer_test_5 = "+50";
const std::string_view int_pointer_test_5 = "+50";
const auto& f5 = int_pointer_test_5;
int result5;
auto answer5 = fast_float::from_chars(f5.data(), f5.data() + f5.size(), result5);
if (strcmp(answer5.ptr, "+50") != 0) {
std::cerr << "ptr of result " << std::quoted(f5) << " did not match with expected ptr: " << std::quoted("+50") << std::endl;
std::cerr << "ptr of result " << quoted(f5) << " did not match with expected ptr: " << quoted("+50") << std::endl;
return EXIT_FAILURE;
}
// unsigned pointer test #2 (string behind numbers)
const std::string unsigned_pointer_test_1 = "1001 with text";
const std::string_view unsigned_pointer_test_1 = "1001 with text";
const auto& f6 = unsigned_pointer_test_1;
unsigned result6;
auto answer6 = fast_float::from_chars(f6.data(), f6.data() + f6.size(), result6);
if (strcmp(answer6.ptr, " with text") != 0) {
std::cerr << "ptr of result " << std::quoted(f6) << " did not match with expected ptr: " << std::quoted(" with text") << std::endl;
std::cerr << "ptr of result " << quoted(f6) << " did not match with expected ptr: " << quoted(" with text") << std::endl;
return EXIT_FAILURE;
}
// unsigned pointer test #2 (invalid unsigned)
const std::string unsigned_pointer_test_2 = "-50";
const std::string_view unsigned_pointer_test_2 = "-50";
const auto& f7 = unsigned_pointer_test_2;
unsigned result7;
auto answer7 = fast_float::from_chars(f7.data(), f7.data() + f7.size(), result7);
if (strcmp(answer7.ptr, "-50") != 0) {
std::cerr << "ptr of result " << std::quoted(f7) << " did not match with expected ptr: " << std::quoted("-50") << std::endl;
std::cerr << "ptr of result " << quoted(f7) << " did not match with expected ptr: " << quoted("-50") << std::endl;
return EXIT_FAILURE;
}
// int base 2 test
const std::vector<int> int_base_2_test_expected { 0, 1, 4, 2, -1 };
const std::vector<std::string> int_base_2_test { "0", "1", "100", "010", "-1" };
const std::vector<std::string_view> int_base_2_test { "0", "1", "100", "010", "-1" };
for (std::size_t i = 0; i < int_base_2_test.size(); ++i)
{
for (std::size_t i = 0; i < int_base_2_test.size(); ++i) {
const auto& f = int_base_2_test[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 2);
if (answer.ec != std::errc()) {
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
else if (result != int_base_2_test_expected[i]) {
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << int_base_2_test_expected[i] << std::endl;
std::cerr << "result " << quoted(f) << " did not match with expected int: " << int_base_2_test_expected[i] << std::endl;
return EXIT_FAILURE;
}
}
// unsigned base 2 test
const std::vector<unsigned> unsigned_base_2_test_expected { 0, 1, 4, 2 };
const std::vector<std::string> unsigned_base_2_test { "0", "1", "100", "010" };
const std::vector<std::string_view> unsigned_base_2_test { "0", "1", "100", "010" };
for (std::size_t i = 0; i < unsigned_base_2_test.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_base_2_test.size(); ++i) {
const auto& f = unsigned_base_2_test[i];
unsigned result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 2);
if (answer.ec != std::errc()) {
std::cerr << "could not convert to unsigned for input: " << std::quoted(f) << std::endl;
std::cerr << "could not convert to unsigned for input: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
else if (result != unsigned_base_2_test_expected[i]) {
std::cerr << "result " << std::quoted(f) << " did not match with expected unsigned: " << unsigned_base_2_test_expected[i] << std::endl;
std::cerr << "result " << quoted(f) << " did not match with expected unsigned: " << unsigned_base_2_test_expected[i] << std::endl;
return EXIT_FAILURE;
}
}
// int invalid error base 2 test
const std::vector<std::string> int_invalid_argument_base_2_test{ "2", "A", "-2" };
const std::vector<std::string_view> int_invalid_argument_base_2_test{ "2", "A", "-2" };
for (std::size_t i = 0; i < int_invalid_argument_base_2_test.size(); ++i)
{
for (std::size_t i = 0; i < int_invalid_argument_base_2_test.size(); ++i) {
const auto& f = int_invalid_argument_base_2_test[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 2);
if (answer.ec != std::errc::invalid_argument) {
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// unsigned invalid error base 2 test
const std::vector<std::string> unsigned_invalid_argument_base_2_test{ "2", "A", "-1", "-2" };
const std::vector<std::string_view> unsigned_invalid_argument_base_2_test{ "2", "A", "-1", "-2" };
for (std::size_t i = 0; i < unsigned_invalid_argument_base_2_test.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_invalid_argument_base_2_test.size(); ++i) {
const auto& f = unsigned_invalid_argument_base_2_test[i];
unsigned result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 2);
if (answer.ec != std::errc::invalid_argument) {
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// octal test
const std::vector<int> base_octal_test_expected {0, 1, 7, 8, 9};
const std::vector<std::string> base_octal_test { "0", "1", "07", "010", "0011" };
const std::vector<std::string_view> base_octal_test { "0", "1", "07", "010", "0011" };
for (std::size_t i = 0; i < base_octal_test.size(); ++i)
{
for (std::size_t i = 0; i < base_octal_test.size(); ++i) {
const auto& f = base_octal_test[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 8);
if (answer.ec != std::errc()) {
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
else if (result != base_octal_test_expected[i]) {
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << base_octal_test_expected[i] << std::endl;
std::cerr << "result " << quoted(f) << " did not match with expected int: " << base_octal_test_expected[i] << std::endl;
return EXIT_FAILURE;
}
}
// hex test
const std::vector<int> base_hex_test_expected { 0, 1, 15, 31, 0, 16};
const std::vector<std::string> base_hex_test { "0", "1", "F", "01f", "0x11", "10X11" };
const std::vector<std::string_view> base_hex_test { "0", "1", "F", "01f", "0x11", "10X11" };
for (std::size_t i = 0; i < base_hex_test.size(); ++i)
{
for (std::size_t i = 0; i < base_hex_test.size(); ++i) {
const auto& f = base_hex_test[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 16);
if (answer.ec != std::errc()) {
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
else if (result != base_hex_test_expected[i]) {
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << base_hex_test_expected[i] << std::endl;
std::cerr << "result " << quoted(f) << " did not match with expected int: " << base_hex_test_expected[i] << std::endl;
return EXIT_FAILURE;
}
}
// invalid base test #1 (-1)
const std::vector<std::string> invalid_base_test_1 { "0", "1", "-1", "F", "10Z" };
const std::vector<std::string_view> invalid_base_test_1 { "0", "1", "-1", "F", "10Z" };
for (std::size_t i = 0; i < invalid_base_test_1.size(); ++i)
{
for (std::size_t i = 0; i < invalid_base_test_1.size(); ++i) {
const auto& f = invalid_base_test_1[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, -1);
if (answer.ec != std::errc::invalid_argument) {
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// invalid base test #2 (37)
const std::vector<std::string> invalid_base_test_2 { "0", "1", "F", "Z", "10Z" };
const std::vector<std::string_view> invalid_base_test_2 { "0", "1", "F", "Z", "10Z" };
for (std::size_t i = 0; i < invalid_base_test_2.size(); ++i)
{
for (std::size_t i = 0; i < invalid_base_test_2.size(); ++i) {
const auto& f = invalid_base_test_2[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 37);
if (answer.ec != std::errc::invalid_argument) {
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// int out of range error base test (64 bit)
const std::vector<std::string> int_out_of_range_base_test { "1000000000000000000000000000000000000000000000000000000000000000",
const std::vector<std::string_view> int_out_of_range_base_test { "1000000000000000000000000000000000000000000000000000000000000000",
"-1000000000000000000000000000000000000000000000000000000000000001",
"2021110011022210012102010021220101220222",
"-2021110011022210012102010021220101221000",
@ -504,19 +503,18 @@ int main()
"1Y2P0IJ32E8E8",
"-1Y2P0IJ32E8E9" };
for (std::size_t i = 0; i < int_out_of_range_base_test.size(); ++i)
{
for (std::size_t i = 0; i < int_out_of_range_base_test.size(); ++i) {
const auto& f = int_out_of_range_base_test[i];
int64_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, int(2 + (i / 2)));
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
}
// unsigned out of range error base test (64 bit)
const std::vector<std::string> unsigned_out_of_range_base_test { "10000000000000000000000000000000000000000000000000000000000000000",
const std::vector<std::string_view> unsigned_out_of_range_base_test { "10000000000000000000000000000000000000000000000000000000000000000",
"11112220022122120101211020120210210211221",
"100000000000000000000000000000000",
"2214220303114400424121122431",
@ -552,20 +550,19 @@ int main()
"5G24A25TWKWFG",
"3W5E11264SGSG" };
int base_unsigned = 2;
for (std::size_t i = 0; i < unsigned_out_of_range_base_test.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_out_of_range_base_test.size(); ++i) {
const auto& f = unsigned_out_of_range_base_test[i];
uint64_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, base_unsigned);
if (answer.ec != std::errc::result_out_of_range) {
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
++base_unsigned;
}
// just within range base test (64 bit)
const std::vector<std::string> int_within_range_base_test { "111111111111111111111111111111111111111111111111111111111111111",
const std::vector<std::string_view> int_within_range_base_test { "111111111111111111111111111111111111111111111111111111111111111",
"-1000000000000000000000000000000000000000000000000000000000000000",
"2021110011022210012102010021220101220221",
"-2021110011022210012102010021220101220222",
@ -636,19 +633,18 @@ int main()
"1Y2P0IJ32E8E7",
"-1Y2P0IJ32E8E8" };
for (std::size_t i = 0; i < int_within_range_base_test.size(); ++i)
{
for (std::size_t i = 0; i < int_within_range_base_test.size(); ++i) {
const auto& f = int_within_range_base_test[i];
int64_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, int(2 + (i / 2)));
if (answer.ec != std::errc()) {
std::cerr << "converting " << std::quoted(f) << " to int failed (most likely out of range)" << std::endl;
std::cerr << "converting " << quoted(f) << " to int failed (most likely out of range)" << std::endl;
return EXIT_FAILURE;
}
}
// unsigned within range base test (64 bit)
const std::vector<std::string> unsigned_within_range_base_test { "1111111111111111111111111111111111111111111111111111111111111111",
const std::vector<std::string_view> unsigned_within_range_base_test { "1111111111111111111111111111111111111111111111111111111111111111",
"11112220022122120101211020120210210211220",
"33333333333333333333333333333333",
"2214220303114400424121122430",
@ -684,20 +680,19 @@ int main()
"5G24A25TWKWFF",
"3W5E11264SGSF" };
int base_unsigned2 = 2;
for (std::size_t i = 0; i < unsigned_within_range_base_test.size(); ++i)
{
for (std::size_t i = 0; i < unsigned_within_range_base_test.size(); ++i) {
const auto& f = unsigned_within_range_base_test[i];
uint64_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, base_unsigned2);
if (answer.ec != std::errc()) {
std::cerr << "converting " << std::quoted(f) << " to unsigned failed (most likely out of range)" << std::endl;
std::cerr << "converting " << quoted(f) << " to unsigned failed (most likely out of range)" << std::endl;
return EXIT_FAILURE;
}
++base_unsigned2;
}
// int leading zeros test
const std::vector<std::string> int_leading_zeros_test { "00000000000000000000000000000000000000000000000000000000000000000000001111110111",
const std::vector<std::string_view> int_leading_zeros_test { "00000000000000000000000000000000000000000000000000000000000000000000001111110111",
"000000000000000000000000000000000000000000000000001101121",
"000000000000000000000000000000000000000033313",
"00000000000000000000000000000013030",
@ -733,20 +728,43 @@ int main()
"00000000000000000000T0",
"00000000000000000000S7" };
for (std::size_t i = 0; i < int_leading_zeros_test.size(); ++i)
{
for (std::size_t i = 0; i < int_leading_zeros_test.size(); ++i) {
const auto& f = int_leading_zeros_test[i];
int result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, int(i + 2));
if (answer.ec != std::errc()) {
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
return EXIT_FAILURE;
}
else if (result != 1015) {
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << 1015 << std::endl;
std::cerr << "result " << quoted(f) << " did not match with expected int: " << 1015 << std::endl;
return EXIT_FAILURE;
}
}
// issue 235
{
std::vector<char> s = {'0'};
s.shrink_to_fit();
int foo;
auto answer = fast_float::from_chars(s.data(), s.data() + s.size(), foo);
if (answer.ec != std::errc()) {
std::cerr << "could not convert to int for input: '0'" << std::endl;
return EXIT_FAILURE;
}
else if (foo != 0) {
std::cerr << "expected zero: " << foo << std::endl;
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
#else
#include <iostream>
#include <cstdlib>
int main() {
std::cerr << "The test requires C++17." << std::endl;
return EXIT_SUCCESS;
}
#endif