// This file is a part of toml++ and is subject to the the terms of the MIT license. // Copyright (c) Mark Gillard // See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT #include "tests.h" #ifdef _WIN32 TOML_DISABLE_WARNINGS; #include TOML_ENABLE_WARNINGS; #endif template static constexpr T one = static_cast(1); TEST_CASE("values - construction") { static constexpr auto check_value = [](const auto& init_value, auto expected_native_type_tag) { using init_type = impl::remove_cvref; using native_type = impl::native_type_of; using expected_native_type = typename decltype(expected_native_type_tag)::type; static_assert(std::is_same_v); auto v = value{ init_value }; using value_type = decltype(v); static_assert(std::is_same_v>); if constexpr (std::is_same_v) { #if TOML_HAS_CHAR8 using char8_type = char8_t; #else using char8_type = char; #endif using init_char_type = impl::remove_cvref; using init_view_type = std::basic_string_view; static_assert(impl::is_one_of); const auto init_view = init_view_type{ init_value }; if constexpr (impl::is_one_of) { const auto coerced_view = std::string_view{ reinterpret_cast(init_view.data()), init_view.length() }; CHECK(v == coerced_view); CHECK(coerced_view == v); } #if TOML_ENABLE_WINDOWS_COMPAT else if constexpr (impl::is_one_of) { const auto narrowed_string = impl::narrow(init_view); CHECK(v == narrowed_string); CHECK(narrowed_string == v); } #endif else { static_assert(impl::dependent_false, "evaluated unreachable branch"); } } else if constexpr (impl::is_one_of) { CHECK(v == static_cast(init_value)); CHECK(static_cast(init_value) == v); } else // dates + times { CHECK(v == init_value); CHECK(init_value == v); } static constexpr auto expected_node_type = impl::node_type_of; CHECK(v.is_homogeneous()); CHECK(v.template is_homogeneous()); CHECK(v.is_homogeneous(expected_node_type)); // sanity check the virtual type checks CHECK(v.type() == expected_node_type); CHECK(!v.is_table()); CHECK(!v.is_array()); CHECK(!v.is_array_of_tables()); CHECK(v.is_value()); CHECK(v.is_string() == (expected_node_type == node_type::string)); CHECK(v.is_integer() == (expected_node_type == node_type::integer)); CHECK(v.is_floating_point() == (expected_node_type == node_type::floating_point)); CHECK(v.is_number() == (expected_node_type == node_type::integer || expected_node_type == node_type::floating_point)); CHECK(v.is_boolean() == (expected_node_type == node_type::boolean)); CHECK(v.is_date() == (expected_node_type == node_type::date)); CHECK(v.is_time() == (expected_node_type == node_type::time)); CHECK(v.is_date_time() == (expected_node_type == node_type::date_time)); // sanity check the virtual type casts (non-const) CHECK(!v.as_table()); CHECK(!v.as_array()); if constexpr (expected_node_type == node_type::string) CHECK(v.as_string() == &v); else CHECK(!v.as_string()); if constexpr (expected_node_type == node_type::integer) CHECK(v.as_integer() == &v); else CHECK(!v.as_integer()); if constexpr (expected_node_type == node_type::floating_point) CHECK(v.as_floating_point() == &v); else CHECK(!v.as_floating_point()); if constexpr (expected_node_type == node_type::boolean) CHECK(v.as_boolean() == &v); else CHECK(!v.as_boolean()); if constexpr (expected_node_type == node_type::date) CHECK(v.as_date() == &v); else CHECK(!v.as_date()); if constexpr (expected_node_type == node_type::time) CHECK(v.as_time() == &v); else CHECK(!v.as_time()); if constexpr (expected_node_type == node_type::date_time) CHECK(v.as_date_time() == &v); else CHECK(!v.as_date_time()); // sanity check the virtual type casts (const) const auto& cv = std::as_const(v); CHECK(!cv.as_table()); CHECK(!cv.as_array()); if constexpr (expected_node_type == node_type::string) CHECK(cv.as_string() == &v); else CHECK(!cv.as_string()); if constexpr (expected_node_type == node_type::integer) CHECK(cv.as_integer() == &v); else CHECK(!cv.as_integer()); if constexpr (expected_node_type == node_type::floating_point) CHECK(cv.as_floating_point() == &v); else CHECK(!cv.as_floating_point()); if constexpr (expected_node_type == node_type::boolean) CHECK(cv.as_boolean() == &v); else CHECK(!cv.as_boolean()); if constexpr (expected_node_type == node_type::date) CHECK(cv.as_date() == &v); else CHECK(!cv.as_date()); if constexpr (expected_node_type == node_type::time) CHECK(cv.as_time() == &v); else CHECK(!cv.as_time()); if constexpr (expected_node_type == node_type::date_time) CHECK(cv.as_date_time() == &v); else CHECK(!cv.as_date_time()); }; check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(true, type_tag{}); check_value(false, type_tag{}); check_value("kek", type_tag{}); check_value("kek"s, type_tag{}); check_value("kek"sv, type_tag{}); check_value("kek"sv.data(), type_tag{}); #if TOML_HAS_CHAR8 check_value(u8"kek", type_tag{}); check_value(u8"kek"s, type_tag{}); check_value(u8"kek"sv, type_tag{}); check_value(u8"kek"sv.data(), type_tag{}); #endif #ifdef _WIN32 check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); check_value(one, type_tag{}); #if TOML_ENABLE_WINDOWS_COMPAT check_value(L"kek", type_tag{}); check_value(L"kek"s, type_tag{}); check_value(L"kek"sv, type_tag{}); check_value(L"kek"sv.data(), type_tag{}); #endif // TOML_ENABLE_WINDOWS_COMPAT #endif } TEST_CASE("values - toml_formatter") { static constexpr auto print_value = [](auto&& raw) { auto val = toml::value{ std::forward(raw) }; std::stringstream ss; ss << val; return ss.str(); }; CHECK(print_value(1) == "1"); CHECK(print_value(1.0f) == "1.0"); CHECK(print_value(1.0) == "1.0"); CHECK(print_value(1.5f) == "1.5"); CHECK(print_value(1.5) == "1.5"); CHECK(print_value(10) == "10"); CHECK(print_value(10.0f) == "10.0"); CHECK(print_value(10.0) == "10.0"); CHECK(print_value(100) == "100"); CHECK(print_value(100.0f) == "100.0"); CHECK(print_value(100.0) == "100.0"); CHECK(print_value(1000) == "1000"); CHECK(print_value(1000.0f) == "1000.0"); CHECK(print_value(1000.0) == "1000.0"); CHECK(print_value(10000) == "10000"); CHECK(print_value(10000.0f) == "10000.0"); CHECK(print_value(10000.0) == "10000.0"); CHECK(print_value(std::numeric_limits::infinity()) == "inf"); CHECK(print_value(-std::numeric_limits::infinity()) == "-inf"); CHECK(print_value(std::numeric_limits::quiet_NaN()) == "nan"); // only integers for large values; // large floats might get output as scientific notation and that's fine CHECK(print_value(10000000000) == "10000000000"); CHECK(print_value(100000000000000) == "100000000000000"); } TEST_CASE("nodes - value() int/float/bool conversions") { #define CHECK_VALUE_PASS(type, v) CHECK(n.value() == static_cast(v)) #define CHECK_VALUE_FAIL(type) CHECK(!n.value()) // bools { value val{ false }; const node& n = val; CHECK_VALUE_PASS(bool, false); CHECK_VALUE_PASS(int8_t, 0); CHECK_VALUE_PASS(uint8_t, 0); CHECK_VALUE_PASS(int16_t, 0); CHECK_VALUE_PASS(uint16_t, 0); CHECK_VALUE_PASS(int32_t, 0); CHECK_VALUE_PASS(uint32_t, 0); CHECK_VALUE_PASS(int64_t, 0); CHECK_VALUE_PASS(uint64_t, 0); CHECK_VALUE_FAIL(float); CHECK_VALUE_FAIL(double); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = true; CHECK_VALUE_PASS(bool, true); CHECK_VALUE_PASS(int8_t, 1); CHECK_VALUE_PASS(uint8_t, 1); CHECK_VALUE_PASS(int16_t, 1); CHECK_VALUE_PASS(uint16_t, 1); CHECK_VALUE_PASS(int32_t, 1); CHECK_VALUE_PASS(uint32_t, 1); CHECK_VALUE_PASS(int64_t, 1); CHECK_VALUE_PASS(uint64_t, 1); CHECK_VALUE_FAIL(float); CHECK_VALUE_FAIL(double); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); } // ints { value val{ 0 }; const node& n = val; CHECK_VALUE_PASS(bool, false); // int -> bool coercion CHECK_VALUE_PASS(int8_t, 0); CHECK_VALUE_PASS(uint8_t, 0); CHECK_VALUE_PASS(int16_t, 0); CHECK_VALUE_PASS(uint16_t, 0); CHECK_VALUE_PASS(int32_t, 0); CHECK_VALUE_PASS(uint32_t, 0); CHECK_VALUE_PASS(int64_t, 0); CHECK_VALUE_PASS(uint64_t, 0); CHECK_VALUE_PASS(float, 0); CHECK_VALUE_PASS(double, 0); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = 100; CHECK_VALUE_PASS(bool, true); // int -> bool coercion CHECK_VALUE_PASS(int8_t, 100); CHECK_VALUE_PASS(uint8_t, 100); CHECK_VALUE_PASS(int16_t, 100); CHECK_VALUE_PASS(uint16_t, 100); CHECK_VALUE_PASS(int32_t, 100); CHECK_VALUE_PASS(uint32_t, 100); CHECK_VALUE_PASS(int64_t, 100); CHECK_VALUE_PASS(uint64_t, 100); CHECK_VALUE_PASS(float, 100); CHECK_VALUE_PASS(double, 100); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = -100; CHECK_VALUE_PASS(bool, true); // int -> bool coercion CHECK_VALUE_PASS(int8_t, -100); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_PASS(int16_t, -100); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_PASS(int32_t, -100); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_PASS(int64_t, -100); CHECK_VALUE_FAIL(uint64_t); CHECK_VALUE_PASS(float, -100); CHECK_VALUE_PASS(double, -100); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = 1000; CHECK_VALUE_PASS(bool, true); // int -> bool coercion CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_PASS(int16_t, 1000); CHECK_VALUE_PASS(uint16_t, 1000); CHECK_VALUE_PASS(int32_t, 1000); CHECK_VALUE_PASS(uint32_t, 1000); CHECK_VALUE_PASS(int64_t, 1000); CHECK_VALUE_PASS(uint64_t, 1000); CHECK_VALUE_PASS(float, 1000); CHECK_VALUE_PASS(double, 1000); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = -1000; CHECK_VALUE_PASS(bool, true); // int -> bool coercion CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_PASS(int16_t, -1000); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_PASS(int32_t, -1000); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_PASS(int64_t, -1000); CHECK_VALUE_FAIL(uint64_t); CHECK_VALUE_PASS(float, -1000); CHECK_VALUE_PASS(double, -1000); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = (std::numeric_limits::max)(); CHECK_VALUE_PASS(bool, true); // int -> bool coercion CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_FAIL(int16_t); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_FAIL(int32_t); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_PASS(int64_t, (std::numeric_limits::max)()); CHECK_VALUE_PASS(uint64_t, (std::numeric_limits::max)()); CHECK_VALUE_FAIL(float); CHECK_VALUE_FAIL(double); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = (std::numeric_limits::min)(); CHECK_VALUE_PASS(bool, true); // int -> bool coercion CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_FAIL(int16_t); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_FAIL(int32_t); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_PASS(int64_t, (std::numeric_limits::min)()); CHECK_VALUE_FAIL(uint64_t); CHECK_VALUE_FAIL(float); CHECK_VALUE_FAIL(double); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); } // floats { value val{ 0.0 }; const node& n = val; CHECK_VALUE_FAIL(bool); CHECK_VALUE_PASS(int8_t, 0); CHECK_VALUE_PASS(uint8_t, 0); CHECK_VALUE_PASS(int16_t, 0); CHECK_VALUE_PASS(uint16_t, 0); CHECK_VALUE_PASS(int32_t, 0); CHECK_VALUE_PASS(uint32_t, 0); CHECK_VALUE_PASS(int64_t, 0); CHECK_VALUE_PASS(uint64_t, 0); CHECK_VALUE_PASS(float, 0); CHECK_VALUE_PASS(double, 0); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = 1.0; CHECK_VALUE_FAIL(bool); CHECK_VALUE_PASS(int8_t, 1); CHECK_VALUE_PASS(uint8_t, 1); CHECK_VALUE_PASS(int16_t, 1); CHECK_VALUE_PASS(uint16_t, 1); CHECK_VALUE_PASS(int32_t, 1); CHECK_VALUE_PASS(uint32_t, 1); CHECK_VALUE_PASS(int64_t, 1); CHECK_VALUE_PASS(uint64_t, 1); CHECK_VALUE_PASS(float, 1); CHECK_VALUE_PASS(double, 1); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = -1.0; CHECK_VALUE_FAIL(bool); CHECK_VALUE_PASS(int8_t, -1); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_PASS(int16_t, -1); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_PASS(int32_t, -1); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_PASS(int64_t, -1); CHECK_VALUE_FAIL(uint64_t); CHECK_VALUE_PASS(float, -1); CHECK_VALUE_PASS(double, -1); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = 1.5; CHECK_VALUE_FAIL(bool); CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_FAIL(int16_t); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_FAIL(int32_t); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_FAIL(int64_t); CHECK_VALUE_FAIL(uint64_t); CHECK_VALUE_PASS(float, 1.5); CHECK_VALUE_PASS(double, 1.5); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = -1.5; CHECK_VALUE_FAIL(bool); CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_FAIL(int16_t); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_FAIL(int32_t); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_FAIL(int64_t); CHECK_VALUE_FAIL(uint64_t); CHECK_VALUE_PASS(float, -1.5); CHECK_VALUE_PASS(double, -1.5); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = std::numeric_limits::infinity(); CHECK_VALUE_FAIL(bool); CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_FAIL(int16_t); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_FAIL(int32_t); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_FAIL(int64_t); CHECK_VALUE_FAIL(uint64_t); CHECK_VALUE_PASS(float, std::numeric_limits::infinity()); CHECK_VALUE_PASS(double, std::numeric_limits::infinity()); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = -std::numeric_limits::infinity(); CHECK_VALUE_FAIL(bool); CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_FAIL(int16_t); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_FAIL(int32_t); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_FAIL(int64_t); CHECK_VALUE_FAIL(uint64_t); CHECK_VALUE_PASS(float, -std::numeric_limits::infinity()); CHECK_VALUE_PASS(double, -std::numeric_limits::infinity()); CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); *val = std::numeric_limits::quiet_NaN(); CHECK_VALUE_FAIL(bool); CHECK_VALUE_FAIL(int8_t); CHECK_VALUE_FAIL(uint8_t); CHECK_VALUE_FAIL(int16_t); CHECK_VALUE_FAIL(uint16_t); CHECK_VALUE_FAIL(int32_t); CHECK_VALUE_FAIL(uint32_t); CHECK_VALUE_FAIL(int64_t); CHECK_VALUE_FAIL(uint64_t); { auto fval = n.value(); REQUIRE(fval.has_value()); CHECK(impl::fpclassify(*fval) == impl::fp_class::nan); } { auto fval = n.value(); REQUIRE(fval.has_value()); CHECK(impl::fpclassify(*fval) == impl::fp_class::nan); } CHECK_VALUE_FAIL(std::string); CHECK_VALUE_FAIL(std::string_view); CHECK_VALUE_FAIL(toml::date); CHECK_VALUE_FAIL(toml::time); CHECK_VALUE_FAIL(toml::date_time); } }