From ba754462b84d928048a1bc645d9759cb06dedd68 Mon Sep 17 00:00:00 2001 From: Mark Gillard Date: Thu, 24 Jun 2021 21:08:45 +0300 Subject: [PATCH] fixed linkage error with windows compat mode also: - updated conformance tests --- external/Catch2 | 2 +- external/tloptional | 2 +- external/toml-test | 2 +- include/toml++/toml.h | 4 +- include/toml++/toml_common.h | 4 +- include/toml++/toml_default_formatter.hpp | 57 +- include/toml++/toml_preprocessor.h | 50 +- tests/conformance_burntsushi_invalid.cpp | 625 ++++++-- tests/conformance_burntsushi_valid.cpp | 1568 +++++++++++++++++---- tests/conformance_iarna_invalid.cpp | 115 +- tests/conformance_iarna_valid.cpp | 304 ++-- toml.hpp | 114 +- tools/generate_conformance_tests.py | 243 ++-- 13 files changed, 2324 insertions(+), 766 deletions(-) diff --git a/external/Catch2 b/external/Catch2 index 5c88067..7727c15 160000 --- a/external/Catch2 +++ b/external/Catch2 @@ -1 +1 @@ -Subproject commit 5c88067bd339465513af4aec606bd2292f1b594a +Subproject commit 7727c15290ce2d289c1809d0eab3cceb88384ad6 diff --git a/external/tloptional b/external/tloptional index e28828e..c28fcf7 160000 --- a/external/tloptional +++ b/external/tloptional @@ -1 +1 @@ -Subproject commit e28828efa021bf51f1c8cc3248642ec5a636c8d7 +Subproject commit c28fcf74d207fc667c4ed3dbae4c251ea551c8c1 diff --git a/external/toml-test b/external/toml-test index 9767d20..1f63896 160000 --- a/external/toml-test +++ b/external/toml-test @@ -1 +1 @@ -Subproject commit 9767d201b51ac9c50630f181828bcd922bf3e9e5 +Subproject commit 1f6389604dc6053f23cc4679c557a0b0e69eaf5d diff --git a/include/toml++/toml.h b/include/toml++/toml.h index 6e91d4e..05ca319 100644 --- a/include/toml++/toml.h +++ b/include/toml++/toml.h @@ -100,6 +100,7 @@ TOML_POP_WARNINGS; // TOML_DISABLE_SPAM_WARNINGS #undef TOML_IMPLEMENTATION #undef TOML_IMPL_NAMESPACE_END #undef TOML_IMPL_NAMESPACE_START + #undef TOML_INCLUDE_WINDOWS_H #undef TOML_INT128 #undef TOML_INTELLISENSE #undef TOML_INTERNAL_LINKAGE @@ -111,7 +112,8 @@ TOML_POP_WARNINGS; // TOML_DISABLE_SPAM_WARNINGS #undef TOML_LAUNDER #undef TOML_LIFETIME_HOOKS #undef TOML_LIKELY - #undef TOML_MAKE_BITOPS + #undef TOML_MAKE_FLAGS_ + #undef TOML_MAKE_FLAGS #undef TOML_MAKE_VERSION #undef TOML_MAY_THROW #undef TOML_MSVC diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h index 747b86d..4050881 100644 --- a/include/toml++/toml_common.h +++ b/include/toml++/toml_common.h @@ -995,7 +995,7 @@ TOML_NAMESPACE_START /// \brief Format integer values as hexadecimal. format_as_hexadecimal = 3, }; - TOML_MAKE_BITOPS(value_flags); + TOML_MAKE_FLAGS(value_flags); /// \brief Format flags for modifying how TOML data is printed to streams. enum class format_flags : uint8_t @@ -1015,7 +1015,7 @@ TOML_NAMESPACE_START /// \brief Values with special format flags will be formatted accordingly. allow_value_format_flags = 8, }; - TOML_MAKE_BITOPS(format_flags); + TOML_MAKE_FLAGS(format_flags); /// \brief Pretty-prints the value of a node_type to a stream. /// diff --git a/include/toml++/toml_default_formatter.hpp b/include/toml++/toml_default_formatter.hpp index 0602fd1..54063ae 100644 --- a/include/toml++/toml_default_formatter.hpp +++ b/include/toml++/toml_default_formatter.hpp @@ -202,27 +202,34 @@ TOML_NAMESPACE_END; #if TOML_WINDOWS_COMPAT #ifndef _WINDOWS_ -extern "C" -{ - int __stdcall WideCharToMultiByte( - unsigned int CodePage, - unsigned long dwFlags, - const wchar_t* lpWideCharStr, - int cchWideChar, - char* lpMultiByteStr, - int cbMultiByte, - const char* lpDefaultChar, - int* lpUsedDefaultChar - ); - int __stdcall MultiByteToWideChar( - unsigned int CodePage, - unsigned long dwFlags, - const char* lpMultiByteStr, - int cbMultiByte, - wchar_t* lpWideCharStr, - int cchWideChar - ); -} + #if TOML_INCLUDE_WINDOWS_H + #include + #else + extern "C" + { + __declspec(dllimport) + int __stdcall WideCharToMultiByte( + unsigned int CodePage, + unsigned long dwFlags, + const wchar_t* lpWideCharStr, + int cchWideChar, + char* lpMultiByteStr, + int cbMultiByte, + const char* lpDefaultChar, + int* lpUsedDefaultChar + ); + + __declspec(dllimport) + int __stdcall MultiByteToWideChar( + unsigned int CodePage, + unsigned long dwFlags, + const char* lpMultiByteStr, + int cbMultiByte, + wchar_t* lpWideCharStr, + int cchWideChar + ); + } + #endif #endif // _WINDOWS_ TOML_IMPL_NAMESPACE_START @@ -234,13 +241,13 @@ TOML_IMPL_NAMESPACE_START return {}; std::string s; - const auto len = WideCharToMultiByte( + const auto len = ::WideCharToMultiByte( 65001, 0, str.data(), static_cast(str.length()), nullptr, 0, nullptr, nullptr ); if (len) { s.resize(static_cast(len)); - WideCharToMultiByte(65001, 0, str.data(), static_cast(str.length()), s.data(), len, nullptr, nullptr); + ::WideCharToMultiByte(65001, 0, str.data(), static_cast(str.length()), s.data(), len, nullptr, nullptr); } return s; } @@ -252,11 +259,11 @@ TOML_IMPL_NAMESPACE_START return {}; std::wstring s; - const auto len = MultiByteToWideChar(65001, 0, str.data(), static_cast(str.length()), nullptr, 0); + const auto len = ::MultiByteToWideChar(65001, 0, str.data(), static_cast(str.length()), nullptr, 0); if (len) { s.resize(static_cast(len)); - MultiByteToWideChar(65001, 0, str.data(), static_cast(str.length()), s.data(), len); + ::MultiByteToWideChar(65001, 0, str.data(), static_cast(str.length()), s.data(), len); } return s; } diff --git a/include/toml++/toml_preprocessor.h b/include/toml++/toml_preprocessor.h index 6c23c36..6ad0f69 100644 --- a/include/toml++/toml_preprocessor.h +++ b/include/toml++/toml_preprocessor.h @@ -393,12 +393,21 @@ #endif #ifndef DOXYGEN - #if defined(_WIN32) && !defined(TOML_WINDOWS_COMPAT) - #define TOML_WINDOWS_COMPAT 1 + #ifdef _WIN32 + #ifndef TOML_WINDOWS_COMPAT + #define TOML_WINDOWS_COMPAT 1 + #endif + #if TOML_WINDOWS_COMPAT && !defined(TOML_INCLUDE_WINDOWS_H) + #define TOML_INCLUDE_WINDOWS_H 0 + #endif #endif #if !defined(_WIN32) || !defined(TOML_WINDOWS_COMPAT) #undef TOML_WINDOWS_COMPAT - #define TOML_WINDOWS_COMPAT 0 + #define TOML_WINDOWS_COMPAT 0 + #endif + #if !TOML_WINDOWS_COMPAT + #undef TOML_INCLUDE_WINDOWS_H + #define TOML_INCLUDE_WINDOWS_H 0 #endif #endif @@ -609,24 +618,43 @@ is no longer necessary. #define TOML_ARM 0 #endif -#define TOML_MAKE_BITOPS(type) \ +#define TOML_MAKE_FLAGS_(name, op) \ [[nodiscard]] \ TOML_ALWAYS_INLINE \ TOML_ATTR(const) \ - TOML_ATTR(flatten) \ - constexpr type operator & (type lhs, type rhs) noexcept \ + constexpr name operator op(name lhs, name rhs) noexcept \ { \ - return static_cast(::toml::impl::unwrap_enum(lhs) & ::toml::impl::unwrap_enum(rhs)); \ + using under = std::underlying_type_t; \ + return static_cast(static_cast(lhs) op static_cast(rhs)); \ + } \ + constexpr name& operator TOML_CONCAT(op, =)(name & lhs, name rhs) noexcept \ + { \ + return lhs = (lhs op rhs); \ + } \ + static_assert(true, "") + +#define TOML_MAKE_FLAGS(name) \ + TOML_MAKE_FLAGS_(name, &); \ + TOML_MAKE_FLAGS_(name, |); \ + TOML_MAKE_FLAGS_(name, ^); \ + [[nodiscard]] \ + TOML_ALWAYS_INLINE \ + TOML_ATTR(const) \ + constexpr name operator~(name val) noexcept \ + { \ + using under = std::underlying_type_t; \ + return static_cast(~static_cast(val)); \ } \ [[nodiscard]] \ TOML_ALWAYS_INLINE \ TOML_ATTR(const) \ - TOML_ATTR(flatten) \ - constexpr type operator | (type lhs, type rhs) noexcept \ + constexpr bool operator!(name val) noexcept \ { \ - return static_cast(::toml::impl::unwrap_enum(lhs) | ::toml::impl::unwrap_enum(rhs)); \ + using under = std::underlying_type_t; \ + return !static_cast(val); \ } \ - static_assert(true) + static_assert(true, "") + #ifndef TOML_LIFETIME_HOOKS #define TOML_LIFETIME_HOOKS 0 diff --git a/tests/conformance_burntsushi_invalid.cpp b/tests/conformance_burntsushi_invalid.cpp index 4166495..b1930e1 100644 --- a/tests/conformance_burntsushi_invalid.cpp +++ b/tests/conformance_burntsushi_invalid.cpp @@ -12,12 +12,42 @@ TOML_DISABLE_WARNINGS; // unused variable spam namespace { + static constexpr auto array_missing_separator = R"(wrong = [ 1 2 3 ])"sv; + static constexpr auto array_no_close_2 = R"(x = [42 #)"sv; + static constexpr auto array_no_close_table_2 = R"(x = [{ key = 42 #)"sv; + static constexpr auto array_no_close_table = R"(x = [{ key = 42)"sv; + static constexpr auto array_no_close = R"(long_array = [ 1, 2, 3)"sv; + static constexpr auto array_of_tables_1 = R"(# INVALID TOML DOC +fruit = [] + +[[fruit]] # Not allowed)"sv; + static constexpr auto array_of_tables_2 = R"(# INVALID TOML DOC +[[fruit]] + name = "apple" + + [[fruit.variety]] + name = "red delicious" + + # This table conflicts with the previous table + [fruit.variety] + name = "granny smith")"sv; + + static constexpr auto bool_mixed_case = R"(valid = False)"sv; static constexpr auto bool_wrong_case_false = R"(b = FALSE)"sv; static constexpr auto bool_wrong_case_true = R"(a = TRUE)"sv; - static constexpr auto datetime_malformed_no_leads = R"(no-leads = 1987-7-05T17:45:00Z)"sv; - static constexpr auto datetime_malformed_no_secs = R"(no-secs = 1987-07-05T17:45Z)"sv; - static constexpr auto datetime_malformed_no_t = R"(no-t = 1987-07-0517:45:00Z)"sv; - static constexpr auto datetime_malformed_with_milli = R"(with-milli = 1987-07-5T17:45:00.12Z)"sv; + + static constexpr auto datetime_impossible_date = R"(d = 2006-01-50T00:00:00Z)"sv; + static constexpr auto datetime_no_leads_with_milli = R"(with-milli = 1987-07-5T17:45:00.12Z)"sv; + static constexpr auto datetime_no_leads = R"(no-leads = 1987-7-05T17:45:00Z)"sv; + static constexpr auto datetime_no_t = R"(no-t = 1987-07-0517:45:00Z)"sv; + static constexpr auto datetime_trailing_t = R"(d = 2006-01-30T)"sv; + +#if !TOML_LANG_UNRELEASED + + static constexpr auto datetime_no_secs = R"(no-secs = 1987-07-05T17:45Z)"sv; + +#endif // !TOML_LANG_UNRELEASED + static constexpr auto duplicate_key_table = R"([fruit] type = "apple" @@ -25,58 +55,187 @@ type = "apple" apple = "yes")"sv; static constexpr auto duplicate_keys = R"(dupe = false dupe = true)"sv; + static constexpr auto duplicate_table_array = R"([tbl] +[[tbl]])"sv; + static constexpr auto duplicate_table_array2 = R"([[tbl]] +[tbl])"sv; static constexpr auto duplicate_tables = R"([a] [a])"sv; + static constexpr auto empty_implicit_table = R"([naughty..naughty])"sv; static constexpr auto empty_table = R"([])"sv; - static constexpr auto float_leading_zero_neg = R"(leading-zero = -03.14)"sv; - static constexpr auto float_leading_zero_pos = R"(leading-zero = +03.14)"sv; + + static constexpr auto float_double_point_1 = R"(double-point-1 = 0..1)"sv; + static constexpr auto float_double_point_2 = R"(double-point-2 = 0.1.2)"sv; + static constexpr auto float_exp_double_e_1 = R"(exp-double-e-1 = 1ee2)"sv; + static constexpr auto float_exp_double_e_2 = R"(exp-double-e-2 = 1e2e3)"sv; + static constexpr auto float_exp_double_us = R"(exp-double-us = 1e__23)"sv; + static constexpr auto float_exp_leading_us = R"(exp-leading-us = 1e_23)"sv; + static constexpr auto float_exp_point_1 = R"(exp-point-1 = 1e2.3)"sv; + static constexpr auto float_exp_point_2 = R"(exp-point-2 = 1.e2)"sv; + static constexpr auto float_exp_trailing_us = R"(exp-trailing-us = 1e_23_)"sv; + static constexpr auto float_inf_incomplete_1 = R"(inf-incomplete-1 = in)"sv; + static constexpr auto float_inf_incomplete_2 = R"(inf-incomplete-2 = +in)"sv; + static constexpr auto float_inf_incomplete_3 = R"(inf-incomplete-3 = -in)"sv; + static constexpr auto float_inf_underscore = R"(inf_underscore = in_f)"sv; + static constexpr auto float_leading_point_neg = R"(leading-point-neg = -.12345)"sv; + static constexpr auto float_leading_point_plus = R"(leading-point-plus = +.12345)"sv; + static constexpr auto float_leading_point = R"(leading-point = .12345)"sv; + static constexpr auto float_leading_us = R"(leading-us = _1.2)"sv; + static constexpr auto float_leading_zero_neg = R"(leading-zero-neg = -03.14)"sv; + static constexpr auto float_leading_zero_plus = R"(leading-zero-plus = +03.14)"sv; static constexpr auto float_leading_zero = R"(leading-zero = 03.14)"sv; - static constexpr auto float_no_leading_zero = R"(answer = .12345 -neganswer = -.12345)"sv; - static constexpr auto float_no_trailing_digits = R"(answer = 1. -neganswer = -1.)"sv; - static constexpr auto float_underscore_after_point = R"(bad = 1._2)"sv; - static constexpr auto float_underscore_after = R"(bad = 1.2_)"sv; - static constexpr auto float_underscore_before_point = R"(bad = 1_.2)"sv; - static constexpr auto float_underscore_before = R"(bad = _1.2)"sv; - static constexpr auto inline_table_linebreak = R"(simple = { a = 1 + static constexpr auto float_nan_incomplete_1 = R"(nan-incomplete-1 = na)"sv; + static constexpr auto float_nan_incomplete_2 = R"(nan-incomplete-2 = +na)"sv; + static constexpr auto float_nan_incomplete_3 = R"(nan-incomplete-3 = -na)"sv; + static constexpr auto float_nan_underscore = R"(nan_underscore = na_n)"sv; + static constexpr auto float_trailing_point_min = R"(trailing-point-min = -1.)"sv; + static constexpr auto float_trailing_point_plus = R"(trailing-point-plus = +1.)"sv; + static constexpr auto float_trailing_point = R"(trailing-point = 1.)"sv; + static constexpr auto float_trailing_us = R"(trailing-us = 1.2_)"sv; + static constexpr auto float_us_after_point = R"(us-after-point = 1._2)"sv; + static constexpr auto float_us_before_point = R"(us-before-point = 1_.2)"sv; + + static constexpr auto inline_table_double_comma = R"(t = {x=3,,y=4})"sv; + static constexpr auto inline_table_empty = R"(t = {,})"sv; + static constexpr auto inline_table_no_comma = R"(t = {x = 3 y = 4})"sv; + +#if !TOML_LANG_UNRELEASED + + static constexpr auto inline_table_linebreak_1 = R"(# No newlines are allowed between the curly braces unless they are valid within +# a value. +simple = { a = 1 })"sv; - static constexpr auto integer_leading_zero_neg = R"(leading-zero = -012)"sv; - static constexpr auto integer_leading_zero_pos = R"(leading-zero = +012)"sv; - static constexpr auto integer_leading_zero = R"(leading-zero = 012)"sv; - static constexpr auto integer_underscore_after = R"(bad = 123_)"sv; - static constexpr auto integer_underscore_before = R"(bad = _123)"sv; - static constexpr auto integer_underscore_double = R"(bad = 1__23)"sv; + static constexpr auto inline_table_linebreak_2 = R"(t = {a=1, +b=2})"sv; + static constexpr auto inline_table_linebreak_3 = R"(t = {a=1 +,b=2})"sv; + static constexpr auto inline_table_trailing_comma = R"(# A terminating comma (also called trailing comma) is not permitted after the +# last key/value pair in an inline table +abc = { abc = 123, })"sv; + +#endif // !TOML_LANG_UNRELEASED + + static constexpr auto integer_capital_bin = R"(capital-bin = 0B0)"sv; + static constexpr auto integer_capital_hex = R"(capital-hex = 0X1)"sv; + static constexpr auto integer_capital_oct = R"(capital-oct = 0O0)"sv; + static constexpr auto integer_double_sign_nex = R"(double-sign-nex = --99)"sv; + static constexpr auto integer_double_sign_plus = R"(double-sign-plus = ++99)"sv; + static constexpr auto integer_double_us = R"(double-us = 1__23)"sv; + static constexpr auto integer_invalid_bin = R"(invalid-bin = 0b0012)"sv; + static constexpr auto integer_invalid_hex = R"(invalid-hex = 0xaafz)"sv; + static constexpr auto integer_invalid_oct = R"(invalid-oct = 0o778)"sv; + static constexpr auto integer_leading_us_bin = R"(leading-us-bin = _0o1)"sv; + static constexpr auto integer_leading_us_hex = R"(leading-us-hex = _0o1)"sv; + static constexpr auto integer_leading_us_oct = R"(leading-us-oct = _0o1)"sv; + static constexpr auto integer_leading_us = R"(leading-us = _123)"sv; + static constexpr auto integer_leading_zero_1 = R"(leading-zero-1 = 01)"sv; + static constexpr auto integer_leading_zero_2 = R"(leading-zero-2 = 00)"sv; + static constexpr auto integer_leading_zero_sign_1 = R"(leading-zero-sign-1 = -01)"sv; + static constexpr auto integer_leading_zero_sign_2 = R"(leading-zero-sign-2 = +01)"sv; + static constexpr auto integer_negative_bin = R"(negative-bin = -0b11010110)"sv; + static constexpr auto integer_negative_hex = R"(negative-hex = -0xff)"sv; + static constexpr auto integer_negative_oct = R"(negative-oct = -0o99)"sv; + static constexpr auto integer_positive_bin = R"(positive-bin = +0b11010110)"sv; + static constexpr auto integer_positive_hex = R"(positive-hex = +0xff)"sv; + static constexpr auto integer_positive_oct = R"(positive-oct = +0o99)"sv; + static constexpr auto integer_trailing_us_bin = R"(trailing-us-bin = 0b1_)"sv; + static constexpr auto integer_trailing_us_hex = R"(trailing-us-hex = 0x1_)"sv; + static constexpr auto integer_trailing_us_oct = R"(trailing-us-oct = 0o1_)"sv; + static constexpr auto integer_trailing_us = R"(trailing-us = 123_)"sv; + static constexpr auto integer_us_after_bin = R"(us-after-bin = 0b_1)"sv; + static constexpr auto integer_us_after_hex = R"(us-after-hex = 0x_1)"sv; + static constexpr auto integer_us_after_oct = R"(us-after-oct = 0o_1)"sv; + static constexpr auto key_after_array = R"([[agencies]] owner = "S Cjelli")"sv; static constexpr auto key_after_table = R"([error] this = "should not be here")"sv; + static constexpr auto key_after_value = R"(first = "Tom" last = "Preston-Werner" # INVALID)"sv; + static constexpr auto key_bare_invalid_character = R"(bare!key = 123)"sv; + static constexpr auto key_dotted_redefine_table = R"(# Defined a.b as int +a.b = 1 +# Tries to access it as table: error +a.b.c = 2)"sv; + static constexpr auto key_duplicate = R"(# DO NOT DO THIS +name = "Tom" +name = "Pradyun")"sv; static constexpr auto key_empty = R"(= 1)"sv; + static constexpr auto key_escape = R"(\u00c0 = "latin capital letter A with grave")"sv; static constexpr auto key_hash = R"(a# = 1)"sv; - static constexpr auto key_newline = R"(a -= 1)"sv; + static constexpr auto key_multiline = R"("""long +key""" = 1)"sv; + static constexpr auto key_newline = R"(barekey + = 123)"sv; static constexpr auto key_no_eol = R"(a = 1 b = 2)"sv; static constexpr auto key_open_bracket = R"([abc = 1)"sv; + static constexpr auto key_partial_quoted = R"(partial"quoted" = 5)"sv; static constexpr auto key_single_open_bracket = R"([)"sv; static constexpr auto key_space = R"(a b = 1)"sv; static constexpr auto key_start_bracket = R"([a] [xyz = 5 [b])"sv; static constexpr auto key_two_equals = R"(key= = 1)"sv; + static constexpr auto key_two_equals2 = R"(a==1)"sv; + static constexpr auto key_two_equals3 = R"(a=b=1)"sv; + static constexpr auto key_without_value_1 = R"(key)"sv; + static constexpr auto key_without_value_2 = R"(key =)"sv; + +#if !TOML_LANG_UNRELEASED && UNICODE_LITERALS_OK + + static constexpr auto key_special_character = R"(μ = "greek small letter mu")"sv; + +#endif // !TOML_LANG_UNRELEASED && UNICODE_LITERALS_OK + static constexpr auto llbrace = R"([ [table]])"sv; + +#if !TOML_LANG_UNRELEASED + static constexpr auto multi_line_inline_table = R"(json_like = { first = "Tom", last = "Preston-Werner" })"sv; + +#endif // !TOML_LANG_UNRELEASED + + static constexpr auto multi_line_string_no_close_2 = R"(x=""")"sv; static constexpr auto multi_line_string_no_close = R"(invalid = """ this will fail)"sv; + static constexpr auto rrbrace = R"([[table] ])"sv; + static constexpr auto string_bad_byte_escape = R"(naughty = "\xAg")"sv; static constexpr auto string_bad_codepoint = R"(invalid-codepoint = "This string contains a non scalar unicode codepoint \uD801")"sv; + static constexpr auto string_bad_concat = R"(no_concat = "first" "second")"sv; static constexpr auto string_bad_escape = R"(invalid-escape = "This string has a bad \a escape character.")"sv; + static constexpr auto string_bad_multiline = R"(multi = "first line +second line")"sv; static constexpr auto string_bad_slash_escape = R"(invalid-escape = "This string has a bad \/ escape character.")"sv; static constexpr auto string_bad_uni_esc = R"(str = "val\ue")"sv; - static constexpr auto string_byte_escapes = R"(answer = "\x33")"sv; + static constexpr auto string_basic_multiline_out_of_range_unicode_escape_1 = R"(a = """\UFFFFFFFF""")"sv; + static constexpr auto string_basic_multiline_out_of_range_unicode_escape_2 = R"(a = """\U00D80000""")"sv; + static constexpr auto string_basic_multiline_quotes = R"(str5 = """Here are three quotation marks: """.""")"sv; + static constexpr auto string_basic_multiline_unknown_escape = R"(a = """\@""")"sv; + static constexpr auto string_basic_out_of_range_unicode_escape_1 = R"(a = "\UFFFFFFFF")"sv; + static constexpr auto string_basic_out_of_range_unicode_escape_2 = R"(a = "\U00D80000")"sv; + static constexpr auto string_basic_unknown_escape = R"(a = "\@")"sv; + static constexpr auto string_literal_multiline_quotes_1 = R"(a = '''6 apostrophes: '''''')"sv; + static constexpr auto string_literal_multiline_quotes_2 = R"(a = '''15 apostrophes: '''''''''''''''''')"sv; + static constexpr auto string_missing_quotes = R"(name = value)"sv; + static constexpr auto string_multiline_escape_space = R"(a = """ + foo \ \n + bar""")"sv; + static constexpr auto string_multiline_quotes_1 = R"(a = """6 quotes: """""")"sv; + static constexpr auto string_multiline_quotes_2 = R"(a = """6 quotes: """""")"sv; static constexpr auto string_no_close = R"(no-ending-quote = "One time, at band camp)"sv; + static constexpr auto string_wrong_close = R"(bad-ending-quote = "double and single')"sv; + +#if !TOML_LANG_UNRELEASED + + static constexpr auto string_basic_byte_escapes = R"(answer = "\x33")"sv; + +#endif // !TOML_LANG_UNRELEASED + + static constexpr auto table_array_empty = R"([[]] +name = "Born to Run")"sv; static constexpr auto table_array_implicit = R"(# This test is a bit tricky. It should fail because the first use of # `[[albums.songs]]` without first declaring `albums` implies that `albums` # must be a table. The alternative would be quite weird. Namely, it wouldn't @@ -91,18 +250,31 @@ name = "Glory Days" [[albums]] name = "Born in the USA")"sv; - static constexpr auto table_array_malformed_bracket = R"([[albums] -name = "Born to Run")"sv; - static constexpr auto table_array_malformed_empty = R"([[]] + static constexpr auto table_array_missing_bracket = R"([[albums] name = "Born to Run")"sv; + static constexpr auto table_duplicate = R"([a] +b = 1 + +[a] +c = 2)"sv; static constexpr auto table_empty = R"([])"sv; + static constexpr auto table_equals_sign = R"([name=bad])"sv; static constexpr auto table_nested_brackets_close = R"([a]b] zyx = 42)"sv; static constexpr auto table_nested_brackets_open = R"([a[b] zyx = 42)"sv; + static constexpr auto table_quoted_no_close = R"(["where will it end] +name = value)"sv; + static constexpr auto table_redefine = R"(# Define b as int, and try to use it as a table: error +[a] +b = 1 + +[a.b] +c = 2)"sv; static constexpr auto table_whitespace = R"([invalid key])"sv; static constexpr auto table_with_pound = R"([key#group] answer = 42)"sv; + static constexpr auto text_after_array_entries = R"(array = [ "Is there life after an array separator?", No "Entry" @@ -125,71 +297,342 @@ TOML_ENABLE_WARNINGS; TEST_CASE("conformance - burntsushi/invalid") { - parsing_should_fail(FILE_LINE_ARGS, bool_wrong_case_false); - parsing_should_fail(FILE_LINE_ARGS, bool_wrong_case_true); - parsing_should_fail(FILE_LINE_ARGS, datetime_malformed_no_leads); - parsing_should_fail(FILE_LINE_ARGS, datetime_malformed_no_t); - parsing_should_fail(FILE_LINE_ARGS, datetime_malformed_with_milli); - parsing_should_fail(FILE_LINE_ARGS, duplicate_key_table); - parsing_should_fail(FILE_LINE_ARGS, duplicate_keys); - parsing_should_fail(FILE_LINE_ARGS, duplicate_tables); - parsing_should_fail(FILE_LINE_ARGS, empty_implicit_table); - parsing_should_fail(FILE_LINE_ARGS, empty_table); - parsing_should_fail(FILE_LINE_ARGS, float_leading_zero_neg); - parsing_should_fail(FILE_LINE_ARGS, float_leading_zero_pos); - parsing_should_fail(FILE_LINE_ARGS, float_leading_zero); - parsing_should_fail(FILE_LINE_ARGS, float_no_leading_zero); - parsing_should_fail(FILE_LINE_ARGS, float_no_trailing_digits); - parsing_should_fail(FILE_LINE_ARGS, float_underscore_after_point); - parsing_should_fail(FILE_LINE_ARGS, float_underscore_after); - parsing_should_fail(FILE_LINE_ARGS, float_underscore_before_point); - parsing_should_fail(FILE_LINE_ARGS, float_underscore_before); - parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_neg); - parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_pos); - parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero); - parsing_should_fail(FILE_LINE_ARGS, integer_underscore_after); - parsing_should_fail(FILE_LINE_ARGS, integer_underscore_before); - parsing_should_fail(FILE_LINE_ARGS, integer_underscore_double); - parsing_should_fail(FILE_LINE_ARGS, key_after_array); - parsing_should_fail(FILE_LINE_ARGS, key_after_table); - parsing_should_fail(FILE_LINE_ARGS, key_empty); - parsing_should_fail(FILE_LINE_ARGS, key_hash); - parsing_should_fail(FILE_LINE_ARGS, key_newline); - parsing_should_fail(FILE_LINE_ARGS, key_no_eol); - parsing_should_fail(FILE_LINE_ARGS, key_open_bracket); - parsing_should_fail(FILE_LINE_ARGS, key_single_open_bracket); - parsing_should_fail(FILE_LINE_ARGS, key_space); - parsing_should_fail(FILE_LINE_ARGS, key_start_bracket); - parsing_should_fail(FILE_LINE_ARGS, key_two_equals); - parsing_should_fail(FILE_LINE_ARGS, llbrace); - parsing_should_fail(FILE_LINE_ARGS, multi_line_string_no_close); - parsing_should_fail(FILE_LINE_ARGS, rrbrace); - parsing_should_fail(FILE_LINE_ARGS, string_bad_byte_escape); - parsing_should_fail(FILE_LINE_ARGS, string_bad_codepoint); - parsing_should_fail(FILE_LINE_ARGS, string_bad_escape); - parsing_should_fail(FILE_LINE_ARGS, string_bad_slash_escape); - parsing_should_fail(FILE_LINE_ARGS, string_bad_uni_esc); - parsing_should_fail(FILE_LINE_ARGS, string_no_close); - parsing_should_fail(FILE_LINE_ARGS, table_array_implicit); - parsing_should_fail(FILE_LINE_ARGS, table_array_malformed_bracket); - parsing_should_fail(FILE_LINE_ARGS, table_array_malformed_empty); - parsing_should_fail(FILE_LINE_ARGS, table_empty); - parsing_should_fail(FILE_LINE_ARGS, table_nested_brackets_close); - parsing_should_fail(FILE_LINE_ARGS, table_nested_brackets_open); - parsing_should_fail(FILE_LINE_ARGS, table_whitespace); - parsing_should_fail(FILE_LINE_ARGS, table_with_pound); - parsing_should_fail(FILE_LINE_ARGS, text_after_array_entries); - parsing_should_fail(FILE_LINE_ARGS, text_after_integer); - parsing_should_fail(FILE_LINE_ARGS, text_after_string); - parsing_should_fail(FILE_LINE_ARGS, text_after_table); - parsing_should_fail(FILE_LINE_ARGS, text_before_array_separator); - parsing_should_fail(FILE_LINE_ARGS, text_in_array); + parsing_should_fail(FILE_LINE_ARGS, array_missing_separator); + + parsing_should_fail(FILE_LINE_ARGS, array_no_close_2); + + parsing_should_fail(FILE_LINE_ARGS, array_no_close_table_2); + + parsing_should_fail(FILE_LINE_ARGS, array_no_close_table); + + parsing_should_fail(FILE_LINE_ARGS, array_no_close); + + parsing_should_fail(FILE_LINE_ARGS, array_of_tables_1); + + parsing_should_fail(FILE_LINE_ARGS, array_of_tables_2); + + parsing_should_fail(FILE_LINE_ARGS, bool_mixed_case); + + parsing_should_fail(FILE_LINE_ARGS, bool_wrong_case_false); + + parsing_should_fail(FILE_LINE_ARGS, bool_wrong_case_true); + + parsing_should_fail(FILE_LINE_ARGS, datetime_impossible_date); + + parsing_should_fail(FILE_LINE_ARGS, datetime_no_leads_with_milli); + + parsing_should_fail(FILE_LINE_ARGS, datetime_no_leads); + + parsing_should_fail(FILE_LINE_ARGS, datetime_no_t); + + parsing_should_fail(FILE_LINE_ARGS, datetime_trailing_t); + +#if !TOML_LANG_UNRELEASED + + parsing_should_fail(FILE_LINE_ARGS, datetime_no_secs); + +#endif // !TOML_LANG_UNRELEASED + + parsing_should_fail(FILE_LINE_ARGS, duplicate_key_table); + + parsing_should_fail(FILE_LINE_ARGS, duplicate_keys); + + parsing_should_fail(FILE_LINE_ARGS, duplicate_table_array); + + parsing_should_fail(FILE_LINE_ARGS, duplicate_table_array2); + + parsing_should_fail(FILE_LINE_ARGS, duplicate_tables); + + parsing_should_fail(FILE_LINE_ARGS, empty_implicit_table); + + parsing_should_fail(FILE_LINE_ARGS, empty_table); + + parsing_should_fail(FILE_LINE_ARGS, float_double_point_1); + + parsing_should_fail(FILE_LINE_ARGS, float_double_point_2); + + parsing_should_fail(FILE_LINE_ARGS, float_exp_double_e_1); + + parsing_should_fail(FILE_LINE_ARGS, float_exp_double_e_2); + + parsing_should_fail(FILE_LINE_ARGS, float_exp_double_us); + + parsing_should_fail(FILE_LINE_ARGS, float_exp_leading_us); + + parsing_should_fail(FILE_LINE_ARGS, float_exp_point_1); + + parsing_should_fail(FILE_LINE_ARGS, float_exp_point_2); + + parsing_should_fail(FILE_LINE_ARGS, float_exp_trailing_us); + + parsing_should_fail(FILE_LINE_ARGS, float_inf_incomplete_1); + + parsing_should_fail(FILE_LINE_ARGS, float_inf_incomplete_2); + + parsing_should_fail(FILE_LINE_ARGS, float_inf_incomplete_3); + + parsing_should_fail(FILE_LINE_ARGS, float_inf_underscore); + + parsing_should_fail(FILE_LINE_ARGS, float_leading_point_neg); + + parsing_should_fail(FILE_LINE_ARGS, float_leading_point_plus); + + parsing_should_fail(FILE_LINE_ARGS, float_leading_point); + + parsing_should_fail(FILE_LINE_ARGS, float_leading_us); + + parsing_should_fail(FILE_LINE_ARGS, float_leading_zero_neg); + + parsing_should_fail(FILE_LINE_ARGS, float_leading_zero_plus); + + parsing_should_fail(FILE_LINE_ARGS, float_leading_zero); + + parsing_should_fail(FILE_LINE_ARGS, float_nan_incomplete_1); + + parsing_should_fail(FILE_LINE_ARGS, float_nan_incomplete_2); + + parsing_should_fail(FILE_LINE_ARGS, float_nan_incomplete_3); + + parsing_should_fail(FILE_LINE_ARGS, float_nan_underscore); + + parsing_should_fail(FILE_LINE_ARGS, float_trailing_point_min); + + parsing_should_fail(FILE_LINE_ARGS, float_trailing_point_plus); + + parsing_should_fail(FILE_LINE_ARGS, float_trailing_point); + + parsing_should_fail(FILE_LINE_ARGS, float_trailing_us); + + parsing_should_fail(FILE_LINE_ARGS, float_us_after_point); + + parsing_should_fail(FILE_LINE_ARGS, float_us_before_point); + + parsing_should_fail(FILE_LINE_ARGS, inline_table_double_comma); + + parsing_should_fail(FILE_LINE_ARGS, inline_table_empty); + + parsing_should_fail(FILE_LINE_ARGS, inline_table_no_comma); + +#if !TOML_LANG_UNRELEASED + + parsing_should_fail(FILE_LINE_ARGS, inline_table_linebreak_1); + + parsing_should_fail(FILE_LINE_ARGS, inline_table_linebreak_2); + + parsing_should_fail(FILE_LINE_ARGS, inline_table_linebreak_3); + + parsing_should_fail(FILE_LINE_ARGS, inline_table_trailing_comma); + +#endif // !TOML_LANG_UNRELEASED + + parsing_should_fail(FILE_LINE_ARGS, integer_capital_bin); + + parsing_should_fail(FILE_LINE_ARGS, integer_capital_hex); + + parsing_should_fail(FILE_LINE_ARGS, integer_capital_oct); + + parsing_should_fail(FILE_LINE_ARGS, integer_double_sign_nex); + + parsing_should_fail(FILE_LINE_ARGS, integer_double_sign_plus); + + parsing_should_fail(FILE_LINE_ARGS, integer_double_us); + + parsing_should_fail(FILE_LINE_ARGS, integer_invalid_bin); + + parsing_should_fail(FILE_LINE_ARGS, integer_invalid_hex); + + parsing_should_fail(FILE_LINE_ARGS, integer_invalid_oct); + + parsing_should_fail(FILE_LINE_ARGS, integer_leading_us_bin); + + parsing_should_fail(FILE_LINE_ARGS, integer_leading_us_hex); + + parsing_should_fail(FILE_LINE_ARGS, integer_leading_us_oct); + + parsing_should_fail(FILE_LINE_ARGS, integer_leading_us); + + parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_1); + + parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_2); + + parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_sign_1); + + parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_sign_2); + + parsing_should_fail(FILE_LINE_ARGS, integer_negative_bin); + + parsing_should_fail(FILE_LINE_ARGS, integer_negative_hex); + + parsing_should_fail(FILE_LINE_ARGS, integer_negative_oct); + + parsing_should_fail(FILE_LINE_ARGS, integer_positive_bin); + + parsing_should_fail(FILE_LINE_ARGS, integer_positive_hex); + + parsing_should_fail(FILE_LINE_ARGS, integer_positive_oct); + + parsing_should_fail(FILE_LINE_ARGS, integer_trailing_us_bin); + + parsing_should_fail(FILE_LINE_ARGS, integer_trailing_us_hex); + + parsing_should_fail(FILE_LINE_ARGS, integer_trailing_us_oct); + + parsing_should_fail(FILE_LINE_ARGS, integer_trailing_us); + + parsing_should_fail(FILE_LINE_ARGS, integer_us_after_bin); + + parsing_should_fail(FILE_LINE_ARGS, integer_us_after_hex); + + parsing_should_fail(FILE_LINE_ARGS, integer_us_after_oct); + + parsing_should_fail(FILE_LINE_ARGS, key_after_array); + + parsing_should_fail(FILE_LINE_ARGS, key_after_table); + + parsing_should_fail(FILE_LINE_ARGS, key_after_value); + + parsing_should_fail(FILE_LINE_ARGS, key_bare_invalid_character); + + parsing_should_fail(FILE_LINE_ARGS, key_dotted_redefine_table); + + parsing_should_fail(FILE_LINE_ARGS, key_duplicate); + + parsing_should_fail(FILE_LINE_ARGS, key_empty); + + parsing_should_fail(FILE_LINE_ARGS, key_escape); + + parsing_should_fail(FILE_LINE_ARGS, key_hash); + + parsing_should_fail(FILE_LINE_ARGS, key_multiline); + + parsing_should_fail(FILE_LINE_ARGS, key_newline); + + parsing_should_fail(FILE_LINE_ARGS, key_no_eol); + + parsing_should_fail(FILE_LINE_ARGS, key_open_bracket); + + parsing_should_fail(FILE_LINE_ARGS, key_partial_quoted); + + parsing_should_fail(FILE_LINE_ARGS, key_single_open_bracket); + + parsing_should_fail(FILE_LINE_ARGS, key_space); + + parsing_should_fail(FILE_LINE_ARGS, key_start_bracket); + + parsing_should_fail(FILE_LINE_ARGS, key_two_equals); + + parsing_should_fail(FILE_LINE_ARGS, key_two_equals2); + + parsing_should_fail(FILE_LINE_ARGS, key_two_equals3); + + parsing_should_fail(FILE_LINE_ARGS, key_without_value_1); + + parsing_should_fail(FILE_LINE_ARGS, key_without_value_2); + +#if !TOML_LANG_UNRELEASED && UNICODE_LITERALS_OK + + parsing_should_fail(FILE_LINE_ARGS, key_special_character); + +#endif // !TOML_LANG_UNRELEASED && UNICODE_LITERALS_OK + + parsing_should_fail(FILE_LINE_ARGS, llbrace); + +#if !TOML_LANG_UNRELEASED - #if !TOML_LANG_UNRELEASED - parsing_should_fail(FILE_LINE_ARGS, datetime_malformed_no_secs); - parsing_should_fail(FILE_LINE_ARGS, inline_table_linebreak); parsing_should_fail(FILE_LINE_ARGS, multi_line_inline_table); - parsing_should_fail(FILE_LINE_ARGS, string_byte_escapes); - #endif // !TOML_LANG_UNRELEASED + +#endif // !TOML_LANG_UNRELEASED + + parsing_should_fail(FILE_LINE_ARGS, multi_line_string_no_close_2); + + parsing_should_fail(FILE_LINE_ARGS, multi_line_string_no_close); + + parsing_should_fail(FILE_LINE_ARGS, rrbrace); + + parsing_should_fail(FILE_LINE_ARGS, string_bad_byte_escape); + + parsing_should_fail(FILE_LINE_ARGS, string_bad_codepoint); + + parsing_should_fail(FILE_LINE_ARGS, string_bad_concat); + + parsing_should_fail(FILE_LINE_ARGS, string_bad_escape); + + parsing_should_fail(FILE_LINE_ARGS, string_bad_multiline); + + parsing_should_fail(FILE_LINE_ARGS, string_bad_slash_escape); + + parsing_should_fail(FILE_LINE_ARGS, string_bad_uni_esc); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_1); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_2); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_quotes); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_unknown_escape); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_1); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_2); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_unknown_escape); + + parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_quotes_1); + + parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_quotes_2); + + parsing_should_fail(FILE_LINE_ARGS, string_missing_quotes); + + parsing_should_fail(FILE_LINE_ARGS, string_multiline_escape_space); + + parsing_should_fail(FILE_LINE_ARGS, string_multiline_quotes_1); + + parsing_should_fail(FILE_LINE_ARGS, string_multiline_quotes_2); + + parsing_should_fail(FILE_LINE_ARGS, string_no_close); + + parsing_should_fail(FILE_LINE_ARGS, string_wrong_close); + +#if !TOML_LANG_UNRELEASED + + parsing_should_fail(FILE_LINE_ARGS, string_basic_byte_escapes); + +#endif // !TOML_LANG_UNRELEASED + + parsing_should_fail(FILE_LINE_ARGS, table_array_empty); + + parsing_should_fail(FILE_LINE_ARGS, table_array_implicit); + + parsing_should_fail(FILE_LINE_ARGS, table_array_missing_bracket); + + parsing_should_fail(FILE_LINE_ARGS, table_duplicate); + + parsing_should_fail(FILE_LINE_ARGS, table_empty); + + parsing_should_fail(FILE_LINE_ARGS, table_equals_sign); + + parsing_should_fail(FILE_LINE_ARGS, table_nested_brackets_close); + + parsing_should_fail(FILE_LINE_ARGS, table_nested_brackets_open); + + parsing_should_fail(FILE_LINE_ARGS, table_quoted_no_close); + + parsing_should_fail(FILE_LINE_ARGS, table_redefine); + + parsing_should_fail(FILE_LINE_ARGS, table_whitespace); + + parsing_should_fail(FILE_LINE_ARGS, table_with_pound); + + parsing_should_fail(FILE_LINE_ARGS, text_after_array_entries); + + parsing_should_fail(FILE_LINE_ARGS, text_after_integer); + + parsing_should_fail(FILE_LINE_ARGS, text_after_string); + + parsing_should_fail(FILE_LINE_ARGS, text_after_table); + + parsing_should_fail(FILE_LINE_ARGS, text_before_array_separator); + + parsing_should_fail(FILE_LINE_ARGS, text_in_array); } diff --git a/tests/conformance_burntsushi_valid.cpp b/tests/conformance_burntsushi_valid.cpp index 7d93d3c..f9a2cd1 100644 --- a/tests/conformance_burntsushi_valid.cpp +++ b/tests/conformance_burntsushi_valid.cpp @@ -12,7 +12,16 @@ TOML_DISABLE_WARNINGS; // unused variable spam namespace { + static constexpr auto array_bool = R"(a = [true, false])"sv; static constexpr auto array_empty = R"(thevoid = [[[[[]]]]])"sv; + static constexpr auto array_hetergeneous = R"(mixed = [[1, 2], ["a", "b"], [1.1, 2.1]])"sv; + static constexpr auto array_mix_string_table = R"(numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ] +contributors = [ + "Foo Bar ", + { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" } +])"sv; + static constexpr auto array_nested_inline_table = R"(a = [ { b = {} } ])"sv; + static constexpr auto array_nested = R"(nest = [["a"], ["b"]])"sv; static constexpr auto array_nospaces = R"(ints = [1,2,3])"sv; static constexpr auto array_string_quote_comma_2 = R"(title = [ " \", ",])"sv; static constexpr auto array_string_quote_comma = R"(title = [ @@ -23,10 +32,9 @@ namespace "Client: XXXX, Job: XXXX", "Code: XXXX" ])"sv; + static constexpr auto array_strings = R"(string_array = [ "all", 'strings', """are the same""", '''type'''])"sv; static constexpr auto array_table_array_string_backslash = R"(foo = [ { bar="\"{{baz}}\""} ])"sv; - static constexpr auto arrays_hetergeneous = R"(mixed = [[1, 2], ["a", "b"], [1.1, 2.1]])"sv; - static constexpr auto arrays_nested = R"(nest = [["a"], ["b"]])"sv; - static constexpr auto arrays = R"(ints = [1, 2, 3] + static constexpr auto array_ = R"(ints = [1, 2, 3, ] floats = [1.1, 2.1, 3.1] strings = ["a", "b", "c"] dates = [ @@ -38,13 +46,15 @@ comments = [ 1, 2, #this is ok ])"sv; + static constexpr auto bool_ = R"(t = true f = false)"sv; - static constexpr auto comments_at_eof = R"(# This is a full-line comment + + static constexpr auto comment_at_eof = R"(# This is a full-line comment key = "value" # This is a comment at the end of a line)"sv; - static constexpr auto comments_at_eof2 = R"(# This is a full-line comment + static constexpr auto comment_at_eof2 = R"(# This is a full-line comment key = "value" # This is a comment at the end of a line)"sv; - static constexpr auto comments_everywhere = R"(# Top comment. + static constexpr auto comment_everywhere = R"(# Top comment. # Top comment. # Top comment. @@ -68,32 +78,89 @@ more = [ # Comment # Evil. # ] Did I fool you? ] # Hopefully not.)"sv; + static constexpr auto comment_tricky = R"([section]#attached comment +#[notsection] +one = "11"#cmt +two = "22#" +three = '#' + +four = """# no comment +# nor this +#also not comment"""#is_comment + +five = 5.5#66 +six = 6#7 +8 = "eight" +#nine = 99 +ten = 10e2#1 +eleven = 1.11e1#23 + +["hash#tag"] +"#!" = "hash bang" +arr3 = [ "#", '#', """###""" ] +arr4 = [ 1,# 9, 9, +2#,9 +,#9 +3#] +,4] +arr5 = [[[[#["#"], +["#"]]]]#] +] +tbl1 = { "#" = '}#'}#}})"sv; + + static constexpr auto datetime_local_date = R"(bestdayever = 1987-07-05)"sv; + static constexpr auto datetime_local_time = R"(besttimeever = 17:45:00 +milliseconds = 10:32:00.555)"sv; + static constexpr auto datetime_local = R"(bestdayever = 1987-07-05T17:45:00 +milliseconds = 1977-12-21T10:32:00.555 +bestdayever_with_space = 1987-07-05 17:45:00)"sv; static constexpr auto datetime_timezone = R"(bestdayever = 2017-06-06T12:34:56-05:00)"sv; - static constexpr auto double_quote_escape = R"(test = "\"one\"")"sv; - static constexpr auto empty = R"()"sv; - static constexpr auto escaped_escape = R"(answer = "\\x64")"sv; + static constexpr auto datetime = R"(bestdayever = 1987-07-05T17:45:00Z +numoffset = 1977-06-28T07:32:00-05:00 +milliseconds = 1977-12-21T10:32:00.555+07:00 +bestdayever_with_space = 1987-07-05 17:45:00Z)"sv; + + static constexpr auto empty_file = R"()"sv; + static constexpr auto example = R"(best-day-ever = 1987-07-05T17:45:00Z [numtheory] boring = false perfection = [6, 28, 496])"sv; - static constexpr auto exponent_part_float = R"(million = 1e6 -minustenth = -1E-1 -beast = 6.66E2)"sv; + static constexpr auto float_exponent = R"(lower = 3e2 upper = 3E2 neg = 3e-2 pos = 3E+2 zero = 3e0 pointlower = 3.1e2 -pointupper = 3.1E2)"sv; +pointupper = 3.1E2 +minustenth = -1E-1)"sv; + static constexpr auto float_inf_and_nan = R"(# We don't encode +nan and -nan back with the signs; many languages don't +# support a sign on NaN (it doesn't really make much sense). +nan = nan +nan_neg = -nan +nan_plus = +nan +infinity = inf +infinity_neg = -inf +infinity_plus = +inf)"sv; + static constexpr auto float_long = R"(longpi = 3.141592653589793 +neglongpi = -3.141592653589793)"sv; static constexpr auto float_underscore = R"(before = 3_141.5927 after = 3141.592_7 exponent = 3e1_4)"sv; + static constexpr auto float_zero = R"(f1 = 0.0 +f2 = +0.0 +f3 = -0.0 +f4 = 0e0 +f5 = 0e00 +f6 = +0e0 +f7 = -0e0)"sv; static constexpr auto float_ = R"(pi = 3.14 pospi = +3.14 negpi = -3.14 zero-intpart = 0.123)"sv; + static constexpr auto implicit_and_explicit_after = R"([a.b.c] answer = 42 @@ -106,24 +173,139 @@ better = 43 answer = 42)"sv; static constexpr auto implicit_groups = R"([a.b.c] answer = 42)"sv; + static constexpr auto inline_table_array = R"(people = [{first_name = "Bruce", last_name = "Springsteen"}, {first_name = "Eric", last_name = "Clapton"}, {first_name = "Bob", last_name = "Seger"}])"sv; + static constexpr auto inline_table_bool = R"(a = {a = true, b = false})"sv; + static constexpr auto inline_table_empty = R"(empty1 = {} +empty2 = { } +empty_in_array = [ { not_empty = 1 }, {} ] +empty_in_array2 = [{},{not_empty=1}] +many_empty = [{},{},{}] +nested_empty = {"empty"={}})"sv; + static constexpr auto inline_table_end_in_bool = R"(black = { python=">3.6", version=">=18.9b0", allow_prereleases=true })"sv; + static constexpr auto inline_table_multiline = R"(tbl_multiline = { a = 1, b = """ +multiline +""", c = """and yet +another line""", d = 4 })"sv; + static constexpr auto inline_table_nest = R"(tbl_tbl_empty = { tbl_0 = {} } +tbl_tbl_val = { tbl_1 = { one = 1 } } +tbl_arr_tbl = { arr_tbl = [ { one = 1 } ] } +arr_tbl_tbl = [ { tbl = { one = 1 } } ] + +# Array-of-array-of-table is interesting because it can only +# be represented in inline form. +arr_arr_tbl_empty = [ [ {} ] ] +arr_arr_tbl_val = [ [ { one = 1 } ] ] +arr_arr_tbls = [ [ { one = 1 }, { two = 2 } ] ])"sv; static constexpr auto inline_table = R"(name = { first = "Tom", last = "Preston-Werner" } point = { x = 1, y = 2 } simple = { a = 1 } str-key = { "a" = 1 } table-array = [{ "a" = 1 }, { "b" = 2 }])"sv; - static constexpr auto integer_underscore = R"(kilo = 1_000)"sv; + + static constexpr auto integer_literals = R"(bin1 = 0b11010110 +bin2 = 0b1_0_1 + +oct1 = 0o01234567 +oct2 = 0o755 +oct3 = 0o7_6_5 + +hex1 = 0xDEADBEEF +hex2 = 0xdeadbeef +hex3 = 0xdead_beef +hex4 = 0x00987)"sv; + static constexpr auto integer_long = R"(int64-max = 9223372036854775807 +int64-max-neg = -9223372036854775808)"sv; + static constexpr auto integer_underscore = R"(kilo = 1_000 +x = 1_1_1_1)"sv; + static constexpr auto integer_zero = R"(d1 = 0 +d2 = +0 +d3 = -0 + +h1 = 0x0 +h2 = 0x00 +h3 = 0x00000 + +o1 = 0o0 +a2 = 0o00 +a3 = 0o00000 + +b1 = 0b0 +b2 = 0b00 +b3 = 0b00000)"sv; static constexpr auto integer = R"(answer = 42 posanswer = +42 neganswer = -42 zero = 0)"sv; + +#if UNICODE_LITERALS_OK + + static constexpr auto key_case_sensitive = R"(sectioN = "NN" + +[section] +name = "lower" +NAME = "upper" +Name = "capitalized" + +[Section] +name = "different section!!" +"μ" = "greek small letter mu" +"Μ" = "greek capital letter MU" +M = "latin letter M")"sv; + static constexpr auto key_escapes = R"("\n" = "newline" +"\u00c0" = "latin capital letter A with grave" +"\"" = "just a quote" + +["backsp\b\b"] + +["\"quoted\""] +quote = true + +["a.b"."\u00c0"])"sv; + +#endif // UNICODE_LITERALS_OK + + static constexpr auto key_dotted = R"(# Note: this file contains literal tab characters. + +name.first = "Arthur" +"name".'last' = "Dent" + +many.dots.here.dot.dot.dot = 42 + +# Space are ignored, and key parts can be quoted. +count.a = 1 +count . b = 2 +"count"."c" = 3 +"count" . "d" = 4 +'count'.'e' = 5 +'count' . 'f' = 6 +"count".'g' = 7 +"count" . 'h' = 8 +count.'i' = 9 +count . 'j' = 10 +"count".k = 11 +"count" . l = 12 + +[tbl] +a.b.c = 42.666 + +[a.few.dots] +polka.dot = "again?" +polka.dance-with = "Dot" + +[[arr]] +a.b.c=1 +a.b.d=2 + +[[arr]] +a.b.c=3 +a.b.d=4)"sv; + static constexpr auto key_empty = R"("" = "blank")"sv; static constexpr auto key_equals_nospace = R"(answer=42)"sv; static constexpr auto key_numeric = R"(1 = 1)"sv; - static constexpr auto key_space = R"("a b" = 1)"sv; - static constexpr auto key_special_chars = R"("~!@$^&*()_+-`1234567890[]|/?><.,;:'" = 1)"sv; - static constexpr auto keys_with_dots = R"(plain = 1 + static constexpr auto key_quoted_dots = R"(plain = 1 "with.dot" = 2 [plain_table] @@ -133,38 +315,34 @@ plain = 3 [table.withdot] plain = 5 "key.with.dots" = 6)"sv; - static constexpr auto long_float = R"(longpi = 3.141592653589793 -neglongpi = -3.141592653589793)"sv; - static constexpr auto long_integer = R"(answer = 9223372036854775807 -neganswer = -9223372036854775808)"sv; - static constexpr auto multiline_string = R"(multiline_empty_one = """""" -multiline_empty_two = """ -""" -multiline_empty_three = """\ - """ -multiline_empty_four = """\ - \ - \ - """ + static constexpr auto key_space = R"("a b" = 1)"sv; + static constexpr auto key_special_chars = R"("~!@$^&*()_+-`1234567890[]|/?><.,;:'" = 1)"sv; + static constexpr auto key_special_word = R"(false = false +true = 1 +inf = 100000000 +nan = "ceci n'est pas un nombre")"sv; -equivalent_one = "The quick brown fox jumps over the lazy dog." -equivalent_two = """ -The quick brown \ + static constexpr auto multiline_string_quotes = R"(# Make sure that quotes inside multiline strings are allowed, including right +# after the opening '''/""" and before the closing '''/""" +lit_one = ''''one quote'''' +lit_two = '''''two quotes''''' +lit_one_space = ''' 'one quote' ''' +lit_two_space = ''' ''two quotes'' ''' - fox jumps over \ - the lazy dog.""" +one = """"one quote"""" +two = """""two quotes""""" +one_space = """ "one quote" """ +two_space = """ ""two quotes"" """ + +mismatch1 = """aaa'''bbb""" +mismatch2 = '''aaa"""bbb''')"sv; -equivalent_three = """\ - The quick brown \ - fox jumps over \ - the lazy dog.\ - """)"sv; - static constexpr auto nested_inline_table_array = R"(a = [ { b = {} } ])"sv; static constexpr auto newline_crlf = R"(os = "DOS" newline = "crlf")"sv; static constexpr auto newline_lf = R"(os = "unix" newline = "lf")"sv; + static constexpr auto raw_multiline_string = R"(oneline = '''This string has a ' quote character.''' firstnl = ''' This string has a ' quote character.''' @@ -181,8 +359,67 @@ formfeed = 'This string has a \f form feed character.' carriage = 'This string has a \r carriage return character.' slash = 'This string has a \/ slash character.' backslash = 'This string has a \\ backslash character.')"sv; - static constexpr auto right_curly_brace_after_boolean = R"(black = { python=">3.6", version=">=18.9b0", allow_prereleases=true })"sv; + + static constexpr auto spec_example_1_compact = R"(#Useless spaces eliminated. +title="TOML Example" +[owner] +name="Lance Uppercut" +dob=1979-05-27T07:32:00-08:00#First class dates +[database] +server="192.168.1.1" +ports=[8001,8001,8002] +connection_max=5000 +enabled=true +[servers] +[servers.alpha] +ip="10.0.0.1" +dc="eqdc10" +[servers.beta] +ip="10.0.0.2" +dc="eqdc10" +[clients] +data=[["gamma","delta"],[1,2]] +hosts=[ +"alpha", +"omega" +])"sv; + static constexpr auto spec_example_1 = R"(# This is a TOML document. Boom. + +title = "TOML Example" + +[owner] +name = "Lance Uppercut" +dob = 1979-05-27T07:32:00-08:00 # First class dates? Why not? + +[database] +server = "192.168.1.1" +ports = [ 8001, 8001, 8002 ] +connection_max = 5000 +enabled = true + +[servers] + + # You can indent as you please. Tabs or spaces. TOML don't care. + [servers.alpha] + ip = "10.0.0.1" + dc = "eqdc10" + + [servers.beta] + ip = "10.0.0.2" + dc = "eqdc10" + +[clients] +data = [ ["gamma", "delta"], [1, 2] ] + +# Line breaks are OK when inside arrays +hosts = [ + "alpha", + "omega" +])"sv; + + static constexpr auto string_double_quote_escape = R"(test = "\"one\"")"sv; static constexpr auto string_empty = R"(answer = "")"sv; + static constexpr auto string_escaped_escape = R"(answer = "\\x64")"sv; static constexpr auto string_nl = R"(nl_mid = "val\nue" nl_end = """value\n""" @@ -192,6 +429,30 @@ lit_nl_uni = 'val\ue')"sv; static constexpr auto string_simple = R"(answer = "You are not drinking enough whisky.")"sv; static constexpr auto string_with_pound = R"(pound = "We see no # comments here." poundcomment = "But there are # some comments here." # Did I # mess you up?)"sv; + +#if UNICODE_LITERALS_OK + + static constexpr auto string_escape_tricky = R"(end_esc = "String does not end here\" but ends here\\" +lit_end_esc = 'String ends here\' + +multiline_unicode = """ +\u00a0""" + +multiline_not_unicode = """ +\\u0041""" + +multiline_end_esc = """When will it end? \"""...""\" should be here\"""" + +lit_multiline_not_unicode = ''' +\u007f''' + +lit_multiline_end = '''There is no escape\''')"sv; + static constexpr auto string_unicode_escape = R"(answer4 = "\u03B4" +answer8 = "\U000003B4")"sv; + static constexpr auto string_unicode_literal = R"(answer = "δ")"sv; + +#endif // UNICODE_LITERALS_OK + static constexpr auto table_array_implicit = R"([[albums.songs]] name = "Glory Days")"sv; static constexpr auto table_array_many = R"([[people]] @@ -252,22 +513,40 @@ answer = 42)"sv; # [x.y.z] need these [x.y.z.w] # for this to work [x] # defining a super-table afterwards is ok)"sv; - static constexpr auto underscored_float = R"(electron_mass = 9_109.109_383e-3_4)"sv; - static constexpr auto underscored_integer = R"(million = 1_000_000)"sv; - static constexpr auto unicode_escape = R"(answer4 = "\u03B4" -answer8 = "\U000003B4")"sv; - #if UNICODE_LITERALS_OK - static constexpr auto unicode_literal = R"(answer = "δ")"sv; - #endif // UNICODE_LITERALS_OK + +#if UNICODE_LITERALS_OK + + static constexpr auto table_names = R"([a.b.c] +[a."b.c"] +[a.'d.e'] +[a.' x '] +[ d.e.f ] +[ g . h . i ] +[ j . "ʞ" . 'l' ])"sv; + +#endif // UNICODE_LITERALS_OK } TOML_ENABLE_WARNINGS; TEST_CASE("conformance - burntsushi/valid") { + parsing_should_succeed(FILE_LINE_ARGS, array_bool, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(a)"sv, toml::array{ + true, + false, + } + }, + }}; + REQUIRE(tbl == expected); + }); + parsing_should_succeed(FILE_LINE_ARGS, array_empty, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(thevoid)"sv, toml::array{ toml::inserter{toml::array{ @@ -283,75 +562,9 @@ TEST_CASE("conformance - burntsushi/valid") REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, array_nospaces, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, array_hetergeneous, [](toml::table&& tbl) { - auto expected = toml::table{{ - { - R"(ints)"sv, toml::array{ - 1, - 2, - 3, - } - }, - }}; - REQUIRE(tbl == expected); - }); - - parsing_should_succeed(FILE_LINE_ARGS, array_string_quote_comma_2, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { - R"(title)"sv, toml::array{ - R"( ", )"sv, - } - }, - }}; - REQUIRE(tbl == expected); - }); - - parsing_should_succeed(FILE_LINE_ARGS, array_string_quote_comma, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { - R"(title)"sv, toml::array{ - R"(Client: "XXXX", Job: XXXX)"sv, - R"(Code: XXXX)"sv, - } - }, - }}; - REQUIRE(tbl == expected); - }); - - parsing_should_succeed(FILE_LINE_ARGS, array_string_with_comma, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { - R"(title)"sv, toml::array{ - R"(Client: XXXX, Job: XXXX)"sv, - R"(Code: XXXX)"sv, - } - }, - }}; - REQUIRE(tbl == expected); - }); - - parsing_should_succeed(FILE_LINE_ARGS, array_table_array_string_backslash, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { - R"(foo)"sv, toml::array{ - toml::table{{ - { R"(bar)"sv, R"("{{baz}}")"sv }, - }}, - } - }, - }}; - REQUIRE(tbl == expected); - }); - - parsing_should_succeed(FILE_LINE_ARGS, arrays_hetergeneous, [](toml::table&& tbl) - { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(mixed)"sv, toml::array{ toml::array{ @@ -372,9 +585,50 @@ TEST_CASE("conformance - burntsushi/valid") REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, arrays_nested, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, array_mix_string_table, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ + { + R"(contributors)"sv, toml::array{ + R"(Foo Bar )"sv, + toml::table{{ + { R"(email)"sv, R"(bazqux@example.com)"sv }, + { R"(name)"sv, R"(Baz Qux)"sv }, + { R"(url)"sv, R"(https://example.com/bazqux)"sv }, + }}, + } + }, + { + R"(numbers)"sv, toml::array{ + 0.1, + 0.2, + 0.5, + 1, + 2, + 5, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, array_nested_inline_table, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(a)"sv, toml::array{ + toml::table{{ + { R"(b)"sv, toml::table{} }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, array_nested, [](toml::table&& tbl) + { + const auto expected = toml::table{{ { R"(nest)"sv, toml::array{ toml::array{ @@ -389,9 +643,9 @@ TEST_CASE("conformance - burntsushi/valid") REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, arrays, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, array_nospaces, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(ints)"sv, toml::array{ 1, @@ -399,18 +653,84 @@ TEST_CASE("conformance - burntsushi/valid") 3, } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, array_string_quote_comma_2, [](toml::table&& tbl) + { + const auto expected = toml::table{{ { - R"(floats)"sv, toml::array{ - 1.1, - 2.1, - 3.1, + R"(title)"sv, toml::array{ + R"( ", )"sv, } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, array_string_quote_comma, [](toml::table&& tbl) + { + const auto expected = toml::table{{ { - R"(strings)"sv, toml::array{ - R"(a)"sv, - R"(b)"sv, - R"(c)"sv, + R"(title)"sv, toml::array{ + R"(Client: "XXXX", Job: XXXX)"sv, + R"(Code: XXXX)"sv, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, array_string_with_comma, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(title)"sv, toml::array{ + R"(Client: XXXX, Job: XXXX)"sv, + R"(Code: XXXX)"sv, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, array_strings, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(string_array)"sv, toml::array{ + R"(all)"sv, + R"(strings)"sv, + R"(are the same)"sv, + R"(type)"sv, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, array_table_array_string_backslash, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(foo)"sv, toml::array{ + toml::table{{ + { R"(bar)"sv, R"("{{baz}}")"sv }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, array_, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(comments)"sv, toml::array{ + 1, + 2, } }, { @@ -421,9 +741,24 @@ TEST_CASE("conformance - burntsushi/valid") } }, { - R"(comments)"sv, toml::array{ + R"(floats)"sv, toml::array{ + 1.1, + 2.1, + 3.1, + } + }, + { + R"(ints)"sv, toml::array{ 1, 2, + 3, + } + }, + { + R"(strings)"sv, toml::array{ + R"(a)"sv, + R"(b)"sv, + R"(c)"sv, } }, }}; @@ -432,32 +767,32 @@ TEST_CASE("conformance - burntsushi/valid") parsing_should_succeed(FILE_LINE_ARGS, bool_, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(f)"sv, false }, { R"(t)"sv, true }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, comments_at_eof, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, comment_at_eof, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(key)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, comments_at_eof2, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, comment_at_eof2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(key)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, comments_everywhere, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, comment_everywhere, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(group)"sv, toml::table{{ { R"(answer)"sv, 42 }, @@ -473,39 +808,121 @@ TEST_CASE("conformance - burntsushi/valid") REQUIRE(tbl == expected); }); + parsing_should_succeed(FILE_LINE_ARGS, comment_tricky, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(hash#tag)"sv, toml::table{{ + { R"(#!)"sv, R"(hash bang)"sv }, + { + R"(arr3)"sv, toml::array{ + R"(#)"sv, + R"(#)"sv, + R"(###)"sv, + } + }, + { + R"(arr4)"sv, toml::array{ + 1, + 2, + 3, + 4, + } + }, + { + R"(arr5)"sv, toml::array{ + toml::inserter{toml::array{ + toml::inserter{toml::array{ + toml::inserter{toml::array{ + toml::inserter{toml::array{ + R"(#)"sv, + }}, + }}, + }}, + }}, + } + }, + { + R"(tbl1)"sv, toml::table{{ + { R"(#)"sv, R"(}#)"sv }, + }} + }, + }} + }, + { + R"(section)"sv, toml::table{{ + { R"(8)"sv, R"(eight)"sv }, + { R"(eleven)"sv, 11.1 }, + { R"(five)"sv, 5.5 }, + { R"(four)"sv, R"(# no comment +# nor this +#also not comment)"sv }, + { R"(one)"sv, R"(11)"sv }, + { R"(six)"sv, 6 }, + { R"(ten)"sv, 1000.0 }, + { R"(three)"sv, R"(#)"sv }, + { R"(two)"sv, R"(22#)"sv }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, datetime_local_date, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(bestdayever)"sv, toml::date{ 1987, 7, 5 } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, datetime_local_time, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(besttimeever)"sv, toml::time{ 17, 45, 0, 0 } }, + { R"(milliseconds)"sv, toml::time{ 10, 32, 0, 555000000 } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, datetime_local, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(bestdayever)"sv, toml::date_time{ { 1987, 7, 5 }, { 17, 45, 0, 0u } } }, + { R"(bestdayever_with_space)"sv, toml::date_time{ { 1987, 7, 5 }, { 17, 45, 0, 0u } } }, + { R"(milliseconds)"sv, toml::date_time{ { 1977, 12, 21 }, { 10, 32, 0, 555000000u } } }, + }}; + REQUIRE(tbl == expected); + }); + parsing_should_succeed(FILE_LINE_ARGS, datetime_timezone, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(bestdayever)"sv, toml::date_time{ { 2017, 6, 6 }, { 12, 34, 56, 0u }, { -5, 0 } } }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, double_quote_escape, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, datetime, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(test)"sv, R"("one")"sv }, + const auto expected = toml::table{{ + { R"(bestdayever)"sv, toml::date_time{ { 1987, 7, 5 }, { 17, 45, 0, 0u }, { 0, 0 } } }, + { R"(bestdayever_with_space)"sv, toml::date_time{ { 1987, 7, 5 }, { 17, 45, 0, 0u }, { 0, 0 } } }, + { R"(milliseconds)"sv, toml::date_time{ { 1977, 12, 21 }, { 10, 32, 0, 555000000u }, { 7, 0 } } }, + { R"(numoffset)"sv, toml::date_time{ { 1977, 6, 28 }, { 7, 32, 0, 0u }, { -5, 0 } } }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, empty, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, empty_file, [](toml::table&& tbl) { - auto expected = toml::table{}; - REQUIRE(tbl == expected); - }); - - parsing_should_succeed(FILE_LINE_ARGS, escaped_escape, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { R"(answer)"sv, R"(\x64)"sv }, - }}; + const auto expected = toml::table{}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, example, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(best-day-ever)"sv, toml::date_time{ { 1987, 7, 5 }, { 17, 45, 0, 0u }, { 0, 0 } } }, { R"(numtheory)"sv, toml::table{{ @@ -523,46 +940,73 @@ TEST_CASE("conformance - burntsushi/valid") REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, exponent_part_float, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, float_exponent, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(million)"sv, 1000000.0 }, + const auto expected = toml::table{{ + { R"(lower)"sv, 300.0 }, { R"(minustenth)"sv, -0.1 }, - { R"(beast)"sv, 666.0 }, + { R"(neg)"sv, 0.03 }, + { R"(pointlower)"sv, 310.0 }, + { R"(pointupper)"sv, 310.0 }, + { R"(pos)"sv, 300.0 }, + { R"(upper)"sv, 300.0 }, + { R"(zero)"sv, 3.0 }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, float_exponent, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, float_inf_and_nan, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(lower)"sv, 300.0 }, - { R"(upper)"sv, 300.0 }, - { R"(neg)"sv, 0.03 }, - { R"(pos)"sv, 300.0 }, - { R"(zero)"sv, 3.0 }, - { R"(pointlower)"sv, 310.0 }, - { R"(pointupper)"sv, 310.0 }, + const auto expected = toml::table{{ + { R"(infinity)"sv, std::numeric_limits::infinity() }, + { R"(infinity_neg)"sv, -std::numeric_limits::infinity() }, + { R"(infinity_plus)"sv, std::numeric_limits::infinity() }, + { R"(nan)"sv, std::numeric_limits::quiet_NaN() }, + { R"(nan_neg)"sv, std::numeric_limits::quiet_NaN() }, + { R"(nan_plus)"sv, std::numeric_limits::quiet_NaN() }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, float_long, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(longpi)"sv, 3.141592653589793 }, + { R"(neglongpi)"sv, -3.141592653589793 }, }}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, float_underscore, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(before)"sv, 3141.5927 }, + const auto expected = toml::table{{ { R"(after)"sv, 3141.5927 }, + { R"(before)"sv, 3141.5927 }, { R"(exponent)"sv, 300000000000000.0 }, }}; REQUIRE(tbl == expected); }); + parsing_should_succeed(FILE_LINE_ARGS, float_zero, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(f1)"sv, 0.0 }, + { R"(f2)"sv, 0.0 }, + { R"(f3)"sv, 0.0 }, + { R"(f4)"sv, 0.0 }, + { R"(f5)"sv, 0.0 }, + { R"(f6)"sv, 0.0 }, + { R"(f7)"sv, 0.0 }, + }}; + REQUIRE(tbl == expected); + }); + parsing_should_succeed(FILE_LINE_ARGS, float_, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ + { R"(negpi)"sv, -3.14 }, { R"(pi)"sv, 3.14 }, { R"(pospi)"sv, 3.14 }, - { R"(negpi)"sv, -3.14 }, { R"(zero-intpart)"sv, 0.123 }, }}; REQUIRE(tbl == expected); @@ -570,10 +1014,9 @@ TEST_CASE("conformance - burntsushi/valid") parsing_should_succeed(FILE_LINE_ARGS, implicit_and_explicit_after, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ - { R"(better)"sv, 43 }, { R"(b)"sv, toml::table{{ { @@ -583,6 +1026,7 @@ TEST_CASE("conformance - burntsushi/valid") }, }} }, + { R"(better)"sv, 43 }, }} }, }}; @@ -591,10 +1035,9 @@ TEST_CASE("conformance - burntsushi/valid") parsing_should_succeed(FILE_LINE_ARGS, implicit_and_explicit_before, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ - { R"(better)"sv, 43 }, { R"(b)"sv, toml::table{{ { @@ -604,6 +1047,7 @@ TEST_CASE("conformance - burntsushi/valid") }, }} }, + { R"(better)"sv, 43 }, }} }, }}; @@ -612,7 +1056,7 @@ TEST_CASE("conformance - burntsushi/valid") parsing_should_succeed(FILE_LINE_ARGS, implicit_groups, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ { @@ -632,7 +1076,7 @@ TEST_CASE("conformance - burntsushi/valid") parsing_should_succeed(FILE_LINE_ARGS, inline_table_array, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(people)"sv, toml::array{ toml::table{{ @@ -653,9 +1097,161 @@ TEST_CASE("conformance - burntsushi/valid") REQUIRE(tbl == expected); }); + parsing_should_succeed(FILE_LINE_ARGS, inline_table_bool, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(a)"sv, toml::table{{ + { R"(a)"sv, true }, + { R"(b)"sv, false }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, inline_table_empty, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(empty1)"sv, toml::table{} }, + { R"(empty2)"sv, toml::table{} }, + { + R"(empty_in_array)"sv, toml::array{ + toml::table{{ + { R"(not_empty)"sv, 1 }, + }}, + toml::table{}, + } + }, + { + R"(empty_in_array2)"sv, toml::array{ + toml::table{}, + toml::table{{ + { R"(not_empty)"sv, 1 }, + }}, + } + }, + { + R"(many_empty)"sv, toml::array{ + toml::table{}, + toml::table{}, + toml::table{}, + } + }, + { + R"(nested_empty)"sv, toml::table{{ + { R"(empty)"sv, toml::table{} }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, inline_table_end_in_bool, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(black)"sv, toml::table{{ + { R"(allow_prereleases)"sv, true }, + { R"(python)"sv, R"(>3.6)"sv }, + { R"(version)"sv, R"(>=18.9b0)"sv }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, inline_table_multiline, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(tbl_multiline)"sv, toml::table{{ + { R"(a)"sv, 1 }, + { R"(b)"sv, R"(multiline +)"sv }, + { R"(c)"sv, R"(and yet +another line)"sv }, + { R"(d)"sv, 4 }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, inline_table_nest, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(arr_arr_tbl_empty)"sv, toml::array{ + toml::inserter{toml::array{ + toml::table{}, + }}, + } + }, + { + R"(arr_arr_tbl_val)"sv, toml::array{ + toml::inserter{toml::array{ + toml::table{{ + { R"(one)"sv, 1 }, + }}, + }}, + } + }, + { + R"(arr_arr_tbls)"sv, toml::array{ + toml::inserter{toml::array{ + toml::table{{ + { R"(one)"sv, 1 }, + }}, + toml::table{{ + { R"(two)"sv, 2 }, + }}, + }}, + } + }, + { + R"(arr_tbl_tbl)"sv, toml::array{ + toml::table{{ + { + R"(tbl)"sv, toml::table{{ + { R"(one)"sv, 1 }, + }} + }, + }}, + } + }, + { + R"(tbl_arr_tbl)"sv, toml::table{{ + { + R"(arr_tbl)"sv, toml::array{ + toml::table{{ + { R"(one)"sv, 1 }, + }}, + } + }, + }} + }, + { + R"(tbl_tbl_empty)"sv, toml::table{{ + { R"(tbl_0)"sv, toml::table{} }, + }} + }, + { + R"(tbl_tbl_val)"sv, toml::table{{ + { + R"(tbl_1)"sv, toml::table{{ + { R"(one)"sv, 1 }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + parsing_should_succeed(FILE_LINE_ARGS, inline_table, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(name)"sv, toml::table{{ { R"(first)"sv, R"(Tom)"sv }, @@ -692,17 +1288,62 @@ TEST_CASE("conformance - burntsushi/valid") REQUIRE(tbl == expected); }); + parsing_should_succeed(FILE_LINE_ARGS, integer_literals, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(bin1)"sv, 214 }, + { R"(bin2)"sv, 5 }, + { R"(hex1)"sv, 3735928559 }, + { R"(hex2)"sv, 3735928559 }, + { R"(hex3)"sv, 3735928559 }, + { R"(hex4)"sv, 2439 }, + { R"(oct1)"sv, 342391 }, + { R"(oct2)"sv, 493 }, + { R"(oct3)"sv, 501 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, integer_long, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(int64-max)"sv, INT64_MAX }, + { R"(int64-max-neg)"sv, INT64_MIN }, + }}; + REQUIRE(tbl == expected); + }); + parsing_should_succeed(FILE_LINE_ARGS, integer_underscore, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(kilo)"sv, 1000 }, + { R"(x)"sv, 1111 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, integer_zero, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(a2)"sv, 0 }, + { R"(a3)"sv, 0 }, + { R"(b1)"sv, 0 }, + { R"(b2)"sv, 0 }, + { R"(b3)"sv, 0 }, + { R"(d1)"sv, 0 }, + { R"(d2)"sv, 0 }, + { R"(d3)"sv, 0 }, + { R"(h1)"sv, 0 }, + { R"(h2)"sv, 0 }, + { R"(h3)"sv, 0 }, + { R"(o1)"sv, 0 }, }}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, integer, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(answer)"sv, 42 }, { R"(neganswer)"sv, -42 }, { R"(posanswer)"sv, 42 }, @@ -711,9 +1352,175 @@ TEST_CASE("conformance - burntsushi/valid") REQUIRE(tbl == expected); }); +#if UNICODE_LITERALS_OK + + parsing_should_succeed(FILE_LINE_ARGS, key_case_sensitive, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(Section)"sv, toml::table{{ + { R"(M)"sv, R"(latin letter M)"sv }, + { R"(name)"sv, R"(different section!!)"sv }, + { R"(Μ)"sv, R"(greek capital letter MU)"sv }, + { R"(μ)"sv, R"(greek small letter mu)"sv }, + }} + }, + { R"(sectioN)"sv, R"(NN)"sv }, + { + R"(section)"sv, toml::table{{ + { R"(NAME)"sv, R"(upper)"sv }, + { R"(Name)"sv, R"(capitalized)"sv }, + { R"(name)"sv, R"(lower)"sv }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, key_escapes, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"( +)"sv, R"(newline)"sv }, + { R"(")"sv, R"(just a quote)"sv }, + { + R"("quoted")"sv, toml::table{{ + { R"(quote)"sv, true }, + }} + }, + { + R"(a.b)"sv, toml::table{{ + { R"(À)"sv, toml::table{} }, + }} + }, + { R"(backsp)"sv, toml::table{} }, + { R"(À)"sv, R"(latin capital letter A with grave)"sv }, + }}; + REQUIRE(tbl == expected); + }); + +#endif // UNICODE_LITERALS_OK + + parsing_should_succeed(FILE_LINE_ARGS, key_dotted, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(a)"sv, toml::table{{ + { + R"(few)"sv, toml::table{{ + { + R"(dots)"sv, toml::table{{ + { + R"(polka)"sv, toml::table{{ + { R"(dance-with)"sv, R"(Dot)"sv }, + { R"(dot)"sv, R"(again?)"sv }, + }} + }, + }} + }, + }} + }, + }} + }, + { + R"(arr)"sv, toml::array{ + toml::table{{ + { + R"(a)"sv, toml::table{{ + { + R"(b)"sv, toml::table{{ + { R"(c)"sv, 1 }, + { R"(d)"sv, 2 }, + }} + }, + }} + }, + }}, + toml::table{{ + { + R"(a)"sv, toml::table{{ + { + R"(b)"sv, toml::table{{ + { R"(c)"sv, 3 }, + { R"(d)"sv, 4 }, + }} + }, + }} + }, + }}, + } + }, + { + R"(count)"sv, toml::table{{ + { R"(a)"sv, 1 }, + { R"(b)"sv, 2 }, + { R"(c)"sv, 3 }, + { R"(d)"sv, 4 }, + { R"(e)"sv, 5 }, + { R"(f)"sv, 6 }, + { R"(g)"sv, 7 }, + { R"(h)"sv, 8 }, + { R"(i)"sv, 9 }, + { R"(j)"sv, 10 }, + { R"(k)"sv, 11 }, + { R"(l)"sv, 12 }, + }} + }, + { + R"(many)"sv, toml::table{{ + { + R"(dots)"sv, toml::table{{ + { + R"(here)"sv, toml::table{{ + { + R"(dot)"sv, toml::table{{ + { + R"(dot)"sv, toml::table{{ + { R"(dot)"sv, 42 }, + }} + }, + }} + }, + }} + }, + }} + }, + }} + }, + { + R"(name)"sv, toml::table{{ + { R"(first)"sv, R"(Arthur)"sv }, + { R"(last)"sv, R"(Dent)"sv }, + }} + }, + { + R"(tbl)"sv, toml::table{{ + { + R"(a)"sv, toml::table{{ + { + R"(b)"sv, toml::table{{ + { R"(c)"sv, 42.666 }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, key_empty, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"()"sv, R"(blank)"sv }, + }}; + REQUIRE(tbl == expected); + }); + parsing_should_succeed(FILE_LINE_ARGS, key_equals_nospace, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(answer)"sv, 42 }, }}; REQUIRE(tbl == expected); @@ -721,33 +1528,16 @@ TEST_CASE("conformance - burntsushi/valid") parsing_should_succeed(FILE_LINE_ARGS, key_numeric, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(1)"sv, 1 }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, key_space, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, key_quoted_dots, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(a b)"sv, 1 }, - }}; - REQUIRE(tbl == expected); - }); - - parsing_should_succeed(FILE_LINE_ARGS, key_special_chars, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { R"(~!@$^&*()_+-`1234567890[]|/?><.,;:')"sv, 1 }, - }}; - REQUIRE(tbl == expected); - }); - - parsing_should_succeed(FILE_LINE_ARGS, keys_with_dots, [](toml::table&& tbl) - { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(plain)"sv, 1 }, - { R"(with.dot)"sv, 2 }, { R"(plain_table)"sv, toml::table{{ { R"(plain)"sv, 3 }, @@ -758,147 +1548,280 @@ TEST_CASE("conformance - burntsushi/valid") R"(table)"sv, toml::table{{ { R"(withdot)"sv, toml::table{{ - { R"(plain)"sv, 5 }, { R"(key.with.dots)"sv, 6 }, + { R"(plain)"sv, 5 }, }} }, }} }, + { R"(with.dot)"sv, 2 }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, long_float, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, key_space, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(longpi)"sv, 3.141592653589793 }, - { R"(neglongpi)"sv, -3.141592653589793 }, + const auto expected = toml::table{{ + { R"(a b)"sv, 1 }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, long_integer, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, key_special_chars, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(answer)"sv, INT64_MAX }, - { R"(neganswer)"sv, INT64_MIN }, + const auto expected = toml::table{{ + { R"(~!@$^&*()_+-`1234567890[]|/?><.,;:')"sv, 1 }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, multiline_string, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, key_special_word, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(multiline_empty_one)"sv, R"()"sv }, - { R"(multiline_empty_two)"sv, R"()"sv }, - { R"(multiline_empty_three)"sv, R"()"sv }, - { R"(multiline_empty_four)"sv, R"()"sv }, - { R"(equivalent_one)"sv, R"(The quick brown fox jumps over the lazy dog.)"sv }, - { R"(equivalent_two)"sv, R"(The quick brown fox jumps over the lazy dog.)"sv }, - { R"(equivalent_three)"sv, R"(The quick brown fox jumps over the lazy dog.)"sv }, + const auto expected = toml::table{{ + { R"(false)"sv, false }, + { R"(inf)"sv, 100000000 }, + { R"(nan)"sv, R"(ceci n'est pas un nombre)"sv }, + { R"(true)"sv, 1 }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, nested_inline_table_array, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, multiline_string_quotes, [](toml::table&& tbl) { - auto expected = toml::table{{ - { - R"(a)"sv, toml::array{ - toml::table{{ - { R"(b)"sv, toml::table{} }, - }}, - } - }, + const auto expected = toml::table{{ + { R"(lit_one)"sv, R"('one quote')"sv }, + { R"(lit_one_space)"sv, R"( 'one quote' )"sv }, + { R"(lit_two)"sv, R"(''two quotes'')"sv }, + { R"(lit_two_space)"sv, R"( ''two quotes'' )"sv }, + { R"(mismatch1)"sv, R"(aaa'''bbb)"sv }, + { R"(mismatch2)"sv, R"(aaa"""bbb)"sv }, + { R"(one)"sv, R"("one quote")"sv }, + { R"(one_space)"sv, R"( "one quote" )"sv }, + { R"(two)"sv, R"(""two quotes"")"sv }, + { R"(two_space)"sv, R"( ""two quotes"" )"sv }, }}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, newline_crlf, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(os)"sv, R"(DOS)"sv }, + const auto expected = toml::table{{ { R"(newline)"sv, R"(crlf)"sv }, + { R"(os)"sv, R"(DOS)"sv }, }}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, newline_lf, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(os)"sv, R"(unix)"sv }, + const auto expected = toml::table{{ { R"(newline)"sv, R"(lf)"sv }, + { R"(os)"sv, R"(unix)"sv }, }}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, raw_multiline_string, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(oneline)"sv, R"(This string has a ' quote character.)"sv }, + const auto expected = toml::table{{ { R"(firstnl)"sv, R"(This string has a ' quote character.)"sv }, { R"(multiline)"sv, R"(This string has ' a quote character and more than one newline in it.)"sv }, + { R"(oneline)"sv, R"(This string has a ' quote character.)"sv }, }}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, raw_string, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(backspace)"sv, R"(This string has a \b backspace character.)"sv }, - { R"(tab)"sv, R"(This string has a \t tab character.)"sv }, - { R"(newline)"sv, R"(This string has a \n new line character.)"sv }, - { R"(formfeed)"sv, R"(This string has a \f form feed character.)"sv }, - { R"(carriage)"sv, R"(This string has a \r carriage return character.)"sv }, - { R"(slash)"sv, R"(This string has a \/ slash character.)"sv }, + const auto expected = toml::table{{ { R"(backslash)"sv, R"(This string has a \\ backslash character.)"sv }, + { R"(backspace)"sv, R"(This string has a \b backspace character.)"sv }, + { R"(carriage)"sv, R"(This string has a \r carriage return character.)"sv }, + { R"(formfeed)"sv, R"(This string has a \f form feed character.)"sv }, + { R"(newline)"sv, R"(This string has a \n new line character.)"sv }, + { R"(slash)"sv, R"(This string has a \/ slash character.)"sv }, + { R"(tab)"sv, R"(This string has a \t tab character.)"sv }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, right_curly_brace_after_boolean, [](toml::table&& tbl) + parsing_should_succeed(FILE_LINE_ARGS, spec_example_1_compact, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { - R"(black)"sv, toml::table{{ - { R"(allow_prereleases)"sv, true }, - { R"(python)"sv, R"(>3.6)"sv }, - { R"(version)"sv, R"(>=18.9b0)"sv }, + R"(clients)"sv, toml::table{{ + { + R"(data)"sv, toml::array{ + toml::array{ + R"(gamma)"sv, + R"(delta)"sv, + }, + toml::array{ + 1, + 2, + }, + } + }, + { + R"(hosts)"sv, toml::array{ + R"(alpha)"sv, + R"(omega)"sv, + } + }, }} }, + { + R"(database)"sv, toml::table{{ + { R"(connection_max)"sv, 5000 }, + { R"(enabled)"sv, true }, + { + R"(ports)"sv, toml::array{ + 8001, + 8001, + 8002, + } + }, + { R"(server)"sv, R"(192.168.1.1)"sv }, + }} + }, + { + R"(owner)"sv, toml::table{{ + { R"(dob)"sv, toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u }, { -8, 0 } } }, + { R"(name)"sv, R"(Lance Uppercut)"sv }, + }} + }, + { + R"(servers)"sv, toml::table{{ + { + R"(alpha)"sv, toml::table{{ + { R"(dc)"sv, R"(eqdc10)"sv }, + { R"(ip)"sv, R"(10.0.0.1)"sv }, + }} + }, + { + R"(beta)"sv, toml::table{{ + { R"(dc)"sv, R"(eqdc10)"sv }, + { R"(ip)"sv, R"(10.0.0.2)"sv }, + }} + }, + }} + }, + { R"(title)"sv, R"(TOML Example)"sv }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, spec_example_1, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(clients)"sv, toml::table{{ + { + R"(data)"sv, toml::array{ + toml::array{ + R"(gamma)"sv, + R"(delta)"sv, + }, + toml::array{ + 1, + 2, + }, + } + }, + { + R"(hosts)"sv, toml::array{ + R"(alpha)"sv, + R"(omega)"sv, + } + }, + }} + }, + { + R"(database)"sv, toml::table{{ + { R"(connection_max)"sv, 5000 }, + { R"(enabled)"sv, true }, + { + R"(ports)"sv, toml::array{ + 8001, + 8001, + 8002, + } + }, + { R"(server)"sv, R"(192.168.1.1)"sv }, + }} + }, + { + R"(owner)"sv, toml::table{{ + { R"(dob)"sv, toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u }, { -8, 0 } } }, + { R"(name)"sv, R"(Lance Uppercut)"sv }, + }} + }, + { + R"(servers)"sv, toml::table{{ + { + R"(alpha)"sv, toml::table{{ + { R"(dc)"sv, R"(eqdc10)"sv }, + { R"(ip)"sv, R"(10.0.0.1)"sv }, + }} + }, + { + R"(beta)"sv, toml::table{{ + { R"(dc)"sv, R"(eqdc10)"sv }, + { R"(ip)"sv, R"(10.0.0.2)"sv }, + }} + }, + }} + }, + { R"(title)"sv, R"(TOML Example)"sv }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, string_double_quote_escape, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(test)"sv, R"("one")"sv }, }}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, string_empty, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(answer)"sv, R"()"sv }, }}; REQUIRE(tbl == expected); }); + parsing_should_succeed(FILE_LINE_ARGS, string_escaped_escape, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(answer)"sv, R"(\x64)"sv }, + }}; + REQUIRE(tbl == expected); + }); + parsing_should_succeed(FILE_LINE_ARGS, string_nl, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(nl_mid)"sv, R"(val -ue)"sv }, - { R"(nl_end)"sv, R"(value -)"sv }, + const auto expected = toml::table{{ { R"(lit_nl_end)"sv, R"(value\n)"sv }, { R"(lit_nl_mid)"sv, R"(val\nue)"sv }, { R"(lit_nl_uni)"sv, R"(val\ue)"sv }, + { R"(nl_end)"sv, R"(value +)"sv }, + { R"(nl_mid)"sv, R"(val +ue)"sv }, }}; REQUIRE(tbl == expected); }); parsing_should_succeed(FILE_LINE_ARGS, string_simple, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(answer)"sv, R"(You are not drinking enough whisky.)"sv }, }}; REQUIRE(tbl == expected); @@ -906,16 +1829,51 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, string_with_pound, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(pound)"sv, R"(We see no # comments here.)"sv }, { R"(poundcomment)"sv, R"(But there are # some comments here.)"sv }, }}; REQUIRE(tbl == expected); }); +#if UNICODE_LITERALS_OK + + parsing_should_succeed(FILE_LINE_ARGS, string_escape_tricky, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(end_esc)"sv, R"(String does not end here" but ends here\)"sv }, + { R"(lit_end_esc)"sv, R"(String ends here\)"sv }, + { R"(lit_multiline_end)"sv, R"(There is no escape\)"sv }, + { R"(lit_multiline_not_unicode)"sv, R"(\u007f)"sv }, + { R"(multiline_end_esc)"sv, R"(When will it end? """...""" should be here")"sv }, + { R"(multiline_not_unicode)"sv, R"(\u0041)"sv }, + { R"(multiline_unicode)"sv, R"( )"sv }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, string_unicode_escape, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(answer4)"sv, R"(δ)"sv }, + { R"(answer8)"sv, R"(δ)"sv }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, string_unicode_literal, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(answer)"sv, R"(δ)"sv }, + }}; + REQUIRE(tbl == expected); + }); + +#endif // UNICODE_LITERALS_OK + parsing_should_succeed(FILE_LINE_ARGS, table_array_implicit, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(albums)"sv, toml::table{{ { @@ -933,7 +1891,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_array_many, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(people)"sv, toml::array{ toml::table{{ @@ -956,7 +1914,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_array_nest, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(albums)"sv, toml::array{ toml::table{{ @@ -993,7 +1951,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_array_one, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(people)"sv, toml::array{ toml::table{{ @@ -1008,7 +1966,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_array_table_array, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::array{ toml::table{{ @@ -1039,7 +1997,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_empty, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{} }, }}; REQUIRE(tbl == expected); @@ -1047,7 +2005,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_no_eol, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(table)"sv, toml::table{} }, }}; REQUIRE(tbl == expected); @@ -1055,7 +2013,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_sub_empty, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ { R"(b)"sv, toml::table{} }, @@ -1067,7 +2025,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_whitespace, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(valid key)"sv, toml::table{} }, }}; REQUIRE(tbl == expected); @@ -1075,7 +2033,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_with_literal_string, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ { @@ -1095,7 +2053,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_with_pound, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(key#group)"sv, toml::table{{ { R"(answer)"sv, 42 }, @@ -1107,7 +2065,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_with_single_quotes, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ { @@ -1127,7 +2085,7 @@ ue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, table_without_super, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(x)"sv, toml::table{{ { @@ -1145,42 +2103,54 @@ ue)"sv }, REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, underscored_float, [](toml::table&& tbl) +#if UNICODE_LITERALS_OK + + parsing_should_succeed(FILE_LINE_ARGS, table_names, [](toml::table&& tbl) { - auto expected = toml::table{{ - { R"(electron_mass)"sv, 9.109109383e-31 }, + const auto expected = toml::table{{ + { + R"(a)"sv, toml::table{{ + { R"( x )"sv, toml::table{} }, + { + R"(b)"sv, toml::table{{ + { R"(c)"sv, toml::table{} }, + }} + }, + { R"(b.c)"sv, toml::table{} }, + { R"(d.e)"sv, toml::table{} }, + }} + }, + { + R"(d)"sv, toml::table{{ + { + R"(e)"sv, toml::table{{ + { R"(f)"sv, toml::table{} }, + }} + }, + }} + }, + { + R"(g)"sv, toml::table{{ + { + R"(h)"sv, toml::table{{ + { R"(i)"sv, toml::table{} }, + }} + }, + }} + }, + { + R"(j)"sv, toml::table{{ + { + R"(ʞ)"sv, toml::table{{ + { R"(l)"sv, toml::table{} }, + }} + }, + }} + }, }}; REQUIRE(tbl == expected); }); - parsing_should_succeed(FILE_LINE_ARGS, underscored_integer, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { R"(million)"sv, 1000000 }, - }}; - REQUIRE(tbl == expected); - }); - - #if UNICODE_LITERALS_OK - parsing_should_succeed(FILE_LINE_ARGS, unicode_escape, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { R"(answer4)"sv, R"(δ)"sv }, - { R"(answer8)"sv, R"(δ)"sv }, - }}; - REQUIRE(tbl == expected); - }); - #endif // UNICODE_LITERALS_OK - - #if UNICODE_LITERALS_OK - parsing_should_succeed(FILE_LINE_ARGS, unicode_literal, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { R"(answer)"sv, R"(δ)"sv }, - }}; - REQUIRE(tbl == expected); - }); - #endif // UNICODE_LITERALS_OK - +#endif // UNICODE_LITERALS_OK } diff --git a/tests/conformance_iarna_invalid.cpp b/tests/conformance_iarna_invalid.cpp index 7601643..948f3ab 100644 --- a/tests/conformance_iarna_invalid.cpp +++ b/tests/conformance_iarna_invalid.cpp @@ -26,23 +26,33 @@ fruit = [] # This table conflicts with the previous table [fruit.variety] name = "granny smith")"sv; + static constexpr auto bare_key_1 = R"(bare!key = 123)"sv; static constexpr auto bare_key_2 = R"(barekey = 123)"sv; static constexpr auto bare_key_3 = R"(barekey =)"sv; + static constexpr auto inline_table_imutable_1 = R"([product] type = { name = "Nail" } type.edible = false # INVALID)"sv; static constexpr auto inline_table_imutable_2 = R"([product] type.name = "Nail" type = { edible = false } # INVALID)"sv; + +#if !TOML_LANG_UNRELEASED + static constexpr auto inline_table_trailing_comma = R"(abc = { abc = 123, })"sv; + +#endif // !TOML_LANG_UNRELEASED + static constexpr auto int_0_padded = R"(int = 0123)"sv; static constexpr auto int_signed_bin = R"(bin = +0b10)"sv; static constexpr auto int_signed_hex = R"(hex = +0xab)"sv; static constexpr auto int_signed_oct = R"(oct = +0o23)"sv; + static constexpr auto key_value_pair_1 = R"(key = # INVALID)"sv; static constexpr auto key_value_pair_2 = R"(first = "Tom" last = "Preston-Werner" # INVALID)"sv; + static constexpr auto multiple_dot_key = R"(# THE FOLLOWING IS INVALID # This defines the value of fruit.apple to be an integer. @@ -54,7 +64,9 @@ fruit.apple.smooth = true)"sv; static constexpr auto multiple_key = R"(# DO NOT DO THIS name = "Tom" name = "Pradyun")"sv; + static constexpr auto no_key_name = R"(= "no key name" # INVALID)"sv; + static constexpr auto string_basic_multiline_invalid_backslash = R"(a = """ foo \ \n bar""")"sv; @@ -66,6 +78,7 @@ name = "Pradyun")"sv; static constexpr auto string_basic_out_of_range_unicode_escape_2 = R"(a = "\U00D80000")"sv; static constexpr auto string_basic_unknown_escape = R"(a = "\@")"sv; static constexpr auto string_literal_multiline_quotes = R"(apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID)"sv; + static constexpr auto table_1 = R"(# DO NOT DO THIS [fruit] @@ -136,41 +149,75 @@ TOML_ENABLE_WARNINGS; TEST_CASE("conformance - iarna/invalid") { parsing_should_fail(FILE_LINE_ARGS, array_of_tables_1); - parsing_should_fail(FILE_LINE_ARGS, array_of_tables_2); - parsing_should_fail(FILE_LINE_ARGS, bare_key_1); - parsing_should_fail(FILE_LINE_ARGS, bare_key_2); - parsing_should_fail(FILE_LINE_ARGS, bare_key_3); - parsing_should_fail(FILE_LINE_ARGS, inline_table_imutable_1); - parsing_should_fail(FILE_LINE_ARGS, inline_table_imutable_2); - parsing_should_fail(FILE_LINE_ARGS, int_0_padded); - parsing_should_fail(FILE_LINE_ARGS, int_signed_bin); - parsing_should_fail(FILE_LINE_ARGS, int_signed_hex); - parsing_should_fail(FILE_LINE_ARGS, int_signed_oct); - parsing_should_fail(FILE_LINE_ARGS, key_value_pair_1); - parsing_should_fail(FILE_LINE_ARGS, key_value_pair_2); - parsing_should_fail(FILE_LINE_ARGS, multiple_dot_key); - parsing_should_fail(FILE_LINE_ARGS, multiple_key); - parsing_should_fail(FILE_LINE_ARGS, no_key_name); - parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_invalid_backslash); - parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_1); - parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_2); - parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_quotes); - parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_unknown_escape); - parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_1); - parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_2); - parsing_should_fail(FILE_LINE_ARGS, string_basic_unknown_escape); - parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_quotes); - parsing_should_fail(FILE_LINE_ARGS, table_1); - parsing_should_fail(FILE_LINE_ARGS, table_2); - parsing_should_fail(FILE_LINE_ARGS, table_3); - parsing_should_fail(FILE_LINE_ARGS, table_4); - parsing_should_fail(FILE_LINE_ARGS, table_invalid_1); - parsing_should_fail(FILE_LINE_ARGS, table_invalid_2); - parsing_should_fail(FILE_LINE_ARGS, table_invalid_3); - parsing_should_fail(FILE_LINE_ARGS, table_invalid_4); - #if !TOML_LANG_UNRELEASED + parsing_should_fail(FILE_LINE_ARGS, array_of_tables_2); + + parsing_should_fail(FILE_LINE_ARGS, bare_key_1); + + parsing_should_fail(FILE_LINE_ARGS, bare_key_2); + + parsing_should_fail(FILE_LINE_ARGS, bare_key_3); + + parsing_should_fail(FILE_LINE_ARGS, inline_table_imutable_1); + + parsing_should_fail(FILE_LINE_ARGS, inline_table_imutable_2); + +#if !TOML_LANG_UNRELEASED + parsing_should_fail(FILE_LINE_ARGS, inline_table_trailing_comma); - #endif // !TOML_LANG_UNRELEASED + +#endif // !TOML_LANG_UNRELEASED + + parsing_should_fail(FILE_LINE_ARGS, int_0_padded); + + parsing_should_fail(FILE_LINE_ARGS, int_signed_bin); + + parsing_should_fail(FILE_LINE_ARGS, int_signed_hex); + + parsing_should_fail(FILE_LINE_ARGS, int_signed_oct); + + parsing_should_fail(FILE_LINE_ARGS, key_value_pair_1); + + parsing_should_fail(FILE_LINE_ARGS, key_value_pair_2); + + parsing_should_fail(FILE_LINE_ARGS, multiple_dot_key); + + parsing_should_fail(FILE_LINE_ARGS, multiple_key); + + parsing_should_fail(FILE_LINE_ARGS, no_key_name); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_invalid_backslash); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_1); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_2); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_quotes); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_unknown_escape); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_1); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_2); + + parsing_should_fail(FILE_LINE_ARGS, string_basic_unknown_escape); + + parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_quotes); + + parsing_should_fail(FILE_LINE_ARGS, table_1); + + parsing_should_fail(FILE_LINE_ARGS, table_2); + + parsing_should_fail(FILE_LINE_ARGS, table_3); + + parsing_should_fail(FILE_LINE_ARGS, table_4); + + parsing_should_fail(FILE_LINE_ARGS, table_invalid_1); + + parsing_should_fail(FILE_LINE_ARGS, table_invalid_2); + + parsing_should_fail(FILE_LINE_ARGS, table_invalid_3); + + parsing_should_fail(FILE_LINE_ARGS, table_invalid_4); } diff --git a/tests/conformance_iarna_valid.cpp b/tests/conformance_iarna_valid.cpp index 2855971..1d63f95 100644 --- a/tests/conformance_iarna_valid.cpp +++ b/tests/conformance_iarna_valid.cpp @@ -156,9 +156,6 @@ orange.color = "orange")"sv; static constexpr auto spec_key_value_pair_7 = R"(_=1)"sv; static constexpr auto spec_key_value_pair_8 = R"(-_-_-_-_-=1)"sv; static constexpr auto spec_key_value_pair_9 = R"(3.14159 = "pi")"sv; - #if UNICODE_LITERALS_OK - static constexpr auto spec_quoted_basic_keys_1 = R"("ʎǝʞ" = "value")"sv; - #endif // UNICODE_LITERALS_OK static constexpr auto spec_quoted_literal_keys_1 = R"('quoted "value"' = "value")"sv; static constexpr auto spec_readme_example = R"(# This is a TOML document. @@ -218,7 +215,6 @@ The quick brown \ static constexpr auto spec_string_basic_multiline_9 = R"(str7 = """"This," she said, "is just a pointless statement."""")"sv; static constexpr auto spec_string_basic_tab_multiline = R"(str = """This is a tab""")"sv; static constexpr auto spec_string_basic_tab = R"(str = "This is a tab")"sv; - static constexpr auto spec_string_basic = R"(str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")"sv; static constexpr auto spec_string_literal_1 = R"(winpath = 'C:\Users\nodejs\templates')"sv; static constexpr auto spec_string_literal_2 = R"(winpath2 = '\\ServerX\admin$\system32\')"sv; static constexpr auto spec_string_literal_3 = R"(quoted = 'Tom "Dubs" Preston-Werner')"sv; @@ -244,9 +240,6 @@ type.name = "pug")"sv; static constexpr auto spec_table_3 = R"([a.b.c])"sv; static constexpr auto spec_table_4 = R"([ d.e.f ] # same as [d.e.f])"sv; static constexpr auto spec_table_5 = R"([ g . h . i ] # same as [g.h.i])"sv; - #if UNICODE_LITERALS_OK - static constexpr auto spec_table_6 = R"([ j . "ʞ" . 'l' ] # same as [j."ʞ".'l'])"sv; - #endif // UNICODE_LITERALS_OK static constexpr auto spec_table_7 = R"(# [x] you # [x.y] don't # [x.y.z] need these @@ -263,6 +256,14 @@ smooth = true)"sv; static constexpr auto spec_table_inline_3 = R"(animal = { type.name = "pug" })"sv; static constexpr auto spec_table = R"([table])"sv; static constexpr auto spec_time_1 = R"(lt1 = 07:32:00)"sv; + +#if UNICODE_LITERALS_OK + + static constexpr auto spec_quoted_basic_keys_1 = R"("ʎǝʞ" = "value")"sv; + static constexpr auto spec_string_basic = R"(str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")"sv; + static constexpr auto spec_table_6 = R"([ j . "ʞ" . 'l' ] # same as [j."ʞ".'l'])"sv; + +#endif // UNICODE_LITERALS_OK } TOML_ENABLE_WARNINGS; @@ -271,7 +272,7 @@ TEST_CASE("conformance - iarna/valid") { parsing_should_succeed(FILE_LINE_ARGS, spec_array_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(integers)"sv, toml::array{ 1, @@ -285,7 +286,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(colors)"sv, toml::array{ R"(red)"sv, @@ -299,7 +300,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(nested_array_of_int)"sv, toml::array{ toml::array{ @@ -319,7 +320,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_4, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(string_array)"sv, toml::array{ R"(all)"sv, @@ -334,7 +335,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_5, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(nested_mixed_array)"sv, toml::array{ toml::array{ @@ -354,7 +355,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_7, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(integers2)"sv, toml::array{ 1, @@ -368,7 +369,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_8, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(integers3)"sv, toml::array{ 1, @@ -381,7 +382,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_mixed_number_types, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(numbers)"sv, toml::array{ 0.1, @@ -398,7 +399,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_more_mixed_types, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(contributors)"sv, toml::array{ R"(Foo Bar )"sv, @@ -415,7 +416,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_of_tables_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(products)"sv, toml::array{ toml::table{{ @@ -436,7 +437,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_of_tables_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(fruit)"sv, toml::array{ toml::table{{ @@ -476,7 +477,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_array_of_tables_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(points)"sv, toml::array{ toml::table{{ @@ -502,7 +503,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_boolean_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(bool1)"sv, true }, }}; REQUIRE(tbl == expected); @@ -510,7 +511,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_boolean_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(bool1)"sv, false }, }}; REQUIRE(tbl == expected); @@ -518,7 +519,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_case_sensitive, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(abc)"sv, 123 }, { R"(ABC)"sv, 456 }, }}; @@ -527,7 +528,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_comment_mid_array, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(abc)"sv, toml::array{ 123, @@ -540,7 +541,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_comment_mid_string, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(another)"sv, R"(# This is not a comment)"sv }, }}; REQUIRE(tbl == expected); @@ -548,7 +549,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_comment_tab, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(key)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); @@ -556,7 +557,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_comment, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(key)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); @@ -564,7 +565,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_date_local_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(ld1)"sv, toml::date{ 1979, 5, 27 } }, }}; REQUIRE(tbl == expected); @@ -572,7 +573,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_date_time_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(odt1)"sv, toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u }, { 0, 0 } } }, }}; REQUIRE(tbl == expected); @@ -580,7 +581,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_date_time_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(odt2)"sv, toml::date_time{ { 1979, 5, 27 }, { 0, 32, 0, 0u }, { -7, 0 } } }, }}; REQUIRE(tbl == expected); @@ -588,7 +589,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_date_time_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(odt3)"sv, toml::date_time{ { 1979, 5, 27 }, { 0, 32, 0, 999999000u }, { -7, 0 } } }, }}; REQUIRE(tbl == expected); @@ -596,7 +597,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_date_time_4, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(odt4)"sv, toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u }, { 0, 0 } } }, }}; REQUIRE(tbl == expected); @@ -604,7 +605,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_date_time_5, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(odt5)"sv, toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 123000000u }, { 0, 0 } } }, }}; REQUIRE(tbl == expected); @@ -612,7 +613,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_date_time_local_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(ldt1)"sv, toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u } } }, }}; REQUIRE(tbl == expected); @@ -620,7 +621,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_dotted_keys_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(name)"sv, R"(Orange)"sv }, { R"(physical)"sv, toml::table{{ @@ -639,7 +640,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_dotted_keys_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ { R"(b)"sv, 23 }, @@ -651,7 +652,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_dotted_keys_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ { R"(b)"sv, 23 }, @@ -663,7 +664,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_empty_key_name_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"()"sv, R"(blank)"sv }, }}; REQUIRE(tbl == expected); @@ -671,7 +672,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_empty_key_name_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"()"sv, R"(blank)"sv }, }}; REQUIRE(tbl == expected); @@ -679,7 +680,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_extend_dotted_object_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(fruit)"sv, toml::table{{ { @@ -696,7 +697,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_extend_dotted_object_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(apple)"sv, toml::table{{ { R"(type)"sv, R"(fruit)"sv }, @@ -717,7 +718,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_extend_dotted_object_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(apple)"sv, toml::table{{ { R"(type)"sv, R"(fruit)"sv }, @@ -738,7 +739,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt1)"sv, 1.0 }, }}; REQUIRE(tbl == expected); @@ -746,7 +747,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_10, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(sf1)"sv, std::numeric_limits::infinity() }, }}; REQUIRE(tbl == expected); @@ -754,7 +755,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_11, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(sf2)"sv, std::numeric_limits::infinity() }, }}; REQUIRE(tbl == expected); @@ -762,7 +763,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_12, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(sf2)"sv, -std::numeric_limits::infinity() }, }}; REQUIRE(tbl == expected); @@ -770,7 +771,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_13, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(sf4)"sv, std::numeric_limits::quiet_NaN() }, }}; REQUIRE(tbl == expected); @@ -778,7 +779,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_14, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(sf5)"sv, std::numeric_limits::quiet_NaN() }, }}; REQUIRE(tbl == expected); @@ -786,7 +787,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_15, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(sf6)"sv, std::numeric_limits::quiet_NaN() }, }}; REQUIRE(tbl == expected); @@ -794,7 +795,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt2)"sv, 3.1415 }, }}; REQUIRE(tbl == expected); @@ -802,7 +803,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt3)"sv, -0.01 }, }}; REQUIRE(tbl == expected); @@ -810,7 +811,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_4, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt4)"sv, 5e+22 }, }}; REQUIRE(tbl == expected); @@ -818,7 +819,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_5, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt5)"sv, 1000000.0 }, }}; REQUIRE(tbl == expected); @@ -826,7 +827,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_6, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt6)"sv, -0.02 }, }}; REQUIRE(tbl == expected); @@ -834,7 +835,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_7, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt7)"sv, 6.626e-34 }, }}; REQUIRE(tbl == expected); @@ -842,7 +843,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_8, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt8)"sv, 224617.445991228 }, }}; REQUIRE(tbl == expected); @@ -850,7 +851,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_float_9, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(flt9)"sv, -0.0 }, }}; REQUIRE(tbl == expected); @@ -858,7 +859,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int1)"sv, 99 }, }}; REQUIRE(tbl == expected); @@ -866,7 +867,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int2)"sv, 42 }, }}; REQUIRE(tbl == expected); @@ -874,7 +875,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int3)"sv, 0 }, }}; REQUIRE(tbl == expected); @@ -882,7 +883,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_3a, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int3)"sv, 0 }, }}; REQUIRE(tbl == expected); @@ -890,7 +891,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_3b, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int3)"sv, 0 }, }}; REQUIRE(tbl == expected); @@ -898,7 +899,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_4, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int4)"sv, -17 }, }}; REQUIRE(tbl == expected); @@ -906,7 +907,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_5, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int5)"sv, 1000 }, }}; REQUIRE(tbl == expected); @@ -914,7 +915,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_6, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int6)"sv, 5349221 }, }}; REQUIRE(tbl == expected); @@ -922,7 +923,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_7, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(int7)"sv, 12345 }, }}; REQUIRE(tbl == expected); @@ -930,7 +931,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_bin1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(bin1)"sv, 214 }, }}; REQUIRE(tbl == expected); @@ -938,7 +939,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_hex1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(hex1)"sv, 3735928559 }, }}; REQUIRE(tbl == expected); @@ -946,7 +947,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_hex2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(hex2)"sv, 3735928559 }, }}; REQUIRE(tbl == expected); @@ -954,7 +955,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_hex3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(hex3)"sv, 3735928559 }, }}; REQUIRE(tbl == expected); @@ -962,7 +963,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_max, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(max)"sv, INT64_MAX }, }}; REQUIRE(tbl == expected); @@ -970,7 +971,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_min, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(min)"sv, INT64_MIN }, }}; REQUIRE(tbl == expected); @@ -978,7 +979,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_oct1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(oct1)"sv, 342391 }, }}; REQUIRE(tbl == expected); @@ -986,7 +987,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_int_oct2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(oct2)"sv, 493 }, }}; REQUIRE(tbl == expected); @@ -994,7 +995,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(key)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); @@ -1002,7 +1003,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(bare_key)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); @@ -1010,7 +1011,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(bare-key)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); @@ -1018,7 +1019,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_4, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(1234)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); @@ -1026,7 +1027,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_5, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(1234)"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); @@ -1034,7 +1035,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_6, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(-)"sv, 1 }, }}; REQUIRE(tbl == expected); @@ -1042,7 +1043,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_7, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(_)"sv, 1 }, }}; REQUIRE(tbl == expected); @@ -1050,7 +1051,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_8, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(-_-_-_-_-)"sv, 1 }, }}; REQUIRE(tbl == expected); @@ -1058,7 +1059,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_key_value_pair_9, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(3)"sv, toml::table{{ { R"(14159)"sv, R"(pi)"sv }, @@ -1068,19 +1069,9 @@ TEST_CASE("conformance - iarna/valid") REQUIRE(tbl == expected); }); - #if UNICODE_LITERALS_OK - parsing_should_succeed(FILE_LINE_ARGS, spec_quoted_basic_keys_1, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { R"(ʎǝʞ)"sv, R"(value)"sv }, - }}; - REQUIRE(tbl == expected); - }); - #endif // UNICODE_LITERALS_OK - parsing_should_succeed(FILE_LINE_ARGS, spec_quoted_literal_keys_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(quoted "value")"sv, R"(value)"sv }, }}; REQUIRE(tbl == expected); @@ -1088,7 +1079,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_readme_example, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(title)"sv, R"(TOML Example)"sv }, { R"(owner)"sv, toml::table{{ @@ -1154,7 +1145,7 @@ TEST_CASE("conformance - iarna/valid") parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_multiline_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str1)"sv, R"(Roses are red Violets are blue)"sv }, }}; @@ -1163,7 +1154,7 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_multiline_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str)"sv, R"(The quick brown fox jumps over the lazy dog.)"sv }, }}; REQUIRE(tbl == expected); @@ -1171,7 +1162,7 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_multiline_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str)"sv, R"(The quick brown fox jumps over the lazy dog.)"sv }, }}; REQUIRE(tbl == expected); @@ -1179,7 +1170,7 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_multiline_5, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(ml-escaped-nl)"sv, R"( foo bar \ baz \quux)"sv }, }}; @@ -1188,7 +1179,7 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_multiline_6, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str4)"sv, R"(Here are two quotation marks: "". Simple enough.)"sv }, }}; REQUIRE(tbl == expected); @@ -1196,7 +1187,7 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_multiline_7, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str5)"sv, R"(Here are three quotation marks: """.)"sv }, }}; REQUIRE(tbl == expected); @@ -1204,7 +1195,7 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_multiline_8, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str6)"sv, R"(Here are fifteen quotation marks: """"""""""""""".)"sv }, }}; REQUIRE(tbl == expected); @@ -1212,7 +1203,7 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_multiline_9, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str7)"sv, R"("This," she said, "is just a pointless statement.")"sv }, }}; REQUIRE(tbl == expected); @@ -1220,7 +1211,7 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_tab_multiline, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str)"sv, R"(This is a tab)"sv }, }}; REQUIRE(tbl == expected); @@ -1228,26 +1219,15 @@ Violets are blue)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic_tab, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str)"sv, R"(This is a tab)"sv }, }}; REQUIRE(tbl == expected); }); - #if UNICODE_LITERALS_OK - parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { R"(str)"sv, R"(I'm a string. "You can quote me". Name José -Location SF.)"sv }, - }}; - REQUIRE(tbl == expected); - }); - #endif // UNICODE_LITERALS_OK - parsing_should_succeed(FILE_LINE_ARGS, spec_string_literal_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(winpath)"sv, R"(C:\Users\nodejs\templates)"sv }, }}; REQUIRE(tbl == expected); @@ -1255,7 +1235,7 @@ Location SF.)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_literal_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(winpath2)"sv, R"(\\ServerX\admin$\system32\)"sv }, }}; REQUIRE(tbl == expected); @@ -1263,7 +1243,7 @@ Location SF.)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_literal_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(quoted)"sv, R"(Tom "Dubs" Preston-Werner)"sv }, }}; REQUIRE(tbl == expected); @@ -1271,7 +1251,7 @@ Location SF.)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_literal_4, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(regex)"sv, R"(<\i\c*\s*>)"sv }, }}; REQUIRE(tbl == expected); @@ -1279,7 +1259,7 @@ Location SF.)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_literal_multiline_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(regex2)"sv, R"(I [dw]on't need \d{2} apples)"sv }, }}; REQUIRE(tbl == expected); @@ -1287,7 +1267,7 @@ Location SF.)"sv }, parsing_should_succeed(FILE_LINE_ARGS, spec_string_literal_multiline_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(lines)"sv, R"(The first newline is trimmed in raw strings. All other whitespace @@ -1299,7 +1279,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_string_literal_multiline_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(quot15)"sv, R"(Here are fifteen quotation marks: """"""""""""""")"sv }, }}; REQUIRE(tbl == expected); @@ -1307,7 +1287,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_string_literal_multiline_4, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(str)"sv, R"('That,' she said, 'is still pointless.')"sv }, }}; REQUIRE(tbl == expected); @@ -1315,7 +1295,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(table-1)"sv, toml::table{{ { R"(key1)"sv, R"(some string)"sv }, @@ -1334,7 +1314,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(dog)"sv, toml::table{{ { @@ -1354,7 +1334,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(a)"sv, toml::table{{ { @@ -1370,7 +1350,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_4, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(d)"sv, toml::table{{ { @@ -1386,7 +1366,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_5, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(g)"sv, toml::table{{ { @@ -1400,27 +1380,9 @@ trimmed in raw strings. REQUIRE(tbl == expected); }); - #if UNICODE_LITERALS_OK - parsing_should_succeed(FILE_LINE_ARGS, spec_table_6, [](toml::table&& tbl) - { - auto expected = toml::table{{ - { - R"(j)"sv, toml::table{{ - { - R"(ʞ)"sv, toml::table{{ - { R"(l)"sv, toml::table{} }, - }} - }, - }} - }, - }}; - REQUIRE(tbl == expected); - }); - #endif // UNICODE_LITERALS_OK - parsing_should_succeed(FILE_LINE_ARGS, spec_table_7, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(x)"sv, toml::table{{ { @@ -1440,7 +1402,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_8, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(fruit)"sv, toml::table{{ { @@ -1466,7 +1428,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_inline_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(name)"sv, toml::table{{ { R"(first)"sv, R"(Tom)"sv }, @@ -1479,7 +1441,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_inline_2, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(point)"sv, toml::table{{ { R"(x)"sv, 1 }, @@ -1492,7 +1454,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table_inline_3, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(animal)"sv, toml::table{{ { @@ -1508,7 +1470,7 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_table, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(table)"sv, toml::table{} }, }}; REQUIRE(tbl == expected); @@ -1516,11 +1478,47 @@ trimmed in raw strings. parsing_should_succeed(FILE_LINE_ARGS, spec_time_1, [](toml::table&& tbl) { - auto expected = toml::table{{ + const auto expected = toml::table{{ { R"(lt1)"sv, toml::time{ 7, 32, 0, 0 } }, }}; REQUIRE(tbl == expected); }); +#if UNICODE_LITERALS_OK + + parsing_should_succeed(FILE_LINE_ARGS, spec_quoted_basic_keys_1, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(ʎǝʞ)"sv, R"(value)"sv }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, spec_string_basic, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { R"(str)"sv, R"(I'm a string. "You can quote me". Name José +Location SF.)"sv }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, spec_table_6, [](toml::table&& tbl) + { + const auto expected = toml::table{{ + { + R"(j)"sv, toml::table{{ + { + R"(ʞ)"sv, toml::table{{ + { R"(l)"sv, toml::table{} }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + +#endif // UNICODE_LITERALS_OK } diff --git a/toml.hpp b/toml.hpp index 9126930..aac64db 100644 --- a/toml.hpp +++ b/toml.hpp @@ -408,12 +408,21 @@ #endif #ifndef DOXYGEN - #if defined(_WIN32) && !defined(TOML_WINDOWS_COMPAT) - #define TOML_WINDOWS_COMPAT 1 + #ifdef _WIN32 + #ifndef TOML_WINDOWS_COMPAT + #define TOML_WINDOWS_COMPAT 1 + #endif + #if TOML_WINDOWS_COMPAT && !defined(TOML_INCLUDE_WINDOWS_H) + #define TOML_INCLUDE_WINDOWS_H 0 + #endif #endif #if !defined(_WIN32) || !defined(TOML_WINDOWS_COMPAT) #undef TOML_WINDOWS_COMPAT - #define TOML_WINDOWS_COMPAT 0 + #define TOML_WINDOWS_COMPAT 0 + #endif + #if !TOML_WINDOWS_COMPAT + #undef TOML_INCLUDE_WINDOWS_H + #define TOML_INCLUDE_WINDOWS_H 0 #endif #endif @@ -620,24 +629,42 @@ is no longer necessary. #define TOML_ARM 0 #endif -#define TOML_MAKE_BITOPS(type) \ +#define TOML_MAKE_FLAGS_(name, op) \ [[nodiscard]] \ TOML_ALWAYS_INLINE \ TOML_ATTR(const) \ - TOML_ATTR(flatten) \ - constexpr type operator & (type lhs, type rhs) noexcept \ + constexpr name operator op(name lhs, name rhs) noexcept \ { \ - return static_cast(::toml::impl::unwrap_enum(lhs) & ::toml::impl::unwrap_enum(rhs)); \ + using under = std::underlying_type_t; \ + return static_cast(static_cast(lhs) op static_cast(rhs)); \ + } \ + constexpr name& operator TOML_CONCAT(op, =)(name & lhs, name rhs) noexcept \ + { \ + return lhs = (lhs op rhs); \ + } \ + static_assert(true, "") + +#define TOML_MAKE_FLAGS(name) \ + TOML_MAKE_FLAGS_(name, &); \ + TOML_MAKE_FLAGS_(name, |); \ + TOML_MAKE_FLAGS_(name, ^); \ + [[nodiscard]] \ + TOML_ALWAYS_INLINE \ + TOML_ATTR(const) \ + constexpr name operator~(name val) noexcept \ + { \ + using under = std::underlying_type_t; \ + return static_cast(~static_cast(val)); \ } \ [[nodiscard]] \ TOML_ALWAYS_INLINE \ TOML_ATTR(const) \ - TOML_ATTR(flatten) \ - constexpr type operator | (type lhs, type rhs) noexcept \ + constexpr bool operator!(name val) noexcept \ { \ - return static_cast(::toml::impl::unwrap_enum(lhs) | ::toml::impl::unwrap_enum(rhs)); \ + using under = std::underlying_type_t; \ + return !static_cast(val); \ } \ - static_assert(true) + static_assert(true, "") #ifndef TOML_LIFETIME_HOOKS #define TOML_LIFETIME_HOOKS 0 @@ -1571,7 +1598,7 @@ TOML_NAMESPACE_START format_as_hexadecimal = 3, }; - TOML_MAKE_BITOPS(value_flags); + TOML_MAKE_FLAGS(value_flags); enum class format_flags : uint8_t { @@ -1585,7 +1612,7 @@ TOML_NAMESPACE_START allow_value_format_flags = 8, }; - TOML_MAKE_BITOPS(format_flags); + TOML_MAKE_FLAGS(format_flags); template inline std::basic_ostream& operator << (std::basic_ostream& lhs, node_type rhs) @@ -12098,27 +12125,34 @@ TOML_NAMESPACE_END; #if TOML_WINDOWS_COMPAT #ifndef _WINDOWS_ -extern "C" -{ - int __stdcall WideCharToMultiByte( - unsigned int CodePage, - unsigned long dwFlags, - const wchar_t* lpWideCharStr, - int cchWideChar, - char* lpMultiByteStr, - int cbMultiByte, - const char* lpDefaultChar, - int* lpUsedDefaultChar - ); - int __stdcall MultiByteToWideChar( - unsigned int CodePage, - unsigned long dwFlags, - const char* lpMultiByteStr, - int cbMultiByte, - wchar_t* lpWideCharStr, - int cchWideChar - ); -} + #if TOML_INCLUDE_WINDOWS_H + #include + #else + extern "C" + { + __declspec(dllimport) + int __stdcall WideCharToMultiByte( + unsigned int CodePage, + unsigned long dwFlags, + const wchar_t* lpWideCharStr, + int cchWideChar, + char* lpMultiByteStr, + int cbMultiByte, + const char* lpDefaultChar, + int* lpUsedDefaultChar + ); + + __declspec(dllimport) + int __stdcall MultiByteToWideChar( + unsigned int CodePage, + unsigned long dwFlags, + const char* lpMultiByteStr, + int cbMultiByte, + wchar_t* lpWideCharStr, + int cchWideChar + ); + } + #endif #endif // _WINDOWS_ TOML_IMPL_NAMESPACE_START @@ -12130,13 +12164,13 @@ TOML_IMPL_NAMESPACE_START return {}; std::string s; - const auto len = WideCharToMultiByte( + const auto len = ::WideCharToMultiByte( 65001, 0, str.data(), static_cast(str.length()), nullptr, 0, nullptr, nullptr ); if (len) { s.resize(static_cast(len)); - WideCharToMultiByte(65001, 0, str.data(), static_cast(str.length()), s.data(), len, nullptr, nullptr); + ::WideCharToMultiByte(65001, 0, str.data(), static_cast(str.length()), s.data(), len, nullptr, nullptr); } return s; } @@ -12148,11 +12182,11 @@ TOML_IMPL_NAMESPACE_START return {}; std::wstring s; - const auto len = MultiByteToWideChar(65001, 0, str.data(), static_cast(str.length()), nullptr, 0); + const auto len = ::MultiByteToWideChar(65001, 0, str.data(), static_cast(str.length()), nullptr, 0); if (len) { s.resize(static_cast(len)); - MultiByteToWideChar(65001, 0, str.data(), static_cast(str.length()), s.data(), len); + ::MultiByteToWideChar(65001, 0, str.data(), static_cast(str.length()), s.data(), len); } return s; } @@ -12420,6 +12454,7 @@ TOML_POP_WARNINGS; // TOML_DISABLE_SPAM_WARNINGS #undef TOML_IMPLEMENTATION #undef TOML_IMPL_NAMESPACE_END #undef TOML_IMPL_NAMESPACE_START + #undef TOML_INCLUDE_WINDOWS_H #undef TOML_INT128 #undef TOML_INTELLISENSE #undef TOML_INTERNAL_LINKAGE @@ -12431,7 +12466,8 @@ TOML_POP_WARNINGS; // TOML_DISABLE_SPAM_WARNINGS #undef TOML_LAUNDER #undef TOML_LIFETIME_HOOKS #undef TOML_LIKELY - #undef TOML_MAKE_BITOPS + #undef TOML_MAKE_FLAGS_ + #undef TOML_MAKE_FLAGS #undef TOML_MAKE_VERSION #undef TOML_MAY_THROW #undef TOML_MSVC diff --git a/tools/generate_conformance_tests.py b/tools/generate_conformance_tests.py index 031083c..44733e9 100644 --- a/tools/generate_conformance_tests.py +++ b/tools/generate_conformance_tests.py @@ -19,7 +19,7 @@ from datetime import datetime, date, time def sanitize(s): s = re.sub(r'[ _:;\/-]+', '_', s, 0, re.I | re.M) - if s in ('bool', 'float', 'int', 'double', 'auto'): + if s in ('bool', 'float', 'int', 'double', 'auto', 'array', 'table'): s = s + '_' return s @@ -135,15 +135,11 @@ class TomlPPTable: s += '\n' + indent + '\t{ ' if isinstance(val, (TomlPPTable, TomlPPArray)) and len(val) > 0: s += '\n' + indent + '\t\t{},'.format(python_value_to_tomlpp(str(key))) - #s += '\n' + val.render(indent + '\t\t') s += ' ' + val.render(indent + '\t\t') s += '\n' + indent + '\t' else: s += '{}, {} '.format(python_value_to_tomlpp(str(key)), python_value_to_tomlpp(val)) s += '},' - #else: - - #s += '}\n' s += '\n' + indent + '}}' return s @@ -170,11 +166,11 @@ def json_to_python(val): return True if val["value"].lower() == "true" else False elif val_type == "array": return json_to_python(val["value"]) - elif val_type in ("datetime", "date", "time", "datetime-local"): + elif val_type in ("datetime", "date", "time", "datetime-local", "date-local", "time-local"): dt_val = dateutil.parser.parse(val["value"]) - if val_type == "date": + if val_type in ("date", "date-local"): return dt_val.date() - elif val_type == "time": + elif val_type in ("time", "time-local"): return dt_val.time() else: return dt_val @@ -218,9 +214,9 @@ class TomlTest: def __init__(self, file_path, is_valid_case): self.__name = file_path.stem self.__identifier = sanitize(self.__name) + self.__group = self.__identifier.strip('_').split('_')[0] self.__data = utils.read_all_text_from_file(file_path, logger=True).strip() - self.condition = '' - self.requires_unicode = False + self.__conditions = [] if is_valid_case: self.__expected = True path_base = str(Path(file_path.parent, file_path.stem)) @@ -246,6 +242,20 @@ class TomlTest: def identifier(self): return self.__identifier + def group(self): + return self.__group + + def add_condition(self, cond): + self.__conditions.append(cond) + return self + + def condition(self): + if not self.__conditions or not self.__conditions[0]: + return '' + if len(self.__conditions) == 1: + return rf'{self.__conditions[0]}' + return rf'{" && ".join([rf"{c}" for c in self.__conditions])}' + def data(self): return self.__data @@ -265,15 +275,43 @@ def load_tests(source_folder, is_valid_set, ignore_list): utils.assert_existing_directory(source_folder) files = utils.get_all_files(source_folder, all="*.toml") if ignore_list: - files = [f for f in files if f.stem not in ignore_list] - return [TomlTest(f, is_valid_set) for f in files] + files_ = [] + for f in files: + ignored = False + for ignore in ignore_list: + if isinstance(ignore, str): + if f.stem == ignore: + ignored = True + break + elif ignore.fullmatch(f.stem) is not None: # regex + ignored = True + break + if not ignored: + files_.append(f) + files = files_ + tests = [] + for f in files: + try: + tests.append(TomlTest(f, is_valid_set)) + except Exception as e: + print(rf'Error reading {f}, skipping...', file=sys.stderr) + return tests -def set_condition(tests, condition, names): +def add_condition(tests, condition, names): for test in tests: - if test.name() in names: - test.condition = condition + matched = False + for name in names: + if isinstance(name, str): + if test.name() == name: + matched = True + break + elif name.fullmatch(test.name()) is not None: # regex + matched = True + break + if matched: + test.add_condition(condition) @@ -281,8 +319,12 @@ def load_valid_inputs(tests, extern_root): tests['valid']['burntsushi'] = load_tests(Path(extern_root, 'toml-test', 'tests', 'valid'), True, ( # newline/escape handling tests. these get broken by I/O (I test them separately) 'string-escapes', - # bugged: https://github.com/BurntSushi/toml-test/issues/58 - 'datetime' + # causes MSVC to run out of heap space during compilation O_o + 'inline-table-key-dotted', + # broken by the json reader + 'key-alphanum', + # breaks clang: + 'multiline-string', )) tests['valid']['iarna'] = load_tests(Path(extern_root, 'toml-spec-tests', 'values'), True, ( # these are stress-tests for 'large' datasets. I test these separately. Having them inline in C++ code is insane. @@ -297,18 +339,8 @@ def load_valid_inputs(tests, extern_root): 'qa-table-inline-1000', 'qa-table-inline-nested-1000', # newline/escape handling tests. these get broken by I/O (I test them separately) - 'spec-newline-1', - 'spec-newline-2', - 'spec-newline-3', - 'spec-string-escape-1', - 'spec-string-escape-2', - 'spec-string-escape-3', - 'spec-string-escape-4', - 'spec-string-escape-5', - 'spec-string-escape-6', - 'spec-string-escape-7', - 'spec-string-escape-8', - 'spec-string-escape-9', + re.compile(r'spec-newline-.*'), + re.compile(r'spec-string-escape-.*'), # bugged: https://github.com/iarna/toml-spec-tests/issues/3 'spec-date-time-6', 'spec-date-time-local-2', @@ -322,41 +354,25 @@ def load_valid_inputs(tests, extern_root): def load_invalid_inputs(tests, extern_root): tests['invalid']['burntsushi'] = load_tests(Path(extern_root, 'toml-test', 'tests', 'invalid'), False, ( # false negatives after TOML 0.4.0 - 'array-mixed-types-arrays-and-ints', - 'array-mixed-types-ints-and-floats', - 'array-mixed-types-strings-and-ints' + re.compile('array-mixed.*'), + # these break IO/git/visual studio (i test them elsewhere) + re.compile('.*(bom|control).*'), + 'encoding-utf16', )) - set_condition(tests['invalid']['burntsushi'], '!TOML_LANG_UNRELEASED', ( - 'datetime-malformed-no-secs', - 'inline-table-linebreak', + add_condition(tests['invalid']['burntsushi'], '!TOML_LANG_UNRELEASED', ( + 'datetime-no-secs', + re.compile(r'inline-table-linebreak-.*'), + 'inline-table-trailing-comma', + 'key-special-character', 'multi-line-inline-table', - 'string-byte-escapes' + 'string-basic-byte-escapes', )) tests['invalid']['iarna'] = load_tests(Path(extern_root, 'toml-spec-tests', 'errors'), False, ( - # I test these explicitly in the other test files (they get broken by I/O) - 'comment-control-1', - 'comment-control-2', - 'comment-control-3', - 'comment-control-4', - 'string-basic-control-1', - 'string-basic-control-2', - 'string-basic-control-3', - 'string-basic-control-4', - 'string-basic-multiline-control-1', - 'string-basic-multiline-control-2', - 'string-basic-multiline-control-3', - 'string-basic-multiline-control-4', - 'string-literal-control-1', - 'string-literal-control-2', - 'string-literal-control-3', - 'string-literal-control-4', - 'string-literal-multiline-control-1', - 'string-literal-multiline-control-2', - 'string-literal-multiline-control-3', - 'string-literal-multiline-control-4' + # these break IO/git/visual studio (i test them elsewhere) + re.compile('.*(bom|control).*'), )) - set_condition(tests['invalid']['iarna'], '!TOML_LANG_UNRELEASED', ( + add_condition(tests['invalid']['iarna'], '!TOML_LANG_UNRELEASED', ( 'inline-table-trailing-comma', )) @@ -370,16 +386,29 @@ def requires_unicode(s): -def write_test_file(name, test_cases): +def write_test_file(name, all_tests): - conditions = set() - for test in test_cases: - conditions.add(test.condition) + for test in all_tests: + unicode = requires_unicode(str(test)) + if not unicode and not isinstance(test.expected(), bool): + unicode = requires_unicode(test.expected().render()) + if unicode: + test.add_condition(r'UNICODE_LITERALS_OK') + + tests_by_group = {} + for test in all_tests: + if test.group() not in tests_by_group: + tests_by_group[test.group()] = {} + cond = test.condition() + if cond not in tests_by_group[test.group()]: + tests_by_group[test.group()][cond] = [] + tests_by_group[test.group()][cond].append(test) + all_tests = tests_by_group test_file_path = Path(utils.entry_script_dir(), '..', 'tests', rf'conformance_{sanitize(name.strip())}.cpp').resolve() print(rf'Writing to {test_file_path}') with open(test_file_path, 'w', encoding='utf-8', newline='\n') as test_file: - write = lambda txt: print(txt, file=test_file) + write = lambda txt,end='\n': print(txt, file=test_file, end=end) # preamble write('// This file is a part of toml++ and is subject to the the terms of the MIT license.') @@ -397,16 +426,18 @@ def write_test_file(name, test_cases): write('TOML_DISABLE_WARNINGS; // unused variable spam') write('') write('namespace') - write('{') - for test in test_cases: - s = f'\t{test}' - test.requires_unicode = requires_unicode(s) - if test.requires_unicode: - write('\t#if UNICODE_LITERALS_OK') - write(s) - write('\t#endif // UNICODE_LITERALS_OK') - else: - write(s) + write('{', end='') + for group, conditions in all_tests.items(): + for condition, tests in conditions.items(): + write('') + if condition != '': + write(f'#if {condition}'); + write('') + for test in tests: + write(f'\t{test}') + if condition != '': + write('') + write(f'#endif // {condition}'); write('}') write('') write('TOML_ENABLE_WARNINGS;') @@ -414,50 +445,46 @@ def write_test_file(name, test_cases): # tests write(f'TEST_CASE("conformance - {name}")') - write('{') - for condition in conditions: - if condition != '': - write('') - write(f'\t#if {condition}'); - for test in test_cases: - if test.condition != condition: - continue - expected = test.expected() - if isinstance(expected, bool): - if expected: - write(f'\tparsing_should_succeed(FILE_LINE_ARGS, {test.identifier()});') - else: - write(f'\tparsing_should_fail(FILE_LINE_ARGS, {test.identifier()});') - else: - s = expected.render('\t\t') - if not test.requires_unicode: - test.requires_unicode = requires_unicode(s) - if test.requires_unicode: - write('\t#if UNICODE_LITERALS_OK') - write(f'\tparsing_should_succeed(FILE_LINE_ARGS, {test.identifier()}, [](toml::table&& tbl)') - write('\t{') - write(f'\t\tauto expected = {s};') - write('\t\tREQUIRE(tbl == expected);') - write('\t});') - if test.requires_unicode: - write('\t#endif // UNICODE_LITERALS_OK') + write('{', end='') + for group, conditions in all_tests.items(): + for condition, tests in conditions.items(): + if condition != '': write('') - if condition != '': - write(f'\t#endif // {condition}'); + write(f'#if {condition}'); + for test in tests: + write('') + expected = test.expected() + if isinstance(expected, bool): + if expected: + write(f'\tparsing_should_succeed(FILE_LINE_ARGS, {test.identifier()});') + else: + write(f'\tparsing_should_fail(FILE_LINE_ARGS, {test.identifier()});') + else: + s = expected.render('\t\t') + write(f'\tparsing_should_succeed(FILE_LINE_ARGS, {test.identifier()}, [](toml::table&& tbl)') + write('\t{') + write(f'\t\tconst auto expected = {s};') + write('\t\tREQUIRE(tbl == expected);') + write('\t});') + if condition != '': + write('') + write(f'#endif // {condition}'); write('}') write('') + def main(): extern_root = Path(utils.entry_script_dir(), '..', 'external').resolve() utils.assert_existing_directory(extern_root) assert extern_root.exists() - tests = { 'valid': dict(), 'invalid': dict() } - load_valid_inputs(tests, extern_root) - load_invalid_inputs(tests, extern_root) - for test_type, test_groups in tests.items(): - for test_group, test_cases in test_groups.items(): - write_test_file('{}/{}'.format(test_group, test_type), test_cases ) + all_tests = { 'valid': dict(), 'invalid': dict() } + load_valid_inputs(all_tests, extern_root) + load_invalid_inputs(all_tests, extern_root) + for validity, sources in all_tests.items(): + for source, tests in sources.items(): + write_test_file('{}/{}'.format(source, validity), tests ) + if __name__ == '__main__':