diff --git a/docs/tomlplusplus.css b/docs/tomlplusplus.css index da24378..6577a68 100644 --- a/docs/tomlplusplus.css +++ b/docs/tomlplusplus.css @@ -108,6 +108,7 @@ pre.m-code + pre.m-console margin-top: -1.0rem; border-top: 1px solid #444444; font-size: 0.8rem; + background-color: #1a1c1d !important; } pre.m-code + pre.m-console span { diff --git a/include/toml++/toml_array.h b/include/toml++/toml_array.h index da81fce..6a30af6 100644 --- a/include/toml++/toml_array.h +++ b/include/toml++/toml_array.h @@ -191,6 +191,14 @@ namespace toml::impl return new value{ std::forward(val) }; } } + + template + [[nodiscard]] + TOML_ALWAYS_INLINE + auto make_node(inserter&& val) noexcept + { + return make_node(std::move(val.value)); + } } namespace toml @@ -286,11 +294,30 @@ namespace toml /// \out /// [1, 2.0, "three", [4, 5]] /// \eout - /// - /// \tparam U One of the TOML node or value types (or a type promotable to one). - /// \tparam V One of the TOML node or value types (or a type promotable to one). - /// \param val The value used to initialize node 0. + /// + /// \remark \parblock If you need to construct an array with one child array element, the array's move constructor + /// will take precedence and perform a move-construction instead. You can use toml::inserter to + /// suppress this behaviour: \cpp + /// // desired result: [ [ 42 ] ] + /// auto bad = toml::array{ toml::array{ 42 } } + /// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } } + /// std::cout << "bad: " << bad << std::endl; + /// std::cout << "good:" << good << std::endl; + /// \ecpp + /// + /// \out + /// bad: [ 42 ] + /// good: [ [ 42 ] ] + /// \eout + /// + /// \endparblock + /// + /// \tparam U One of the TOML node or value types (or a type promotable to one). + /// \tparam V One of the TOML node or value types (or a type promotable to one). + /// \param val The value used to initialize node 0. /// \param vals The values used to initialize nodes 1...N. + /// + /// \returns A TOML_NODISCARD_CTOR. template TOML_NODISCARD_CTOR explicit array(U&& val, V&&... vals) diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h index 0f8abf0..e481848 100644 --- a/include/toml++/toml_common.h +++ b/include/toml++/toml_common.h @@ -568,4 +568,27 @@ namespace toml #if !TOML_ALL_INLINE extern template TOML_API std::ostream& operator << (std::ostream&, node_type); #endif + + /// \brief Helper class for suppressing move-construction in single-argument array constructors. + /// + /// \detail \cpp + /// // desired result: [ [ 42 ] ] + /// auto bad = toml::array{ toml::array{ 42 } } + /// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } } + /// std::cout << "bad: " << bad << std::endl; + /// std::cout << "good:" << good << std::endl; + /// \ecpp + /// + /// \out + /// bad: [ 42 ] + /// good: [ [ 42 ] ] + /// \eout + /// + /// \see toml::array + template + struct TOML_TRIVIAL_ABI inserter + { + T&& value; + }; + template inserter(T&&) -> inserter; } diff --git a/include/toml++/toml_parser.hpp b/include/toml++/toml_parser.hpp index fd39a10..e53cd20 100644 --- a/include/toml++/toml_parser.hpp +++ b/include/toml++/toml_parser.hpp @@ -549,9 +549,14 @@ namespace toml::impl // handle 'line ending slashes' in multi-line mode if constexpr (MultiLine) { - if (is_line_break(*cp)) + //consume_leading_whitespace + if (is_line_break(*cp) || is_whitespace(*cp)) { - consume_line_break(); + consume_leading_whitespace(); + if (!consume_line_break()) + set_error_and_return_default( + "line-ending backslashes must be the last non-whitespace character on the line"sv + ); skipping_whitespace = true; return_if_error({}); continue; diff --git a/include/toml++/toml_utf8_generated.h b/include/toml++/toml_utf8_generated.h index 9d240a4..bc5cd59 100644 --- a/include/toml++/toml_utf8_generated.h +++ b/include/toml++/toml_utf8_generated.h @@ -21,7 +21,7 @@ namespace toml::impl return cp >= U'0' && cp <= U'f' && (1ull << (static_cast(cp) - 0x30ull)) & 0x7E0000007E03FFull; } - #if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys) +#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys) //# Returns true if a codepoint belongs to any of these categories: //# Ll, Lm, Lo, Lt, Lu @@ -752,5 +752,5 @@ namespace toml::impl //# chunk summary: 2282 codepoints from 293 ranges (spanning a search area of 917232) } - #endif // TOML_LANG_UNRELEASED +#endif // TOML_LANG_UNRELEASED } // toml::impl diff --git a/include/toml++/toml_value.h b/include/toml++/toml_value.h index 1b40d6c..11efc61 100644 --- a/include/toml++/toml_value.h +++ b/include/toml++/toml_value.h @@ -193,7 +193,26 @@ namespace toml } /// \brief Value equality operator. - [[nodiscard]] friend bool operator == (const value& lhs, value_arg rhs) noexcept { return lhs.val_ == rhs; } + [[nodiscard]] friend bool operator == (const value& lhs, value_arg rhs) noexcept + { + if constexpr (std::is_same_v) + { + static constexpr auto pack = [](auto l, auto r) constexpr noexcept + { + return ((static_cast(l) << 32) | static_cast(r)); + }; + + switch (pack(std::fpclassify(lhs.val_), std::fpclassify(rhs))) + { + case pack(FP_INFINITE, FP_INFINITE): return (lhs.val_ < 0.0) == (rhs < 0.0); + case pack(FP_NAN, FP_NAN): return true; + default: return lhs.val_ == rhs; + } + } + else + return lhs.val_ == rhs; + + } TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, ) /// \brief Value less-than operator. @@ -224,7 +243,7 @@ namespace toml [[nodiscard]] friend bool operator == (const value& lhs, const value& rhs) noexcept { if constexpr (std::is_same_v) - return lhs.val_ == rhs.val_; + return lhs == rhs.val_; //calls asymmetrical value-equality operator defined above else return false; } diff --git a/python/generate_conformance_tests.py b/python/generate_conformance_tests.py index 8712b33..e4ebe29 100644 --- a/python/generate_conformance_tests.py +++ b/python/generate_conformance_tests.py @@ -9,116 +9,430 @@ import os.path as path import utils import io import re - - - -def open_test_file(name): - test_file_path = path.join(utils.get_script_folder(), '..', 'tests', name) - print("Writing to {}".format(test_file_path)) - return open(test_file_path, 'w', encoding='utf-8', newline='\n') - - - -def emit_preamble(test_file): - write = lambda txt: print(txt, file=test_file) - write('#include "tests.h"') - write('using namespace toml::impl;') - write('') - write('#if !TOML_UNRELEASED_FEATURES // todo: improve conformance script to remove this') - write('') - - +import json +import yaml # pip install pyyaml +import math +import dateutil.parser # pip install python-dateutil +from datetime import datetime, date, time def sanitize(s): - return re.sub(r'[ -]+', '_', s, 0, re.I | re.M) + return re.sub(r'[ _:;\/-]+', '_', s, 0, re.I | re.M) -def emit_invalid_tests(test_file, name, source_folder, skip_list=None): - constants_buf = io.StringIO('', newline='\n') - constants = lambda txt: print(txt, file=constants_buf) - tests_buf = io.StringIO('', newline='\n') - tests = lambda txt: print(txt, file=tests_buf) +def python_value_to_tomlpp(val): + if isinstance(val, str): + if re.fullmatch(r'^[+-]?[0-9]+[eE][+-]?[0-9]+$', val, re.M): + return str(float(val)) + else: + return 'S(R"({})"sv)'.format(val) + elif isinstance(val, bool): + return 'true' if val else 'false' + elif isinstance(val, float): + if math.isinf(val): + return ('-' if val < 0.0 else '') + 'std::numeric_limits::infinity()' + elif math.isnan(val): + return 'std::numeric_limits::quiet_NaN()' + else: + return str(val) + elif isinstance(val, int): + if val == 9223372036854775807: + return 'INT64_MAX' + elif val == -9223372036854775808: + return 'INT64_MIN' + else: + return str(val) + elif isinstance(val, (TomlPPArray, TomlPPTable)): + return str(val) + elif isinstance(val, datetime): + offset = None + if val.tzinfo is not None: + offset = val.tzinfo.utcoffset(val) + mins = offset.total_seconds() / 60 + offset = (int(mins / 60), int(mins % 60)) + return 'toml::date_time{{ {{ {}, {}, {} }}, {{ {}, {}, {}, {}u }}{} }}'.format( + val.year, + val.month, + val.day, + val.hour, + val.minute, + val.second, + val.microsecond*1000, + '' if offset is None else ', {{ {}, {} }}'.format(offset[0], offset[1]) + ) + elif isinstance(val, date): + return 'toml::date{{ {}, {}, {} }}'.format( + val.year, + val.month, + val.day + ) + elif isinstance(val, time): + return 'toml::time{{ {}, {}, {}, {} }}'.format( + val.hour, + val.minute, + val.second, + val.microsecond*1000 + ) + else: + raise ValueError(str(type(val))) - constants('namespace // invalid test data for {}'.format(name)) - constants('{') - - tests('TEST_CASE("conformance - invalid inputs from {}")'.format(name)) - tests('{') - #files = [path.splitext(path.split(f)[1])[0] for f in utils.get_all_files(source_folder,all="*.toml")] - files = [path.split(f) for f in utils.get_all_files(source_folder, all="*.toml")] - files = [(f[0], *path.splitext(f[1])) for f in files] - for dir,file,ext in files: - if skip_list and file in skip_list: + +class TomlPPArray: + + def __init__(self, init_data=None): + self.values = init_data if init_data else list() + + def render(self, indent = '', indent_declaration = False): + s = '' + if indent_declaration: + s += indent + if len(self.values) == 0: + s += 'toml::array{}' + else: + s += 'toml::array{' + for val in self.values: + s += '\n' + indent + '\t' + if isinstance(val, TomlPPArray) and len(self.values) == 1: + s += 'toml::inserter{' + if isinstance(val, (TomlPPTable, TomlPPArray)) and len(val) > 0: + s += val.render(indent + '\t') + else: + s += python_value_to_tomlpp(val) + if isinstance(val, TomlPPArray) and len(self.values) == 1: + s += '}' + s += ',' + s += '\n' + indent + '}' + return s + + def __str__(self): + return self.render() + + def __len__(self): + return len(self.values) + + + +class TomlPPTable: + + def __init__(self, init_data=None): + self.values = init_data if init_data else dict() + + def render(self, indent = '', indent_declaration = False): + s = '' + if indent_declaration: + s += indent + if len(self.values) == 0: + s += 'toml::table{}' + else: + s += 'toml::table{{' + for key, val in self.values.items(): + 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 + + def __str__(self): + return self.render() + + def __len__(self): + return len(self.values) + + + +def json_to_python(val): + + if isinstance(val, dict): + if len(val) == 2 and "type" in val and "value" in val: + val_type = val["type"] + if val_type == "integer": + return int(val["value"]) + elif val_type == "float": + return float(val["value"]) + elif val_type == "string": + return str(val["value"]) + elif val_type == "bool": + 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"): + dt_val = dateutil.parser.parse(val["value"]) + if val_type == "date": + return dt_val.date() + elif val_type == "time": + return dt_val.time() + else: + return dt_val + else: + raise ValueError(val_type) + else: + vals = dict() + for k,v in val.items(): + vals[k] = json_to_python(v) + return vals + + elif isinstance(val, list): + vals = list() + for v in val: + vals.append(json_to_python(v)) + return vals + + else: + raise ValueError(str(type(val))) + +def python_to_tomlpp(node): + if isinstance(node, dict): + table = TomlPPTable() + for key, val in node.items(): + table.values[key] = python_to_tomlpp(val) + return table + elif isinstance(node, (set, list, tuple)): + array = TomlPPArray() + for val in node: + array.values.append(python_to_tomlpp(val)) + return array + else: + return node + + +class TomlTest: + + def __init__(self, file_path, group, name, is_valid_case): + self.__name = name + self.__group = group + self.__identifier = sanitize(group + '_' + name) + self.__data = utils.read_all_text_from_file(file_path).strip() + self.condition = '' + if is_valid_case: + self.__expected = True + path_base = path.splitext(file_path)[0] + yaml_file = path_base + '.yaml' + if path.exists(yaml_file): + self.__expected = python_to_tomlpp(yaml.load( + utils.read_all_text_from_file(yaml_file), + Loader=yaml.FullLoader + )) + else: + json_file = path_base + '.json' + if path.exists(json_file): + self.__expected = python_to_tomlpp(json_to_python(json.loads( + utils.read_all_text_from_file(json_file), + ))) + + else: + self.__expected = False + + def name(self): + return self.__name + + def group(self): + return self.__group + + def identifier(self): + return self.__identifier + + def data(self): + return self.__data + + def expected(self): + return self.__expected + + def __str__(self): + return 'static constexpr auto {} = S(R"({})"sv);'.format( + self.__identifier, + self.__data, + ) + + + +def load_tests(source_folder, group, is_valid_set, ignore_list): + tests = [] + files = [(fp, path.splitext(path.split(fp)[1])[0]) for fp in utils.get_all_files(source_folder, all="*.toml")] + for file_path,name in files: + if ignore_list and name in ignore_list: continue - identifier = sanitize(file) - constants('\t static constexpr auto {} = S(R"({})"sv);'.format( - identifier, - utils.read_all_text_from_file(path.join(dir, file + ext)).strip() - )) - - tests('\tparsing_should_fail(FILE_LINE_ARGS, {});'.format(identifier)) + tests.append(TomlTest(file_path, group, name, is_valid_set)) + return tests - constants('}') - tests('}') - write = lambda txt: print(txt, file=test_file) - write(constants_buf.getvalue()) - write(tests_buf.getvalue()) -def emit_appendix(test_file): - write = lambda txt: print(txt, file=test_file) - write('') - write('#endif // !TOML_UNRELEASED_FEATURES') +def set_condition(tests, condition, group, names): + for test in tests: + if test.group() == group and test.name() in names: + test.condition = condition def main(): extern_root = path.join(utils.get_script_folder(), '..', 'extern') - with open_test_file('conformance.cpp') as test_file: - emit_preamble(test_file) - emit_invalid_tests( - test_file, - 'BurntSushi/toml-test', - path.join(extern_root, 'toml-test', 'tests', 'invalid'), - ( - # 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' - ) - ) - emit_invalid_tests( - test_file, - 'iarna/toml-spec-tests', - path.join(extern_root, 'toml-spec-tests', 'errors'), - ( - # I handle these internally, 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', - ) - ) - emit_appendix(test_file) + tests = { 'valid': list(), 'invalid': list() } + + + tests['invalid'] += load_tests(path.join(extern_root, 'toml-test', 'tests', 'invalid'), 'burntsushi', 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' + )) + set_condition(tests['invalid'], '!TOML_LANG_UNRELEASED', 'burntsushi', ( + 'datetime-malformed-no-secs', + 'inline-table-linebreak', + 'multi-line-inline-table', + 'string-byte-escapes' + )) + + tests['invalid'] += load_tests(path.join(extern_root, 'toml-spec-tests', 'errors'), 'iarna', 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' + )) + set_condition(tests['invalid'], '!TOML_LANG_UNRELEASED', 'iarna', ( + 'inline-table-trailing-comma', + )) + + tests['valid'] += load_tests(path.join(extern_root, 'toml-test', 'tests', 'valid'), 'burntsushi', 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' + )) + + tests['valid'] += load_tests(path.join(extern_root, 'toml-spec-tests', 'values'), 'iarna', True, ( + # these are stress-tests for 'large' datasets. I test these separately. Having them inline in C++ code is insane. + 'qa-array-inline-1000', + 'qa-array-inline-nested-1000', + 'qa-key-literal-40kb', + 'qa-key-string-40kb', + 'qa-scalar-literal-40kb', + 'qa-scalar-literal-multiline-40kb', + 'qa-scalar-string-40kb', + 'qa-scalar-string-multiline-40kb', + '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', + # bugged: https://github.com/iarna/toml-spec-tests/issues/3 + 'spec-date-time-6', + 'spec-date-time-local-2', + 'spec-time-2', + # breaks gcc: + 'spec-string-basic-multiline-4', + )) + + conditions = set() + for test_type, test_cases in tests.items(): + for test in test_cases: + conditions.add(test.condition) + + test_file_path = path.join(utils.get_script_folder(), '..', 'tests', 'conformance.cpp') + print("Writing to {}".format(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) + + # preamble + write('// This file is a part of toml++ and is subject to the the terms of the MIT license.') + write('// Copyright (c) 2019-2020 Mark Gillard ') + write('// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.') + write('// SPDX-License-Identifier: MIT') + write('//-----') + write('// this file was generated by generate_conformance_tests.py - do not modify it directly') + write('') + write('#include "tests.h"') + write('using namespace toml::impl;') + write('') + + # test data + write('TOML_PUSH_WARNINGS') + write('TOML_DISABLE_ALL_WARNINGS // unused variable spam') + write('') + write('namespace {') + write('') + for test_type, test_cases in tests.items(): + write('namespace {}'.format(test_type)) + write('{') + for test in test_cases: + write('\t{}'.format(test)) + write('}') + write('') + write('}') + write('') + write('TOML_POP_WARNINGS') + write('') + + # tests + write('TEST_CASE("conformance")') + write('{') + for test_type, test_cases in tests.items(): + write('\t'+utils.make_divider(test_type + ' inputs', 20, line_length=116)) + write('\t#if 1') + write('\t{') + for condition in conditions: + if condition != '': + write('') + write('\t\t#if {}'.format(condition)); + for test in test_cases: + if test.condition != condition: + continue + expected = test.expected() + if isinstance(expected, bool): + if expected: + write('\t\tparsing_should_succeed(FILE_LINE_ARGS, {}::{});'.format(test_type, test.identifier())) + else: + write('\t\tparsing_should_fail(FILE_LINE_ARGS, {}::{});'.format(test_type, test.identifier())) + else: + write('') + write('\t\tparsing_should_succeed(FILE_LINE_ARGS, {}::{}, [](toml::table&& tbl)'.format(test_type, test.identifier())) + write('\t\t{') + write('\t\t\tauto expected = {};'.format(expected.render('\t\t\t'))) + write('\t\t\tREQUIRE(tbl == expected);') + write('\t\t});') + if condition != '': + write('\t\t#endif // {}'.format(condition)); + write('\t}') + write('\t#endif') + write('') + write('}') + write('') diff --git a/python/generate_documentation.py b/python/generate_documentation.py index 4c94b87..99f00dc 100644 --- a/python/generate_documentation.py +++ b/python/generate_documentation.py @@ -74,7 +74,8 @@ type_names = [ 'parse_error', 'json_formatter', 'default_formatter', - 'format_flags' + 'format_flags', + 'inserter', ] all_namespaces = [ 'std', diff --git a/python/generate_single_header.py b/python/generate_single_header.py index e0bac5c..2f9633a 100644 --- a/python/generate_single_header.py +++ b/python/generate_single_header.py @@ -11,18 +11,6 @@ import re -def make_divider(text = None, text_col = 40, pattern = '-'): - if (text is None): - return "//" + utils.repeat_pattern(pattern, 118) - else: - text = "//{} {} ".format(utils.repeat_pattern(pattern, text_col - 2), text); - if (len(text) < 120): - return text + utils.repeat_pattern(pattern, 120 - len(text)) - else: - return text - - - class Preprocessor: def __init__(self): @@ -48,7 +36,7 @@ class Preprocessor: lpad = 28 + ((25 * (self.header_indent % 4)) - int((len(header_text) + 4) / 2)) self.header_indent += 1 text = '{}\n#if 1\n\n{}\n\n#endif\n{}\n'.format( - make_divider(header_text, lpad), text, make_divider('↑ ' + raw_incl, lpad) + utils.make_divider(header_text, lpad), text, utils.make_divider('↑ ' + raw_incl, lpad) ) return '\n\n' + text + '\n\n' # will get merged later @@ -141,7 +129,7 @@ v0.5.0: https://toml.io/en/v0.5.0''') print("Writing to {}".format(output_file_path)) with open(output_file_path,'w', encoding='utf-8', newline='\n') as output_file: if (len(preamble) > 0): - print(make_divider(), file=output_file) + print(utils.make_divider(), file=output_file) for pre in preamble: print('//', file=output_file) for line in pre.strip().splitlines(): @@ -152,7 +140,7 @@ v0.5.0: https://toml.io/en/v0.5.0''') else: print('\n', file=output_file, end = '') print('//', file=output_file) - print(make_divider(), file=output_file) + print(utils.make_divider(), file=output_file) print('''// clang-format off #ifndef INCLUDE_TOMLPLUSPLUS_H #define INCLUDE_TOMLPLUSPLUS_H diff --git a/python/generate_unicode_functions.py b/python/generate_unicode_functions.py index f77e8ea..7751a7d 100644 --- a/python/generate_unicode_functions.py +++ b/python/generate_unicode_functions.py @@ -1103,13 +1103,14 @@ def write_to_files(codepoints, header_file, test_file): test = lambda txt: print(txt, file=test_file) if test_file is not None else None both = lambda txt: (header(txt), test(txt)) - header('//# This file is a part of toml++ and is subject to the the terms of the MIT license.') - header('//# Copyright (c) 2019-2020 Mark Gillard ') - header('//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.') - header('// SPDX-License-Identifier: MIT') - header('//#-----') - header('//# this file was generated by generate_unicode_functions.py - do not modify it directly') - header('') + both('//# This file is a part of toml++ and is subject to the the terms of the MIT license.') + both('//# Copyright (c) 2019-2020 Mark Gillard ') + both('//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.') + both('// SPDX-License-Identifier: MIT') + both('//#-----') + both('//# this file was generated by generate_unicode_functions.py - do not modify it directly') + both('') + header('#pragma once') header('#include "toml_preprocessor.h"') header('') diff --git a/python/utils.py b/python/utils.py index 5d28431..80119d8 100644 --- a/python/utils.py +++ b/python/utils.py @@ -86,6 +86,18 @@ def get_all_files(dir, all=None, any=None): +def make_divider(text = None, text_col = 40, pattern = '-', line_length = 120): + if (text is None): + return "//" + repeat_pattern(pattern, line_length-2) + else: + text = "//{} {} ".format(repeat_pattern(pattern, text_col - 2), text); + if (len(text) < line_length): + return text + repeat_pattern(pattern, line_length - len(text)) + else: + return text + + + def run(main_func): try: result = main_func() diff --git a/tests/catch2.h b/tests/catch2.h index 37fe6b3..f5fad6d 100644 --- a/tests/catch2.h +++ b/tests/catch2.h @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #pragma once #include "settings.h" diff --git a/tests/conformance.cpp b/tests/conformance.cpp index 97ab1b1..e9d8f5a 100644 --- a/tests/conformance.cpp +++ b/tests/conformance.cpp @@ -1,74 +1,575 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT +//----- +// this file was generated by generate_conformance_tests.py - do not modify it directly + #include "tests.h" using namespace toml::impl; -#if !TOML_UNRELEASED_FEATURES // todo: improve conformance script to remove this +TOML_PUSH_WARNINGS +TOML_DISABLE_ALL_WARNINGS // unused variable spam -namespace // invalid test data for BurntSushi/toml-test +namespace { + +namespace valid { - static constexpr auto datetime_malformed_no_leads = S(R"(no-leads = 1987-7-05T17:45:00Z)"sv); - static constexpr auto datetime_malformed_no_secs = S(R"(no-secs = 1987-07-05T17:45Z)"sv); - static constexpr auto datetime_malformed_no_t = S(R"(no-t = 1987-07-0517:45:00Z)"sv); - static constexpr auto datetime_malformed_with_milli = S(R"(with-milli = 1987-07-5T17:45:00.12Z)"sv); - static constexpr auto duplicate_key_table = S(R"([fruit] + static constexpr auto burntsushi_array_empty = S(R"(thevoid = [[[[[]]]]])"sv); + static constexpr auto burntsushi_array_nospaces = S(R"(ints = [1,2,3])"sv); + static constexpr auto burntsushi_array_string_quote_comma_2 = S(R"(title = [ " \", ",])"sv); + static constexpr auto burntsushi_array_string_quote_comma = S(R"(title = [ +"Client: \"XXXX\", Job: XXXX", +"Code: XXXX" +])"sv); + static constexpr auto burntsushi_array_string_with_comma = S(R"(title = [ +"Client: XXXX, Job: XXXX", +"Code: XXXX" +])"sv); + static constexpr auto burntsushi_array_table_array_string_backslash = S(R"(foo = [ { bar="\"{{baz}}\""} ])"sv); + static constexpr auto burntsushi_arrays_hetergeneous = S(R"(mixed = [[1, 2], ["a", "b"], [1.1, 2.1]])"sv); + static constexpr auto burntsushi_arrays_nested = S(R"(nest = [["a"], ["b"]])"sv); + static constexpr auto burntsushi_arrays = S(R"(ints = [1, 2, 3] +floats = [1.1, 2.1, 3.1] +strings = ["a", "b", "c"] +dates = [ + 1987-07-05T17:45:00Z, + 1979-05-27T07:32:00Z, + 2006-06-01T11:00:00Z, +] +comments = [ + 1, + 2, #this is ok +])"sv); + static constexpr auto burntsushi_bool = S(R"(t = true +f = false)"sv); + static constexpr auto burntsushi_comments_at_eof = S(R"(# This is a full-line comment +key = "value" # This is a comment at the end of a line)"sv); + static constexpr auto burntsushi_comments_at_eof2 = S(R"(# This is a full-line comment +key = "value" # This is a comment at the end of a line)"sv); + static constexpr auto burntsushi_comments_everywhere = S(R"(# Top comment. + # Top comment. +# Top comment. + +# [no-extraneous-groups-please] + +[group] # Comment +answer = 42 # Comment +# no-extraneous-keys-please = 999 +# Inbetween comment. +more = [ # Comment + # What about multiple # comments? + # Can you handle it? + # + # Evil. +# Evil. + 42, 42, # Comments within arrays are fun. + # What about multiple # comments? + # Can you handle it? + # + # Evil. +# Evil. +# ] Did I fool you? +] # Hopefully not.)"sv); + static constexpr auto burntsushi_datetime_timezone = S(R"(bestdayever = 2017-06-06T12:34:56-05:00)"sv); + static constexpr auto burntsushi_double_quote_escape = S(R"(test = "\"one\"")"sv); + static constexpr auto burntsushi_empty = S(R"()"sv); + static constexpr auto burntsushi_escaped_escape = S(R"(answer = "\\x64")"sv); + static constexpr auto burntsushi_example = S(R"(best-day-ever = 1987-07-05T17:45:00Z + +[numtheory] +boring = false +perfection = [6, 28, 496])"sv); + static constexpr auto burntsushi_exponent_part_float = S(R"(million = 1e6 +minustenth = -1E-1 +beast = 6.66E2)"sv); + static constexpr auto burntsushi_float_exponent = S(R"(lower = 3e2 +upper = 3E2 +neg = 3e-2 +pos = 3E+2 +zero = 3e0 +pointlower = 3.1e2 +pointupper = 3.1E2)"sv); + static constexpr auto burntsushi_float_underscore = S(R"(before = 3_141.5927 +after = 3141.592_7 +exponent = 3e1_4)"sv); + static constexpr auto burntsushi_float = S(R"(pi = 3.14 +pospi = +3.14 +negpi = -3.14 +zero-intpart = 0.123)"sv); + static constexpr auto burntsushi_implicit_and_explicit_after = S(R"([a.b.c] +answer = 42 + +[a] +better = 43)"sv); + static constexpr auto burntsushi_implicit_and_explicit_before = S(R"([a] +better = 43 + +[a.b.c] +answer = 42)"sv); + static constexpr auto burntsushi_implicit_groups = S(R"([a.b.c] +answer = 42)"sv); + static constexpr auto burntsushi_inline_table_array = S(R"(people = [{first_name = "Bruce", last_name = "Springsteen"}, + {first_name = "Eric", last_name = "Clapton"}, + {first_name = "Bob", last_name = "Seger"}])"sv); + static constexpr auto burntsushi_inline_table = S(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 burntsushi_integer_underscore = S(R"(kilo = 1_000)"sv); + static constexpr auto burntsushi_integer = S(R"(answer = 42 +posanswer = +42 +neganswer = -42 +zero = 0)"sv); + static constexpr auto burntsushi_key_equals_nospace = S(R"(answer=42)"sv); + static constexpr auto burntsushi_key_numeric = S(R"(1 = 1)"sv); + static constexpr auto burntsushi_key_space = S(R"("a b" = 1)"sv); + static constexpr auto burntsushi_key_special_chars = S(R"("~!@$^&*()_+-`1234567890[]|/?><.,;:'" = 1)"sv); + static constexpr auto burntsushi_keys_with_dots = S(R"(plain = 1 +"with.dot" = 2 + +[plain_table] +plain = 3 +"with.dot" = 4 + +[table.withdot] +plain = 5 +"key.with.dots" = 6)"sv); + static constexpr auto burntsushi_long_float = S(R"(longpi = 3.141592653589793 +neglongpi = -3.141592653589793)"sv); + static constexpr auto burntsushi_long_integer = S(R"(answer = 9223372036854775807 +neganswer = -9223372036854775808)"sv); + static constexpr auto burntsushi_multiline_string = S(R"(multiline_empty_one = """""" +multiline_empty_two = """ +""" +multiline_empty_three = """\ + """ +multiline_empty_four = """\ + \ + \ + """ + +equivalent_one = "The quick brown fox jumps over the lazy dog." +equivalent_two = """ +The quick brown \ + + + fox jumps over \ + the lazy dog.""" + +equivalent_three = """\ + The quick brown \ + fox jumps over \ + the lazy dog.\ + """)"sv); + static constexpr auto burntsushi_nested_inline_table_array = S(R"(a = [ { b = {} } ])"sv); + static constexpr auto burntsushi_newline_crlf = S(R"(os = "DOS" +newline = "crlf")"sv); + static constexpr auto burntsushi_newline_lf = S(R"(os = "unix" +newline = "lf")"sv); + static constexpr auto burntsushi_raw_multiline_string = S(R"(oneline = '''This string has a ' quote character.''' +firstnl = ''' +This string has a ' quote character.''' +multiline = ''' +This string +has ' a quote character +and more than +one newline +in it.''')"sv); + static constexpr auto burntsushi_raw_string = S(R"(backspace = 'This string has a \b backspace character.' +tab = 'This string has a \t tab character.' +newline = 'This string has a \n new line character.' +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 burntsushi_right_curly_brace_after_boolean = S(R"(black = { python=">3.6", version=">=18.9b0", allow_prereleases=true })"sv); + static constexpr auto burntsushi_string_empty = S(R"(answer = "")"sv); + static constexpr auto burntsushi_string_nl = S(R"(nl_mid = "val\nue" +nl_end = """value\n""" + +lit_nl_end = '''value\n''' +lit_nl_mid = 'val\nue' +lit_nl_uni = 'val\ue')"sv); + static constexpr auto burntsushi_string_simple = S(R"(answer = "You are not drinking enough whisky.")"sv); + static constexpr auto burntsushi_string_with_pound = S(R"(pound = "We see no # comments here." +poundcomment = "But there are # some comments here." # Did I # mess you up?)"sv); + static constexpr auto burntsushi_table_array_implicit = S(R"([[albums.songs]] +name = "Glory Days")"sv); + static constexpr auto burntsushi_table_array_many = S(R"([[people]] +first_name = "Bruce" +last_name = "Springsteen" + +[[people]] +first_name = "Eric" +last_name = "Clapton" + +[[people]] +first_name = "Bob" +last_name = "Seger")"sv); + static constexpr auto burntsushi_table_array_nest = S(R"([[albums]] +name = "Born to Run" + + [[albums.songs]] + name = "Jungleland" + + [[albums.songs]] + name = "Meeting Across the River" + +[[albums]] +name = "Born in the USA" + + [[albums.songs]] + name = "Glory Days" + + [[albums.songs]] + name = "Dancing in the Dark")"sv); + static constexpr auto burntsushi_table_array_one = S(R"([[people]] +first_name = "Bruce" +last_name = "Springsteen")"sv); + static constexpr auto burntsushi_table_array_table_array = S(R"([[a]] + [[a.b]] + [a.b.c] + d = "val0" + [[a.b]] + [a.b.c] + d = "val1")"sv); + static constexpr auto burntsushi_table_empty = S(R"([a])"sv); + static constexpr auto burntsushi_table_no_eol = S(R"([table])"sv); + static constexpr auto burntsushi_table_sub_empty = S(R"([a] +[a.b])"sv); + static constexpr auto burntsushi_table_whitespace = S(R"(["valid key"])"sv); + static constexpr auto burntsushi_table_with_literal_string = S(R"(['a'] +[a.'"b"'] +[a.'"b"'.c] +answer = 42)"sv); + static constexpr auto burntsushi_table_with_pound = S(R"(["key#group"] +answer = 42)"sv); + static constexpr auto burntsushi_table_with_single_quotes = S(R"(['a'] +[a.'b'] +[a.'b'.c] +answer = 42)"sv); + static constexpr auto burntsushi_underscored_float = S(R"(electron_mass = 9_109.109_383e-3_4)"sv); + static constexpr auto burntsushi_underscored_integer = S(R"(million = 1_000_000)"sv); + static constexpr auto burntsushi_unicode_escape = S(R"(answer4 = "\u03B4" +answer8 = "\U000003B4")"sv); + static constexpr auto burntsushi_unicode_literal = S(R"(answer = "δ")"sv); + static constexpr auto iarna_spec_array_1 = S(R"(integers = [ 1, 2, 3 ])"sv); + static constexpr auto iarna_spec_array_2 = S(R"(colors = [ "red", "yellow", "green" ])"sv); + static constexpr auto iarna_spec_array_3 = S(R"(nested_array_of_int = [ [ 1, 2 ], [3, 4, 5] ])"sv); + static constexpr auto iarna_spec_array_4 = S(R"(string_array = [ "all", 'strings', """are the same""", '''type'''])"sv); + static constexpr auto iarna_spec_array_5 = S(R"(nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ])"sv); + static constexpr auto iarna_spec_array_7 = S(R"(integers2 = [ + 1, 2, 3 +])"sv); + static constexpr auto iarna_spec_array_8 = S(R"(integers3 = [ + 1, + 2, # this is ok +])"sv); + static constexpr auto iarna_spec_array_mixed_number_types = S(R"(numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ])"sv); + static constexpr auto iarna_spec_array_more_mixed_types = S(R"(contributors = [ + "Foo Bar ", + { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" } +])"sv); + static constexpr auto iarna_spec_array_of_tables_1 = S(R"([[products]] +name = "Hammer" +sku = 738594937 + +[[products]] + +[[products]] +name = "Nail" +sku = 284758393 +color = "gray")"sv); + static constexpr auto iarna_spec_array_of_tables_2 = S(R"([[fruit]] + name = "apple" + + [fruit.physical] + color = "red" + shape = "round" + + [[fruit.variety]] + name = "red delicious" + + [[fruit.variety]] + name = "granny smith" + +[[fruit]] + name = "banana" + + [[fruit.variety]] + name = "plantain")"sv); + static constexpr auto iarna_spec_array_of_tables_3 = S(R"(points = [ { x = 1, y = 2, z = 3 }, + { x = 7, y = 8, z = 9 }, + { x = 2, y = 4, z = 8 } ])"sv); + static constexpr auto iarna_spec_boolean_1 = S(R"(bool1 = true)"sv); + static constexpr auto iarna_spec_boolean_2 = S(R"(bool1 = false)"sv); + static constexpr auto iarna_spec_case_sensitive = S(R"(# TOML is case sensitive. +abc = 123 +ABC = 456)"sv); + static constexpr auto iarna_spec_comment_mid_array = S(R"(# eol commetns can go anywhere +abc = [ # this is valid + 123,#as is this + 456 #so is this + ]# and this +# here too)"sv); + static constexpr auto iarna_spec_comment_mid_string = S(R"(another = "# This is not a comment")"sv); + static constexpr auto iarna_spec_comment_tab = S(R"(# This is a full-line comment with a tab in the middle +key = "value" # This is a commen with a tab in the middle at the end of a line)"sv); + static constexpr auto iarna_spec_comment = S(R"(# This is a full-line comment +key = "value" # This is a comment at the end of a line)"sv); + static constexpr auto iarna_spec_date_local_1 = S(R"(ld1 = 1979-05-27)"sv); + static constexpr auto iarna_spec_date_time_1 = S(R"(odt1 = 1979-05-27T07:32:00Z)"sv); + static constexpr auto iarna_spec_date_time_2 = S(R"(odt2 = 1979-05-27T00:32:00-07:00)"sv); + static constexpr auto iarna_spec_date_time_3 = S(R"(odt3 = 1979-05-27T00:32:00.999999-07:00)"sv); + static constexpr auto iarna_spec_date_time_4 = S(R"(odt4 = 1979-05-27 07:32:00Z)"sv); + static constexpr auto iarna_spec_date_time_5 = S(R"(odt5 = 1979-05-27T07:32:00.123Z)"sv); + static constexpr auto iarna_spec_date_time_local_1 = S(R"(ldt1 = 1979-05-27T07:32:00)"sv); + static constexpr auto iarna_spec_dotted_keys_1 = S(R"(name = "Orange" +physical.color = "orange" +physical.shape = "round" +site."google.com" = true)"sv); + static constexpr auto iarna_spec_dotted_keys_2 = S(R"(a . b = 23)"sv); + static constexpr auto iarna_spec_dotted_keys_3 = S(R"(a . b = 23)"sv); + static constexpr auto iarna_spec_empty_key_name_1 = S(R"("" = "blank" # VALID but discouraged)"sv); + static constexpr auto iarna_spec_empty_key_name_2 = S(R"('' = "blank" # VALID but discouraged)"sv); + static constexpr auto iarna_spec_extend_dotted_object_1 = S(R"(# This makes the key "fruit" into a table. +fruit.apple.smooth = true + +# So then you can add to the table "fruit" like so: +fruit.orange = 2)"sv); + static constexpr auto iarna_spec_extend_dotted_object_2 = S(R"(# VALID BUT DISCOURAGED + +apple.type = "fruit" +orange.type = "fruit" + +apple.skin = "thin" +orange.skin = "thick" + +apple.color = "red" +orange.color = "orange")"sv); + static constexpr auto iarna_spec_extend_dotted_object_3 = S(R"(# RECOMMENDED + +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange")"sv); + static constexpr auto iarna_spec_float_1 = S(R"(flt1 = +1.0)"sv); + static constexpr auto iarna_spec_float_10 = S(R"(sf1 = inf # positive infinity)"sv); + static constexpr auto iarna_spec_float_11 = S(R"(sf2 = +inf # positive infinity)"sv); + static constexpr auto iarna_spec_float_12 = S(R"(sf2 = -inf # negative infinity)"sv); + static constexpr auto iarna_spec_float_13 = S(R"(sf4 = nan # actual sNaN/qNaN encoding is implementation specific)"sv); + static constexpr auto iarna_spec_float_14 = S(R"(sf5 = +nan # same as `nan`)"sv); + static constexpr auto iarna_spec_float_15 = S(R"(sf6 = -nan # valid, actual encoding is implementation specific)"sv); + static constexpr auto iarna_spec_float_2 = S(R"(flt2 = 3.1415)"sv); + static constexpr auto iarna_spec_float_3 = S(R"(flt3 = -0.01)"sv); + static constexpr auto iarna_spec_float_4 = S(R"(flt4 = 5e+22)"sv); + static constexpr auto iarna_spec_float_5 = S(R"(flt5 = 1e06)"sv); + static constexpr auto iarna_spec_float_6 = S(R"(flt6 = -2E-2)"sv); + static constexpr auto iarna_spec_float_7 = S(R"(flt7 = 6.626e-34)"sv); + static constexpr auto iarna_spec_float_8 = S(R"(flt8 = 224_617.445_991_228)"sv); + static constexpr auto iarna_spec_float_9 = S(R"(flt9 = -0e0)"sv); + static constexpr auto iarna_spec_int_1 = S(R"(int1 = +99)"sv); + static constexpr auto iarna_spec_int_2 = S(R"(int2 = 42)"sv); + static constexpr auto iarna_spec_int_3 = S(R"(int3 = 0)"sv); + static constexpr auto iarna_spec_int_3a = S(R"(int3 = +0)"sv); + static constexpr auto iarna_spec_int_3b = S(R"(int3 = -0)"sv); + static constexpr auto iarna_spec_int_4 = S(R"(int4 = -17)"sv); + static constexpr auto iarna_spec_int_5 = S(R"(int5 = 1_000)"sv); + static constexpr auto iarna_spec_int_6 = S(R"(int6 = 5_349_221)"sv); + static constexpr auto iarna_spec_int_7 = S(R"(int7 = 1_2_3_4_5 # VALID but discouraged)"sv); + static constexpr auto iarna_spec_int_bin1 = S(R"(bin1 = 0b11010110)"sv); + static constexpr auto iarna_spec_int_hex1 = S(R"(hex1 = 0xDEADBEEF)"sv); + static constexpr auto iarna_spec_int_hex2 = S(R"(hex2 = 0xdeadbeef)"sv); + static constexpr auto iarna_spec_int_hex3 = S(R"(hex3 = 0xdead_beef)"sv); + static constexpr auto iarna_spec_int_max = S(R"(max=9_223_372_036_854_775_807)"sv); + static constexpr auto iarna_spec_int_min = S(R"(min=-9_223_372_036_854_775_808)"sv); + static constexpr auto iarna_spec_int_oct1 = S(R"(oct1 = 0o01234567)"sv); + static constexpr auto iarna_spec_int_oct2 = S(R"(oct2 = 0o755 # useful for Unix file permissions)"sv); + static constexpr auto iarna_spec_key_value_pair_1 = S(R"(key = "value")"sv); + static constexpr auto iarna_spec_key_value_pair_2 = S(R"(bare_key = "value")"sv); + static constexpr auto iarna_spec_key_value_pair_3 = S(R"(bare-key = "value")"sv); + static constexpr auto iarna_spec_key_value_pair_4 = S(R"(1234 = "value")"sv); + static constexpr auto iarna_spec_key_value_pair_5 = S(R"(1234="value")"sv); + static constexpr auto iarna_spec_key_value_pair_6 = S(R"(-=1)"sv); + static constexpr auto iarna_spec_key_value_pair_7 = S(R"(_=1)"sv); + static constexpr auto iarna_spec_key_value_pair_8 = S(R"(-_-_-_-_-=1)"sv); + static constexpr auto iarna_spec_key_value_pair_9 = S(R"(3.14159 = "pi")"sv); + static constexpr auto iarna_spec_quoted_basic_keys_1 = S(R"("ʎǝʞ" = "value")"sv); + static constexpr auto iarna_spec_quoted_literal_keys_1 = S(R"('quoted "value"' = "value")"sv); + static constexpr auto iarna_spec_readme_example = S(R"(# This is a TOML document. + +title = "TOML Example" + +[owner] +name = "Tom Preston-Werner" +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] + + # Indentation (tabs and/or spaces) is allowed but not required + [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 iarna_spec_string_basic_multiline_1 = S(R"(str1 = """ +Roses are red +Violets are blue""")"sv); + static constexpr auto iarna_spec_string_basic_multiline_2 = S(R"(str = """ +The quick brown \ + + + fox jumps over \ + the lazy dog.""")"sv); + static constexpr auto iarna_spec_string_basic_multiline_3 = S(R"(str = """\ + The quick brown \ + fox jumps over \ + the lazy dog.\ + """)"sv); + static constexpr auto iarna_spec_string_basic_multiline_5 = S(R"(ml-escaped-nl = """ + foo \ + bar \\ + baz \\\ + quux""")"sv); + static constexpr auto iarna_spec_string_basic_multiline_6 = S(R"(str4 = """Here are two quotation marks: "". Simple enough.""")"sv); + static constexpr auto iarna_spec_string_basic_multiline_7 = S(R"(str5 = """Here are three quotation marks: ""\".""")"sv); + static constexpr auto iarna_spec_string_basic_multiline_8 = S(R"(str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""")"sv); + static constexpr auto iarna_spec_string_basic_multiline_9 = S(R"(str7 = """"This," she said, "is just a pointless statement."""")"sv); + static constexpr auto iarna_spec_string_basic_tab_multiline = S(R"(str = """This is a tab""")"sv); + static constexpr auto iarna_spec_string_basic_tab = S(R"(str = "This is a tab")"sv); + static constexpr auto iarna_spec_string_basic = S(R"(str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")"sv); + static constexpr auto iarna_spec_string_literal_1 = S(R"(winpath = 'C:\Users\nodejs\templates')"sv); + static constexpr auto iarna_spec_string_literal_2 = S(R"(winpath2 = '\\ServerX\admin$\system32\')"sv); + static constexpr auto iarna_spec_string_literal_3 = S(R"(quoted = 'Tom "Dubs" Preston-Werner')"sv); + static constexpr auto iarna_spec_string_literal_4 = S(R"(regex = '<\i\c*\s*>')"sv); + static constexpr auto iarna_spec_string_literal_multiline_1 = S(R"(regex2 = '''I [dw]on't need \d{2} apples''')"sv); + static constexpr auto iarna_spec_string_literal_multiline_2 = S(R"(lines = ''' +The first newline is +trimmed in raw strings. + All other whitespace + is preserved. +''')"sv); + static constexpr auto iarna_spec_string_literal_multiline_3 = S(R"(quot15 = '''Here are fifteen quotation marks: """""""""""""""''')"sv); + static constexpr auto iarna_spec_string_literal_multiline_4 = S(R"(str = ''''That,' she said, 'is still pointless.'''')"sv); + static constexpr auto iarna_spec_table_1 = S(R"([table-1] +key1 = "some string" +key2 = 123 + +[table-2] +key1 = "another string" +key2 = 456)"sv); + static constexpr auto iarna_spec_table_2 = S(R"([dog."tater.man"] +type.name = "pug")"sv); + static constexpr auto iarna_spec_table_3 = S(R"([a.b.c])"sv); + static constexpr auto iarna_spec_table_4 = S(R"([ d.e.f ] # same as [d.e.f])"sv); + static constexpr auto iarna_spec_table_5 = S(R"([ g . h . i ] # same as [g.h.i])"sv); + static constexpr auto iarna_spec_table_6 = S(R"([ j . "ʞ" . 'l' ] # same as [j."ʞ".'l'])"sv); + static constexpr auto iarna_spec_table_7 = S(R"(# [x] you +# [x.y] don't +# [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 iarna_spec_table_8 = S(R"([fruit] +apple.color = "red" +apple.taste.sweet = true + +[fruit.apple.texture] # you can add sub-tables +smooth = true)"sv); + static constexpr auto iarna_spec_table_inline_1 = S(R"(name = { first = "Tom", last = "Preston-Werner" })"sv); + static constexpr auto iarna_spec_table_inline_2 = S(R"(point = { x = 1, y = 2 })"sv); + static constexpr auto iarna_spec_table_inline_3 = S(R"(animal = { type.name = "pug" })"sv); + static constexpr auto iarna_spec_table = S(R"([table])"sv); + static constexpr auto iarna_spec_time_1 = S(R"(lt1 = 07:32:00)"sv); +} + +namespace invalid +{ + static constexpr auto burntsushi_datetime_malformed_no_leads = S(R"(no-leads = 1987-7-05T17:45:00Z)"sv); + static constexpr auto burntsushi_datetime_malformed_no_secs = S(R"(no-secs = 1987-07-05T17:45Z)"sv); + static constexpr auto burntsushi_datetime_malformed_no_t = S(R"(no-t = 1987-07-0517:45:00Z)"sv); + static constexpr auto burntsushi_datetime_malformed_with_milli = S(R"(with-milli = 1987-07-5T17:45:00.12Z)"sv); + static constexpr auto burntsushi_duplicate_key_table = S(R"([fruit] type = "apple" [fruit.type] apple = "yes")"sv); - static constexpr auto duplicate_keys = S(R"(dupe = false + static constexpr auto burntsushi_duplicate_keys = S(R"(dupe = false dupe = true)"sv); - static constexpr auto duplicate_tables = S(R"([a] + static constexpr auto burntsushi_duplicate_tables = S(R"([a] [a])"sv); - static constexpr auto empty_implicit_table = S(R"([naughty..naughty])"sv); - static constexpr auto empty_table = S(R"([])"sv); - static constexpr auto float_leading_zero_neg = S(R"(leading-zero = -03.14)"sv); - static constexpr auto float_leading_zero_pos = S(R"(leading-zero = +03.14)"sv); - static constexpr auto float_leading_zero = S(R"(leading-zero = 03.14)"sv); - static constexpr auto float_no_leading_zero = S(R"(answer = .12345 + static constexpr auto burntsushi_empty_implicit_table = S(R"([naughty..naughty])"sv); + static constexpr auto burntsushi_empty_table = S(R"([])"sv); + static constexpr auto burntsushi_float_leading_zero_neg = S(R"(leading-zero = -03.14)"sv); + static constexpr auto burntsushi_float_leading_zero_pos = S(R"(leading-zero = +03.14)"sv); + static constexpr auto burntsushi_float_leading_zero = S(R"(leading-zero = 03.14)"sv); + static constexpr auto burntsushi_float_no_leading_zero = S(R"(answer = .12345 neganswer = -.12345)"sv); - static constexpr auto float_no_trailing_digits = S(R"(answer = 1. + static constexpr auto burntsushi_float_no_trailing_digits = S(R"(answer = 1. neganswer = -1.)"sv); - static constexpr auto float_underscore_after_point = S(R"(bad = 1._2)"sv); - static constexpr auto float_underscore_after = S(R"(bad = 1.2_)"sv); - static constexpr auto float_underscore_before_point = S(R"(bad = 1_.2)"sv); - static constexpr auto float_underscore_before = S(R"(bad = _1.2)"sv); - static constexpr auto inline_table_linebreak = S(R"(simple = { a = 1 + static constexpr auto burntsushi_float_underscore_after_point = S(R"(bad = 1._2)"sv); + static constexpr auto burntsushi_float_underscore_after = S(R"(bad = 1.2_)"sv); + static constexpr auto burntsushi_float_underscore_before_point = S(R"(bad = 1_.2)"sv); + static constexpr auto burntsushi_float_underscore_before = S(R"(bad = _1.2)"sv); + static constexpr auto burntsushi_inline_table_linebreak = S(R"(simple = { a = 1 })"sv); - static constexpr auto integer_leading_zero_neg = S(R"(leading-zero = -012)"sv); - static constexpr auto integer_leading_zero_pos = S(R"(leading-zero = +012)"sv); - static constexpr auto integer_leading_zero = S(R"(leading-zero = 012)"sv); - static constexpr auto integer_underscore_after = S(R"(bad = 123_)"sv); - static constexpr auto integer_underscore_before = S(R"(bad = _123)"sv); - static constexpr auto integer_underscore_double = S(R"(bad = 1__23)"sv); - static constexpr auto key_after_array = S(R"([[agencies]] owner = "S Cjelli")"sv); - static constexpr auto key_after_table = S(R"([error] this = "should not be here")"sv); - static constexpr auto key_empty = S(R"(= 1)"sv); - static constexpr auto key_hash = S(R"(a# = 1)"sv); - static constexpr auto key_newline = S(R"(a + static constexpr auto burntsushi_integer_leading_zero_neg = S(R"(leading-zero = -012)"sv); + static constexpr auto burntsushi_integer_leading_zero_pos = S(R"(leading-zero = +012)"sv); + static constexpr auto burntsushi_integer_leading_zero = S(R"(leading-zero = 012)"sv); + static constexpr auto burntsushi_integer_underscore_after = S(R"(bad = 123_)"sv); + static constexpr auto burntsushi_integer_underscore_before = S(R"(bad = _123)"sv); + static constexpr auto burntsushi_integer_underscore_double = S(R"(bad = 1__23)"sv); + static constexpr auto burntsushi_key_after_array = S(R"([[agencies]] owner = "S Cjelli")"sv); + static constexpr auto burntsushi_key_after_table = S(R"([error] this = "should not be here")"sv); + static constexpr auto burntsushi_key_empty = S(R"(= 1)"sv); + static constexpr auto burntsushi_key_hash = S(R"(a# = 1)"sv); + static constexpr auto burntsushi_key_newline = S(R"(a = 1)"sv); - static constexpr auto key_no_eol = S(R"(a = 1 b = 2)"sv); - static constexpr auto key_open_bracket = S(R"([abc = 1)"sv); - static constexpr auto key_single_open_bracket = S(R"([)"sv); - static constexpr auto key_space = S(R"(a b = 1)"sv); - static constexpr auto key_start_bracket = S(R"([a] + static constexpr auto burntsushi_key_no_eol = S(R"(a = 1 b = 2)"sv); + static constexpr auto burntsushi_key_open_bracket = S(R"([abc = 1)"sv); + static constexpr auto burntsushi_key_single_open_bracket = S(R"([)"sv); + static constexpr auto burntsushi_key_space = S(R"(a b = 1)"sv); + static constexpr auto burntsushi_key_start_bracket = S(R"([a] [xyz = 5 [b])"sv); - static constexpr auto key_two_equals = S(R"(key= = 1)"sv); - static constexpr auto llbrace = S(R"([ [table]])"sv); - static constexpr auto multi_line_inline_table = S(R"(json_like = { + static constexpr auto burntsushi_key_two_equals = S(R"(key= = 1)"sv); + static constexpr auto burntsushi_llbrace = S(R"([ [table]])"sv); + static constexpr auto burntsushi_multi_line_inline_table = S(R"(json_like = { first = "Tom", last = "Preston-Werner" })"sv); - static constexpr auto multi_line_string_no_close = S(R"(invalid = """ + static constexpr auto burntsushi_multi_line_string_no_close = S(R"(invalid = """ this will fail)"sv); - static constexpr auto rrbrace = S(R"([[table] ])"sv); - static constexpr auto string_bad_byte_escape = S(R"(naughty = "\xAg")"sv); - static constexpr auto string_bad_codepoint = S(R"(invalid-codepoint = "This string contains a non scalar unicode codepoint \uD801")"sv); - static constexpr auto string_bad_escape = S(R"(invalid-escape = "This string has a bad \a escape character.")"sv); - static constexpr auto string_bad_slash_escape = S(R"(invalid-escape = "This string has a bad \/ escape character.")"sv); - static constexpr auto string_bad_uni_esc = S(R"(str = "val\ue")"sv); - static constexpr auto string_byte_escapes = S(R"(answer = "\x33")"sv); - static constexpr auto string_no_close = S(R"(no-ending-quote = "One time, at band camp)"sv); - static constexpr auto table_array_implicit = S(R"(# This test is a bit tricky. It should fail because the first use of + static constexpr auto burntsushi_rrbrace = S(R"([[table] ])"sv); + static constexpr auto burntsushi_string_bad_byte_escape = S(R"(naughty = "\xAg")"sv); + static constexpr auto burntsushi_string_bad_codepoint = S(R"(invalid-codepoint = "This string contains a non scalar unicode codepoint \uD801")"sv); + static constexpr auto burntsushi_string_bad_escape = S(R"(invalid-escape = "This string has a bad \a escape character.")"sv); + static constexpr auto burntsushi_string_bad_slash_escape = S(R"(invalid-escape = "This string has a bad \/ escape character.")"sv); + static constexpr auto burntsushi_string_bad_uni_esc = S(R"(str = "val\ue")"sv); + static constexpr auto burntsushi_string_byte_escapes = S(R"(answer = "\x33")"sv); + static constexpr auto burntsushi_string_no_close = S(R"(no-ending-quote = "One time, at band camp)"sv); + static constexpr auto burntsushi_table_array_implicit = S(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 # comply with the TOML spec: "Each double-bracketed sub-table will belong to @@ -82,108 +583,39 @@ name = "Glory Days" [[albums]] name = "Born in the USA")"sv); - static constexpr auto table_array_malformed_bracket = S(R"([[albums] + static constexpr auto burntsushi_table_array_malformed_bracket = S(R"([[albums] name = "Born to Run")"sv); - static constexpr auto table_array_malformed_empty = S(R"([[]] + static constexpr auto burntsushi_table_array_malformed_empty = S(R"([[]] name = "Born to Run")"sv); - static constexpr auto table_empty = S(R"([])"sv); - static constexpr auto table_nested_brackets_close = S(R"([a]b] + static constexpr auto burntsushi_table_empty = S(R"([])"sv); + static constexpr auto burntsushi_table_nested_brackets_close = S(R"([a]b] zyx = 42)"sv); - static constexpr auto table_nested_brackets_open = S(R"([a[b] + static constexpr auto burntsushi_table_nested_brackets_open = S(R"([a[b] zyx = 42)"sv); - static constexpr auto table_whitespace = S(R"([invalid key])"sv); - static constexpr auto table_with_pound = S(R"([key#group] + static constexpr auto burntsushi_table_whitespace = S(R"([invalid key])"sv); + static constexpr auto burntsushi_table_with_pound = S(R"([key#group] answer = 42)"sv); - static constexpr auto text_after_array_entries = S(R"(array = [ + static constexpr auto burntsushi_text_after_array_entries = S(R"(array = [ "Is there life after an array separator?", No "Entry" ])"sv); - static constexpr auto text_after_integer = S(R"(answer = 42 the ultimate answer?)"sv); - static constexpr auto text_after_string = S(R"(string = "Is there life after strings?" No.)"sv); - static constexpr auto text_after_table = S(R"([error] this shouldn't be here)"sv); - static constexpr auto text_before_array_separator = S(R"(array = [ + static constexpr auto burntsushi_text_after_integer = S(R"(answer = 42 the ultimate answer?)"sv); + static constexpr auto burntsushi_text_after_string = S(R"(string = "Is there life after strings?" No.)"sv); + static constexpr auto burntsushi_text_after_table = S(R"([error] this shouldn't be here)"sv); + static constexpr auto burntsushi_text_before_array_separator = S(R"(array = [ "Is there life before an array separator?" No, "Entry" ])"sv); - static constexpr auto text_in_array = S(R"(array = [ + static constexpr auto burntsushi_text_in_array = S(R"(array = [ "Entry 1", I don't belong, "Entry 2", ])"sv); -} - -TEST_CASE("conformance - invalid inputs from BurntSushi/toml-test") -{ - parsing_should_fail(FILE_LINE_ARGS, datetime_malformed_no_leads); - parsing_should_fail(FILE_LINE_ARGS, datetime_malformed_no_secs); - 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, inline_table_linebreak); - 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_inline_table); - 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_byte_escapes); - 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); -} - -namespace // invalid test data for iarna/toml-spec-tests -{ - static constexpr auto array_of_tables_1 = S(R"(# INVALID TOML DOC + static constexpr auto iarna_array_of_tables_1 = S(R"(# INVALID TOML DOC fruit = [] [[fruit]] # Not allowed)"sv); - static constexpr auto array_of_tables_2 = S(R"(# INVALID TOML DOC + static constexpr auto iarna_array_of_tables_2 = S(R"(# INVALID TOML DOC [[fruit]] name = "apple" @@ -193,24 +625,24 @@ fruit = [] # This table conflicts with the previous table [fruit.variety] name = "granny smith")"sv); - static constexpr auto bare_key_1 = S(R"(bare!key = 123)"sv); - static constexpr auto bare_key_2 = S(R"(barekey + static constexpr auto iarna_bare_key_1 = S(R"(bare!key = 123)"sv); + static constexpr auto iarna_bare_key_2 = S(R"(barekey = 123)"sv); - static constexpr auto bare_key_3 = S(R"(barekey =)"sv); - static constexpr auto inline_table_imutable_1 = S(R"([product] + static constexpr auto iarna_bare_key_3 = S(R"(barekey =)"sv); + static constexpr auto iarna_inline_table_imutable_1 = S(R"([product] type = { name = "Nail" } type.edible = false # INVALID)"sv); - static constexpr auto inline_table_imutable_2 = S(R"([product] + static constexpr auto iarna_inline_table_imutable_2 = S(R"([product] type.name = "Nail" type = { edible = false } # INVALID)"sv); - static constexpr auto inline_table_trailing_comma = S(R"(abc = { abc = 123, })"sv); - static constexpr auto int_0_padded = S(R"(int = 0123)"sv); - static constexpr auto int_signed_bin = S(R"(bin = +0b10)"sv); - static constexpr auto int_signed_hex = S(R"(hex = +0xab)"sv); - static constexpr auto int_signed_oct = S(R"(oct = +0o23)"sv); - static constexpr auto key_value_pair_1 = S(R"(key = # INVALID)"sv); - static constexpr auto key_value_pair_2 = S(R"(first = "Tom" last = "Preston-Werner" # INVALID)"sv); - static constexpr auto multiple_dot_key = S(R"(# THE FOLLOWING IS INVALID + static constexpr auto iarna_inline_table_trailing_comma = S(R"(abc = { abc = 123, })"sv); + static constexpr auto iarna_int_0_padded = S(R"(int = 0123)"sv); + static constexpr auto iarna_int_signed_bin = S(R"(bin = +0b10)"sv); + static constexpr auto iarna_int_signed_hex = S(R"(hex = +0xab)"sv); + static constexpr auto iarna_int_signed_oct = S(R"(oct = +0o23)"sv); + static constexpr auto iarna_key_value_pair_1 = S(R"(key = # INVALID)"sv); + static constexpr auto iarna_key_value_pair_2 = S(R"(first = "Tom" last = "Preston-Werner" # INVALID)"sv); + static constexpr auto iarna_multiple_dot_key = S(R"(# THE FOLLOWING IS INVALID # This defines the value of fruit.apple to be an integer. fruit.apple = 1 @@ -218,57 +650,57 @@ fruit.apple = 1 # But then this treats fruit.apple like it's a table. # You can't turn an integer into a table. fruit.apple.smooth = true)"sv); - static constexpr auto multiple_key = S(R"(# DO NOT DO THIS + static constexpr auto iarna_multiple_key = S(R"(# DO NOT DO THIS name = "Tom" name = "Pradyun")"sv); - static constexpr auto no_key_name = S(R"(= "no key name" # INVALID)"sv); - static constexpr auto string_basic_multiline_invalid_backslash = S(R"(a = """ + static constexpr auto iarna_no_key_name = S(R"(= "no key name" # INVALID)"sv); + static constexpr auto iarna_string_basic_multiline_invalid_backslash = S(R"(a = """ foo \ \n bar""")"sv); - static constexpr auto string_basic_multiline_out_of_range_unicode_escape_1 = S(R"(a = """\UFFFFFFFF""")"sv); - static constexpr auto string_basic_multiline_out_of_range_unicode_escape_2 = S(R"(a = """\U00D80000""")"sv); - static constexpr auto string_basic_multiline_quotes = S(R"(str5 = """Here are three quotation marks: """.""")"sv); - static constexpr auto string_basic_multiline_unknown_escape = S(R"(a = """\@""")"sv); - static constexpr auto string_basic_out_of_range_unicode_escape_1 = S(R"(a = "\UFFFFFFFF")"sv); - static constexpr auto string_basic_out_of_range_unicode_escape_2 = S(R"(a = "\U00D80000")"sv); - static constexpr auto string_basic_unknown_escape = S(R"(a = "\@")"sv); - static constexpr auto string_literal_multiline_quotes = S(R"(apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID)"sv); - static constexpr auto table_1 = S(R"(# DO NOT DO THIS + static constexpr auto iarna_string_basic_multiline_out_of_range_unicode_escape_1 = S(R"(a = """\UFFFFFFFF""")"sv); + static constexpr auto iarna_string_basic_multiline_out_of_range_unicode_escape_2 = S(R"(a = """\U00D80000""")"sv); + static constexpr auto iarna_string_basic_multiline_quotes = S(R"(str5 = """Here are three quotation marks: """.""")"sv); + static constexpr auto iarna_string_basic_multiline_unknown_escape = S(R"(a = """\@""")"sv); + static constexpr auto iarna_string_basic_out_of_range_unicode_escape_1 = S(R"(a = "\UFFFFFFFF")"sv); + static constexpr auto iarna_string_basic_out_of_range_unicode_escape_2 = S(R"(a = "\U00D80000")"sv); + static constexpr auto iarna_string_basic_unknown_escape = S(R"(a = "\@")"sv); + static constexpr auto iarna_string_literal_multiline_quotes = S(R"(apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID)"sv); + static constexpr auto iarna_table_1 = S(R"(# DO NOT DO THIS [fruit] apple = "red" [fruit] orange = "orange")"sv); - static constexpr auto table_2 = S(R"(# DO NOT DO THIS EITHER + static constexpr auto iarna_table_2 = S(R"(# DO NOT DO THIS EITHER [fruit] apple = "red" [fruit.apple] texture = "smooth")"sv); - static constexpr auto table_3 = S(R"([fruit] + static constexpr auto iarna_table_3 = S(R"([fruit] apple.color = "red" apple.taste.sweet = true [fruit.apple] # INVALID)"sv); - static constexpr auto table_4 = S(R"([fruit] + static constexpr auto iarna_table_4 = S(R"([fruit] apple.color = "red" apple.taste.sweet = true [fruit.apple.taste] # INVALID)"sv); - static constexpr auto table_invalid_1 = S(R"([fruit.physical] # subtable, but to which parent element should it belong? + static constexpr auto iarna_table_invalid_1 = S(R"([fruit.physical] # subtable, but to which parent element should it belong? color = "red" shape = "round" [[fruit]] # parser must throw an error upon discovering that "fruit" is # an array rather than a table name = "apple")"sv); - static constexpr auto table_invalid_2 = S(R"(# INVALID TOML DOC + static constexpr auto iarna_table_invalid_2 = S(R"(# INVALID TOML DOC fruit = [] [[fruit]] # Not allowed)"sv); - static constexpr auto table_invalid_3 = S(R"(# INVALID TOML DOC + static constexpr auto iarna_table_invalid_3 = S(R"(# INVALID TOML DOC [[fruit]] name = "apple" @@ -282,7 +714,7 @@ fruit = [] [fruit.physical] color = "red" shape = "round")"sv); - static constexpr auto table_invalid_4 = S(R"(# INVALID TOML DOC + static constexpr auto iarna_table_invalid_4 = S(R"(# INVALID TOML DOC [[fruit]] name = "apple" @@ -298,43 +730,2264 @@ fruit = [] color = "green")"sv); } -TEST_CASE("conformance - invalid inputs from iarna/toml-spec-tests") -{ - 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, inline_table_trailing_comma); - 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); } +TOML_POP_WARNINGS + +TEST_CASE("conformance") +{ + //------------------ valid inputs -------------------------------------------------------------------------------- + #if 1 + { + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_array_empty, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(thevoid)"sv), toml::array{ + toml::inserter{toml::array{ + toml::inserter{toml::array{ + toml::inserter{toml::array{ + toml::inserter{toml::array{}}, + }}, + }}, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_array_nospaces, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(ints)"sv), toml::array{ + 1, + 2, + 3, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_array_string_quote_comma_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(title)"sv), toml::array{ + S(R"( ", )"sv), + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_array_string_quote_comma, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(title)"sv), toml::array{ + S(R"(Client: "XXXX", Job: XXXX)"sv), + S(R"(Code: XXXX)"sv), + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_array_string_with_comma, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(title)"sv), toml::array{ + S(R"(Client: XXXX, Job: XXXX)"sv), + S(R"(Code: XXXX)"sv), + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_array_table_array_string_backslash, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(foo)"sv), toml::array{ + toml::table{{ + { S(R"(bar)"sv), S(R"("{{baz}}")"sv) }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_arrays_hetergeneous, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(mixed)"sv), toml::array{ + toml::array{ + 1, + 2, + }, + toml::array{ + S(R"(a)"sv), + S(R"(b)"sv), + }, + toml::array{ + 1.1, + 2.1, + }, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_arrays_nested, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(nest)"sv), toml::array{ + toml::array{ + S(R"(a)"sv), + }, + toml::array{ + S(R"(b)"sv), + }, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_arrays, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(ints)"sv), toml::array{ + 1, + 2, + 3, + } + }, + { + S(R"(floats)"sv), toml::array{ + 1.1, + 2.1, + 3.1, + } + }, + { + S(R"(strings)"sv), toml::array{ + S(R"(a)"sv), + S(R"(b)"sv), + S(R"(c)"sv), + } + }, + { + S(R"(dates)"sv), toml::array{ + toml::date_time{ { 1987, 7, 5 }, { 17, 45, 0, 0u }, { 0, 0 } }, + toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u }, { 0, 0 } }, + toml::date_time{ { 2006, 6, 1 }, { 11, 0, 0, 0u }, { 0, 0 } }, + } + }, + { + S(R"(comments)"sv), toml::array{ + 1, + 2, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_bool, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(f)"sv), false }, + { S(R"(t)"sv), true }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_comments_at_eof, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(key)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_comments_at_eof2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(key)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_comments_everywhere, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(group)"sv), toml::table{{ + { S(R"(answer)"sv), 42 }, + { + S(R"(more)"sv), toml::array{ + 42, + 42, + } + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_datetime_timezone, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(bestdayever)"sv), toml::date_time{ { 2017, 6, 6 }, { 12, 34, 56, 0u }, { -5, 0 } } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_double_quote_escape, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(test)"sv), S(R"("one")"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_empty, [](toml::table&& tbl) + { + auto expected = toml::table{}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_escaped_escape, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(answer)"sv), S(R"(\x64)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_example, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(best-day-ever)"sv), toml::date_time{ { 1987, 7, 5 }, { 17, 45, 0, 0u }, { 0, 0 } } }, + { + S(R"(numtheory)"sv), toml::table{{ + { S(R"(boring)"sv), false }, + { + S(R"(perfection)"sv), toml::array{ + 6, + 28, + 496, + } + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_exponent_part_float, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(million)"sv), 1000000.0 }, + { S(R"(minustenth)"sv), -0.1 }, + { S(R"(beast)"sv), 666.0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_float_exponent, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(lower)"sv), 300.0 }, + { S(R"(upper)"sv), 300.0 }, + { S(R"(neg)"sv), 0.03 }, + { S(R"(pos)"sv), 300.0 }, + { S(R"(zero)"sv), 3.0 }, + { S(R"(pointlower)"sv), 310.0 }, + { S(R"(pointupper)"sv), 310.0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_float_underscore, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(before)"sv), 3141.5927 }, + { S(R"(after)"sv), 3141.5927 }, + { S(R"(exponent)"sv), 300000000000000.0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_float, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(pi)"sv), 3.14 }, + { S(R"(pospi)"sv), 3.14 }, + { S(R"(negpi)"sv), -3.14 }, + { S(R"(zero-intpart)"sv), 0.123 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_implicit_and_explicit_after, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { S(R"(better)"sv), 43 }, + { + S(R"(b)"sv), toml::table{{ + { + S(R"(c)"sv), toml::table{{ + { S(R"(answer)"sv), 42 }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_implicit_and_explicit_before, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { S(R"(better)"sv), 43 }, + { + S(R"(b)"sv), toml::table{{ + { + S(R"(c)"sv), toml::table{{ + { S(R"(answer)"sv), 42 }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_implicit_groups, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { + S(R"(b)"sv), toml::table{{ + { + S(R"(c)"sv), toml::table{{ + { S(R"(answer)"sv), 42 }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_inline_table_array, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(people)"sv), toml::array{ + toml::table{{ + { S(R"(first_name)"sv), S(R"(Bruce)"sv) }, + { S(R"(last_name)"sv), S(R"(Springsteen)"sv) }, + }}, + toml::table{{ + { S(R"(first_name)"sv), S(R"(Eric)"sv) }, + { S(R"(last_name)"sv), S(R"(Clapton)"sv) }, + }}, + toml::table{{ + { S(R"(first_name)"sv), S(R"(Bob)"sv) }, + { S(R"(last_name)"sv), S(R"(Seger)"sv) }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_inline_table, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(name)"sv), toml::table{{ + { S(R"(first)"sv), S(R"(Tom)"sv) }, + { S(R"(last)"sv), S(R"(Preston-Werner)"sv) }, + }} + }, + { + S(R"(point)"sv), toml::table{{ + { S(R"(x)"sv), 1 }, + { S(R"(y)"sv), 2 }, + }} + }, + { + S(R"(simple)"sv), toml::table{{ + { S(R"(a)"sv), 1 }, + }} + }, + { + S(R"(str-key)"sv), toml::table{{ + { S(R"(a)"sv), 1 }, + }} + }, + { + S(R"(table-array)"sv), toml::array{ + toml::table{{ + { S(R"(a)"sv), 1 }, + }}, + toml::table{{ + { S(R"(b)"sv), 2 }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_integer_underscore, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(kilo)"sv), 1000 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_integer, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(answer)"sv), 42 }, + { S(R"(neganswer)"sv), -42 }, + { S(R"(posanswer)"sv), 42 }, + { S(R"(zero)"sv), 0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_key_equals_nospace, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(answer)"sv), 42 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_key_numeric, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(1)"sv), 1 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_key_space, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(a b)"sv), 1 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_key_special_chars, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(~!@$^&*()_+-`1234567890[]|/?><.,;:')"sv), 1 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_keys_with_dots, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(plain)"sv), 1 }, + { S(R"(with.dot)"sv), 2 }, + { + S(R"(plain_table)"sv), toml::table{{ + { S(R"(plain)"sv), 3 }, + { S(R"(with.dot)"sv), 4 }, + }} + }, + { + S(R"(table)"sv), toml::table{{ + { + S(R"(withdot)"sv), toml::table{{ + { S(R"(plain)"sv), 5 }, + { S(R"(key.with.dots)"sv), 6 }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_long_float, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(longpi)"sv), 3.141592653589793 }, + { S(R"(neglongpi)"sv), -3.141592653589793 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_long_integer, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(answer)"sv), INT64_MAX }, + { S(R"(neganswer)"sv), INT64_MIN }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_multiline_string, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(multiline_empty_one)"sv), S(R"()"sv) }, + { S(R"(multiline_empty_two)"sv), S(R"()"sv) }, + { S(R"(multiline_empty_three)"sv), S(R"()"sv) }, + { S(R"(multiline_empty_four)"sv), S(R"()"sv) }, + { S(R"(equivalent_one)"sv), S(R"(The quick brown fox jumps over the lazy dog.)"sv) }, + { S(R"(equivalent_two)"sv), S(R"(The quick brown fox jumps over the lazy dog.)"sv) }, + { S(R"(equivalent_three)"sv), S(R"(The quick brown fox jumps over the lazy dog.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_nested_inline_table_array, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::array{ + toml::table{{ + { S(R"(b)"sv), toml::table{} }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_newline_crlf, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(os)"sv), S(R"(DOS)"sv) }, + { S(R"(newline)"sv), S(R"(crlf)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_newline_lf, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(os)"sv), S(R"(unix)"sv) }, + { S(R"(newline)"sv), S(R"(lf)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_raw_multiline_string, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(oneline)"sv), S(R"(This string has a ' quote character.)"sv) }, + { S(R"(firstnl)"sv), S(R"(This string has a ' quote character.)"sv) }, + { S(R"(multiline)"sv), S(R"(This string +has ' a quote character +and more than +one newline +in it.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_raw_string, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(backspace)"sv), S(R"(This string has a \b backspace character.)"sv) }, + { S(R"(tab)"sv), S(R"(This string has a \t tab character.)"sv) }, + { S(R"(newline)"sv), S(R"(This string has a \n new line character.)"sv) }, + { S(R"(formfeed)"sv), S(R"(This string has a \f form feed character.)"sv) }, + { S(R"(carriage)"sv), S(R"(This string has a \r carriage return character.)"sv) }, + { S(R"(slash)"sv), S(R"(This string has a \/ slash character.)"sv) }, + { S(R"(backslash)"sv), S(R"(This string has a \\ backslash character.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_right_curly_brace_after_boolean, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(black)"sv), toml::table{{ + { S(R"(allow_prereleases)"sv), true }, + { S(R"(python)"sv), S(R"(>3.6)"sv) }, + { S(R"(version)"sv), S(R"(>=18.9b0)"sv) }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_string_empty, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(answer)"sv), S(R"()"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_string_nl, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(nl_mid)"sv), S(R"(val +ue)"sv) }, + { S(R"(nl_end)"sv), S(R"(value +)"sv) }, + { S(R"(lit_nl_end)"sv), S(R"(value\n)"sv) }, + { S(R"(lit_nl_mid)"sv), S(R"(val\nue)"sv) }, + { S(R"(lit_nl_uni)"sv), S(R"(val\ue)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_string_simple, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(answer)"sv), S(R"(You are not drinking enough whisky.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_string_with_pound, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(pound)"sv), S(R"(We see no # comments here.)"sv) }, + { S(R"(poundcomment)"sv), S(R"(But there are # some comments here.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_array_implicit, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(albums)"sv), toml::table{{ + { + S(R"(songs)"sv), toml::array{ + toml::table{{ + { S(R"(name)"sv), S(R"(Glory Days)"sv) }, + }}, + } + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_array_many, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(people)"sv), toml::array{ + toml::table{{ + { S(R"(first_name)"sv), S(R"(Bruce)"sv) }, + { S(R"(last_name)"sv), S(R"(Springsteen)"sv) }, + }}, + toml::table{{ + { S(R"(first_name)"sv), S(R"(Eric)"sv) }, + { S(R"(last_name)"sv), S(R"(Clapton)"sv) }, + }}, + toml::table{{ + { S(R"(first_name)"sv), S(R"(Bob)"sv) }, + { S(R"(last_name)"sv), S(R"(Seger)"sv) }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_array_nest, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(albums)"sv), toml::array{ + toml::table{{ + { S(R"(name)"sv), S(R"(Born to Run)"sv) }, + { + S(R"(songs)"sv), toml::array{ + toml::table{{ + { S(R"(name)"sv), S(R"(Jungleland)"sv) }, + }}, + toml::table{{ + { S(R"(name)"sv), S(R"(Meeting Across the River)"sv) }, + }}, + } + }, + }}, + toml::table{{ + { S(R"(name)"sv), S(R"(Born in the USA)"sv) }, + { + S(R"(songs)"sv), toml::array{ + toml::table{{ + { S(R"(name)"sv), S(R"(Glory Days)"sv) }, + }}, + toml::table{{ + { S(R"(name)"sv), S(R"(Dancing in the Dark)"sv) }, + }}, + } + }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_array_one, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(people)"sv), toml::array{ + toml::table{{ + { S(R"(first_name)"sv), S(R"(Bruce)"sv) }, + { S(R"(last_name)"sv), S(R"(Springsteen)"sv) }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_array_table_array, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::array{ + toml::table{{ + { + S(R"(b)"sv), toml::array{ + toml::table{{ + { + S(R"(c)"sv), toml::table{{ + { S(R"(d)"sv), S(R"(val0)"sv) }, + }} + }, + }}, + toml::table{{ + { + S(R"(c)"sv), toml::table{{ + { S(R"(d)"sv), S(R"(val1)"sv) }, + }} + }, + }}, + } + }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_empty, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(a)"sv), toml::table{} }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_no_eol, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(table)"sv), toml::table{} }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_sub_empty, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { S(R"(b)"sv), toml::table{} }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_whitespace, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(valid key)"sv), toml::table{} }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_with_literal_string, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { + S(R"("b")"sv), toml::table{{ + { + S(R"(c)"sv), toml::table{{ + { S(R"(answer)"sv), 42 }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_with_pound, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(key#group)"sv), toml::table{{ + { S(R"(answer)"sv), 42 }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_table_with_single_quotes, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { + S(R"(b)"sv), toml::table{{ + { + S(R"(c)"sv), toml::table{{ + { S(R"(answer)"sv), 42 }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_underscored_float, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(electron_mass)"sv), 9.109109383e-31 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_underscored_integer, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(million)"sv), 1000000 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_unicode_escape, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(answer4)"sv), S(R"(δ)"sv) }, + { S(R"(answer8)"sv), S(R"(δ)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::burntsushi_unicode_literal, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(answer)"sv), S(R"(δ)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(integers)"sv), toml::array{ + 1, + 2, + 3, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(colors)"sv), toml::array{ + S(R"(red)"sv), + S(R"(yellow)"sv), + S(R"(green)"sv), + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(nested_array_of_int)"sv), toml::array{ + toml::array{ + 1, + 2, + }, + toml::array{ + 3, + 4, + 5, + }, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_4, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(string_array)"sv), toml::array{ + S(R"(all)"sv), + S(R"(strings)"sv), + S(R"(are the same)"sv), + S(R"(type)"sv), + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_5, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(nested_mixed_array)"sv), toml::array{ + toml::array{ + 1, + 2, + }, + toml::array{ + S(R"(a)"sv), + S(R"(b)"sv), + S(R"(c)"sv), + }, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_7, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(integers2)"sv), toml::array{ + 1, + 2, + 3, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_8, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(integers3)"sv), toml::array{ + 1, + 2, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_mixed_number_types, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(numbers)"sv), toml::array{ + 0.1, + 0.2, + 0.5, + 1, + 2, + 5, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_more_mixed_types, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(contributors)"sv), toml::array{ + S(R"(Foo Bar )"sv), + toml::table{{ + { S(R"(name)"sv), S(R"(Baz Qux)"sv) }, + { S(R"(email)"sv), S(R"(bazqux@example.com)"sv) }, + { S(R"(url)"sv), S(R"(https://example.com/bazqux)"sv) }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_of_tables_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(products)"sv), toml::array{ + toml::table{{ + { S(R"(name)"sv), S(R"(Hammer)"sv) }, + { S(R"(sku)"sv), 738594937 }, + }}, + toml::table{}, + toml::table{{ + { S(R"(name)"sv), S(R"(Nail)"sv) }, + { S(R"(sku)"sv), 284758393 }, + { S(R"(color)"sv), S(R"(gray)"sv) }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_of_tables_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(fruit)"sv), toml::array{ + toml::table{{ + { S(R"(name)"sv), S(R"(apple)"sv) }, + { + S(R"(physical)"sv), toml::table{{ + { S(R"(color)"sv), S(R"(red)"sv) }, + { S(R"(shape)"sv), S(R"(round)"sv) }, + }} + }, + { + S(R"(variety)"sv), toml::array{ + toml::table{{ + { S(R"(name)"sv), S(R"(red delicious)"sv) }, + }}, + toml::table{{ + { S(R"(name)"sv), S(R"(granny smith)"sv) }, + }}, + } + }, + }}, + toml::table{{ + { S(R"(name)"sv), S(R"(banana)"sv) }, + { + S(R"(variety)"sv), toml::array{ + toml::table{{ + { S(R"(name)"sv), S(R"(plantain)"sv) }, + }}, + } + }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_array_of_tables_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(points)"sv), toml::array{ + toml::table{{ + { S(R"(x)"sv), 1 }, + { S(R"(y)"sv), 2 }, + { S(R"(z)"sv), 3 }, + }}, + toml::table{{ + { S(R"(x)"sv), 7 }, + { S(R"(y)"sv), 8 }, + { S(R"(z)"sv), 9 }, + }}, + toml::table{{ + { S(R"(x)"sv), 2 }, + { S(R"(y)"sv), 4 }, + { S(R"(z)"sv), 8 }, + }}, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_boolean_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(bool1)"sv), true }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_boolean_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(bool1)"sv), false }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_case_sensitive, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(abc)"sv), 123 }, + { S(R"(ABC)"sv), 456 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_comment_mid_array, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(abc)"sv), toml::array{ + 123, + 456, + } + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_comment_mid_string, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(another)"sv), S(R"(# This is not a comment)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_comment_tab, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(key)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_comment, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(key)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_date_local_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(ld1)"sv), toml::date{ 1979, 5, 27 } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_date_time_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(odt1)"sv), toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u }, { 0, 0 } } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_date_time_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(odt2)"sv), toml::date_time{ { 1979, 5, 27 }, { 0, 32, 0, 0u }, { -7, 0 } } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_date_time_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(odt3)"sv), toml::date_time{ { 1979, 5, 27 }, { 0, 32, 0, 999999000u }, { -7, 0 } } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_date_time_4, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(odt4)"sv), toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u }, { 0, 0 } } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_date_time_5, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(odt5)"sv), toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 123000000u }, { 0, 0 } } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_date_time_local_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(ldt1)"sv), toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u } } }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_dotted_keys_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(name)"sv), S(R"(Orange)"sv) }, + { + S(R"(physical)"sv), toml::table{{ + { S(R"(color)"sv), S(R"(orange)"sv) }, + { S(R"(shape)"sv), S(R"(round)"sv) }, + }} + }, + { + S(R"(site)"sv), toml::table{{ + { S(R"(google.com)"sv), true }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_dotted_keys_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { S(R"(b)"sv), 23 }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_dotted_keys_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { S(R"(b)"sv), 23 }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_empty_key_name_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"()"sv), S(R"(blank)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_empty_key_name_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"()"sv), S(R"(blank)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_extend_dotted_object_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(fruit)"sv), toml::table{{ + { + S(R"(apple)"sv), toml::table{{ + { S(R"(smooth)"sv), true }, + }} + }, + { S(R"(orange)"sv), 2 }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_extend_dotted_object_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(apple)"sv), toml::table{{ + { S(R"(type)"sv), S(R"(fruit)"sv) }, + { S(R"(skin)"sv), S(R"(thin)"sv) }, + { S(R"(color)"sv), S(R"(red)"sv) }, + }} + }, + { + S(R"(orange)"sv), toml::table{{ + { S(R"(type)"sv), S(R"(fruit)"sv) }, + { S(R"(skin)"sv), S(R"(thick)"sv) }, + { S(R"(color)"sv), S(R"(orange)"sv) }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_extend_dotted_object_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(apple)"sv), toml::table{{ + { S(R"(type)"sv), S(R"(fruit)"sv) }, + { S(R"(skin)"sv), S(R"(thin)"sv) }, + { S(R"(color)"sv), S(R"(red)"sv) }, + }} + }, + { + S(R"(orange)"sv), toml::table{{ + { S(R"(type)"sv), S(R"(fruit)"sv) }, + { S(R"(skin)"sv), S(R"(thick)"sv) }, + { S(R"(color)"sv), S(R"(orange)"sv) }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt1)"sv), 1.0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_10, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(sf1)"sv), std::numeric_limits::infinity() }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_11, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(sf2)"sv), std::numeric_limits::infinity() }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_12, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(sf2)"sv), -std::numeric_limits::infinity() }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_13, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(sf4)"sv), std::numeric_limits::quiet_NaN() }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_14, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(sf5)"sv), std::numeric_limits::quiet_NaN() }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_15, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(sf6)"sv), std::numeric_limits::quiet_NaN() }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt2)"sv), 3.1415 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt3)"sv), -0.01 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_4, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt4)"sv), 5e+22 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_5, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt5)"sv), 1000000.0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_6, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt6)"sv), -0.02 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_7, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt7)"sv), 6.626e-34 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_8, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt8)"sv), 224617.445991228 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_float_9, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(flt9)"sv), -0.0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int1)"sv), 99 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int2)"sv), 42 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int3)"sv), 0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_3a, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int3)"sv), 0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_3b, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int3)"sv), 0 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_4, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int4)"sv), -17 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_5, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int5)"sv), 1000 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_6, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int6)"sv), 5349221 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_7, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(int7)"sv), 12345 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_bin1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(bin1)"sv), 214 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_hex1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(hex1)"sv), 3735928559 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_hex2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(hex2)"sv), 3735928559 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_hex3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(hex3)"sv), 3735928559 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_max, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(max)"sv), INT64_MAX }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_min, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(min)"sv), INT64_MIN }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_oct1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(oct1)"sv), 342391 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_int_oct2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(oct2)"sv), 493 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(key)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(bare_key)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(bare-key)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_4, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(1234)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_5, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(1234)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_6, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(-)"sv), 1 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_7, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(_)"sv), 1 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_8, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(-_-_-_-_-)"sv), 1 }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_key_value_pair_9, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(3)"sv), toml::table{{ + { S(R"(14159)"sv), S(R"(pi)"sv) }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_quoted_basic_keys_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(ʎǝʞ)"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_quoted_literal_keys_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(quoted "value")"sv), S(R"(value)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_readme_example, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(title)"sv), S(R"(TOML Example)"sv) }, + { + S(R"(owner)"sv), toml::table{{ + { S(R"(name)"sv), S(R"(Tom Preston-Werner)"sv) }, + { S(R"(dob)"sv), toml::date_time{ { 1979, 5, 27 }, { 7, 32, 0, 0u }, { -8, 0 } } }, + }} + }, + { + S(R"(database)"sv), toml::table{{ + { S(R"(server)"sv), S(R"(192.168.1.1)"sv) }, + { + S(R"(ports)"sv), toml::array{ + 8001, + 8001, + 8002, + } + }, + { S(R"(connection_max)"sv), 5000 }, + { S(R"(enabled)"sv), true }, + }} + }, + { + S(R"(servers)"sv), toml::table{{ + { + S(R"(alpha)"sv), toml::table{{ + { S(R"(ip)"sv), S(R"(10.0.0.1)"sv) }, + { S(R"(dc)"sv), S(R"(eqdc10)"sv) }, + }} + }, + { + S(R"(beta)"sv), toml::table{{ + { S(R"(ip)"sv), S(R"(10.0.0.2)"sv) }, + { S(R"(dc)"sv), S(R"(eqdc10)"sv) }, + }} + }, + }} + }, + { + S(R"(clients)"sv), toml::table{{ + { + S(R"(data)"sv), toml::array{ + toml::array{ + S(R"(gamma)"sv), + S(R"(delta)"sv), + }, + toml::array{ + 1, + 2, + }, + } + }, + { + S(R"(hosts)"sv), toml::array{ + S(R"(alpha)"sv), + S(R"(omega)"sv), + } + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_multiline_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str1)"sv), S(R"(Roses are red +Violets are blue)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_multiline_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str)"sv), S(R"(The quick brown fox jumps over the lazy dog.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_multiline_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str)"sv), S(R"(The quick brown fox jumps over the lazy dog.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_multiline_5, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(ml-escaped-nl)"sv), S(R"( foo bar \ + baz \quux)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_multiline_6, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str4)"sv), S(R"(Here are two quotation marks: "". Simple enough.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_multiline_7, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str5)"sv), S(R"(Here are three quotation marks: """.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_multiline_8, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str6)"sv), S(R"(Here are fifteen quotation marks: """"""""""""""".)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_multiline_9, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str7)"sv), S(R"("This," she said, "is just a pointless statement.")"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_tab_multiline, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str)"sv), S(R"(This is a tab)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic_tab, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str)"sv), S(R"(This is a tab)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_basic, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str)"sv), S(R"(I'm a string. "You can quote me". Name José +Location SF.)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_literal_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(winpath)"sv), S(R"(C:\Users\nodejs\templates)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_literal_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(winpath2)"sv), S(R"(\\ServerX\admin$\system32\)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_literal_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(quoted)"sv), S(R"(Tom "Dubs" Preston-Werner)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_literal_4, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(regex)"sv), S(R"(<\i\c*\s*>)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_literal_multiline_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(regex2)"sv), S(R"(I [dw]on't need \d{2} apples)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_literal_multiline_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(lines)"sv), S(R"(The first newline is +trimmed in raw strings. + All other whitespace + is preserved. +)"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_literal_multiline_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(quot15)"sv), S(R"(Here are fifteen quotation marks: """"""""""""""")"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_string_literal_multiline_4, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(str)"sv), S(R"('That,' she said, 'is still pointless.')"sv) }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(table-1)"sv), toml::table{{ + { S(R"(key1)"sv), S(R"(some string)"sv) }, + { S(R"(key2)"sv), 123 }, + }} + }, + { + S(R"(table-2)"sv), toml::table{{ + { S(R"(key1)"sv), S(R"(another string)"sv) }, + { S(R"(key2)"sv), 456 }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(dog)"sv), toml::table{{ + { + S(R"(tater.man)"sv), toml::table{{ + { + S(R"(type)"sv), toml::table{{ + { S(R"(name)"sv), S(R"(pug)"sv) }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(a)"sv), toml::table{{ + { + S(R"(b)"sv), toml::table{{ + { S(R"(c)"sv), toml::table{} }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_4, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(d)"sv), toml::table{{ + { + S(R"(e)"sv), toml::table{{ + { S(R"(f)"sv), toml::table{} }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_5, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(g)"sv), toml::table{{ + { + S(R"(h)"sv), toml::table{{ + { S(R"(i)"sv), toml::table{} }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_6, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(j)"sv), toml::table{{ + { + S(R"(ʞ)"sv), toml::table{{ + { S(R"(l)"sv), toml::table{} }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_7, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(x)"sv), toml::table{{ + { + S(R"(y)"sv), toml::table{{ + { + S(R"(z)"sv), toml::table{{ + { S(R"(w)"sv), toml::table{} }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_8, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(fruit)"sv), toml::table{{ + { + S(R"(apple)"sv), toml::table{{ + { S(R"(color)"sv), S(R"(red)"sv) }, + { + S(R"(taste)"sv), toml::table{{ + { S(R"(sweet)"sv), true }, + }} + }, + { + S(R"(texture)"sv), toml::table{{ + { S(R"(smooth)"sv), true }, + }} + }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_inline_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(name)"sv), toml::table{{ + { S(R"(first)"sv), S(R"(Tom)"sv) }, + { S(R"(last)"sv), S(R"(Preston-Werner)"sv) }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_inline_2, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(point)"sv), toml::table{{ + { S(R"(x)"sv), 1 }, + { S(R"(y)"sv), 2 }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table_inline_3, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { + S(R"(animal)"sv), toml::table{{ + { + S(R"(type)"sv), toml::table{{ + { S(R"(name)"sv), S(R"(pug)"sv) }, + }} + }, + }} + }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_table, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(table)"sv), toml::table{} }, + }}; + REQUIRE(tbl == expected); + }); + + parsing_should_succeed(FILE_LINE_ARGS, valid::iarna_spec_time_1, [](toml::table&& tbl) + { + auto expected = toml::table{{ + { S(R"(lt1)"sv), toml::time{ 7, 32, 0, 0 } }, + }}; + REQUIRE(tbl == expected); + }); + + #if !TOML_LANG_UNRELEASED + #endif // !TOML_LANG_UNRELEASED + } + #endif + + //------------------ invalid inputs ------------------------------------------------------------------------------ + #if 1 + { + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_datetime_malformed_no_leads); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_datetime_malformed_no_t); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_datetime_malformed_with_milli); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_duplicate_key_table); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_duplicate_keys); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_duplicate_tables); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_empty_implicit_table); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_empty_table); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_leading_zero_neg); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_leading_zero_pos); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_leading_zero); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_no_leading_zero); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_no_trailing_digits); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_underscore_after_point); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_underscore_after); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_underscore_before_point); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_float_underscore_before); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_integer_leading_zero_neg); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_integer_leading_zero_pos); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_integer_leading_zero); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_integer_underscore_after); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_integer_underscore_before); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_integer_underscore_double); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_after_array); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_after_table); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_empty); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_hash); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_newline); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_no_eol); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_open_bracket); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_single_open_bracket); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_space); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_start_bracket); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_key_two_equals); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_llbrace); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_multi_line_string_no_close); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_rrbrace); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_string_bad_byte_escape); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_string_bad_codepoint); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_string_bad_escape); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_string_bad_slash_escape); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_string_bad_uni_esc); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_string_no_close); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_table_array_implicit); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_table_array_malformed_bracket); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_table_array_malformed_empty); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_table_empty); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_table_nested_brackets_close); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_table_nested_brackets_open); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_table_whitespace); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_table_with_pound); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_text_after_array_entries); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_text_after_integer); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_text_after_string); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_text_after_table); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_text_before_array_separator); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_text_in_array); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_array_of_tables_1); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_array_of_tables_2); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_bare_key_1); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_bare_key_2); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_bare_key_3); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_inline_table_imutable_1); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_inline_table_imutable_2); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_int_0_padded); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_int_signed_bin); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_int_signed_hex); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_int_signed_oct); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_key_value_pair_1); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_key_value_pair_2); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_multiple_dot_key); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_multiple_key); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_no_key_name); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_basic_multiline_invalid_backslash); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_basic_multiline_out_of_range_unicode_escape_1); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_basic_multiline_out_of_range_unicode_escape_2); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_basic_multiline_quotes); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_basic_multiline_unknown_escape); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_basic_out_of_range_unicode_escape_1); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_basic_out_of_range_unicode_escape_2); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_basic_unknown_escape); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_string_literal_multiline_quotes); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_table_1); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_table_2); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_table_3); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_table_4); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_table_invalid_1); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_table_invalid_2); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_table_invalid_3); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_table_invalid_4); + + #if !TOML_LANG_UNRELEASED + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_datetime_malformed_no_secs); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_inline_table_linebreak); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_multi_line_inline_table); + parsing_should_fail(FILE_LINE_ARGS, invalid::burntsushi_string_byte_escapes); + parsing_should_fail(FILE_LINE_ARGS, invalid::iarna_inline_table_trailing_comma); + #endif // !TOML_LANG_UNRELEASED + } + #endif + +} -#endif // !TOML_UNRELEASED_FEATURES diff --git a/tests/impl_catch2.cpp b/tests/impl_catch2.cpp index 5308311..c53729e 100644 --- a/tests/impl_catch2.cpp +++ b/tests/impl_catch2.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #define CATCH_CONFIG_RUNNER #include "catch2.h" #include diff --git a/tests/impl_toml.cpp b/tests/impl_toml.cpp index d363dad..9a0ba33 100644 --- a/tests/impl_toml.cpp +++ b/tests/impl_toml.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "settings.h" #if !TOML_ALL_INLINE #define TOML_IMPLEMENTATION diff --git a/tests/manipulating_arrays.cpp b/tests/manipulating_arrays.cpp index 83af5ff..30418ae 100644 --- a/tests/manipulating_arrays.cpp +++ b/tests/manipulating_arrays.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("arrays - moving") diff --git a/tests/manipulating_parse_result.cpp b/tests/manipulating_parse_result.cpp index 908f698..d683580 100644 --- a/tests/manipulating_parse_result.cpp +++ b/tests/manipulating_parse_result.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" #if !TOML_EXCEPTIONS diff --git a/tests/manipulating_tables.cpp b/tests/manipulating_tables.cpp index 885ec02..09b9043 100644 --- a/tests/manipulating_tables.cpp +++ b/tests/manipulating_tables.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("tables - moving") diff --git a/tests/manipulating_values.cpp b/tests/manipulating_values.cpp index 497f000..6e203ad 100644 --- a/tests/manipulating_values.cpp +++ b/tests/manipulating_values.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("values - printing") diff --git a/tests/parsing_arrays.cpp b/tests/parsing_arrays.cpp index ecf7fa1..82ef636 100644 --- a/tests/parsing_arrays.cpp +++ b/tests/parsing_arrays.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("parsing - arrays") diff --git a/tests/parsing_booleans.cpp b/tests/parsing_booleans.cpp index 89e9449..a45be41 100644 --- a/tests/parsing_booleans.cpp +++ b/tests/parsing_booleans.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("parsing - booleans") diff --git a/tests/parsing_comments.cpp b/tests/parsing_comments.cpp index b044000..f2cf863 100644 --- a/tests/parsing_comments.cpp +++ b/tests/parsing_comments.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("parsing - comments") diff --git a/tests/parsing_dates_and_times.cpp b/tests/parsing_dates_and_times.cpp index 3945d09..7148ca7 100644 --- a/tests/parsing_dates_and_times.cpp +++ b/tests/parsing_dates_and_times.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TOML_PUSH_WARNINGS diff --git a/tests/parsing_floats.cpp b/tests/parsing_floats.cpp index a4a9063..a0d74b3 100644 --- a/tests/parsing_floats.cpp +++ b/tests/parsing_floats.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TOML_DISABLE_FLOAT_WARNINGS diff --git a/tests/parsing_integers.cpp b/tests/parsing_integers.cpp index 8c091a2..373b911 100644 --- a/tests/parsing_integers.cpp +++ b/tests/parsing_integers.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("parsing - integers (decimal)") diff --git a/tests/parsing_key_value_pairs.cpp b/tests/parsing_key_value_pairs.cpp index 5fc9011..f28b1e1 100644 --- a/tests/parsing_key_value_pairs.cpp +++ b/tests/parsing_key_value_pairs.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("parsing - key-value pairs") diff --git a/tests/parsing_spec_example.cpp b/tests/parsing_spec_example.cpp index 721f468..ac57097 100644 --- a/tests/parsing_spec_example.cpp +++ b/tests/parsing_spec_example.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TOML_PUSH_WARNINGS diff --git a/tests/parsing_strings.cpp b/tests/parsing_strings.cpp index f0b6b7d..025dc6c 100644 --- a/tests/parsing_strings.cpp +++ b/tests/parsing_strings.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("parsing - strings") diff --git a/tests/parsing_tables.cpp b/tests/parsing_tables.cpp index 9879944..a85fec7 100644 --- a/tests/parsing_tables.cpp +++ b/tests/parsing_tables.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" TEST_CASE("parsing - tables") diff --git a/tests/settings.h b/tests/settings.h index 3957b0e..e5744e6 100644 --- a/tests/settings.h +++ b/tests/settings.h @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #pragma once // toml++ config diff --git a/tests/tests.cpp b/tests/tests.cpp index 7574ddf..de089b6 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" template bool parse_expected_value(std::string_view, uint32_t, std::string_view, const int&); diff --git a/tests/unicode.cpp b/tests/unicode.cpp index 4200d7a..89b7c5d 100644 --- a/tests/unicode.cpp +++ b/tests/unicode.cpp @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #include "tests.h" #include "unicode.h" using namespace toml::impl; diff --git a/tests/unicode.h b/tests/unicode.h index f815677..6835032 100644 --- a/tests/unicode.h +++ b/tests/unicode.h @@ -1,3 +1,8 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + #pragma once #include "tests.h" diff --git a/tests/unicode_generated.cpp b/tests/unicode_generated.cpp index 260a0e1..4af210c 100644 --- a/tests/unicode_generated.cpp +++ b/tests/unicode_generated.cpp @@ -1,3 +1,10 @@ +//# This file is a part of toml++ and is subject to the the terms of the MIT license. +//# Copyright (c) 2019-2020 Mark Gillard +//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT +//#----- +//# this file was generated by generate_unicode_functions.py - do not modify it directly + #include "tests.h" #include "unicode.h" using namespace toml::impl; diff --git a/toml.hpp b/toml.hpp index 0fb5f32..a5007dc 100644 --- a/toml.hpp +++ b/toml.hpp @@ -889,6 +889,13 @@ namespace toml #if !TOML_ALL_INLINE extern template TOML_API std::ostream& operator << (std::ostream&, node_type); #endif + + template + struct TOML_TRIVIAL_ABI inserter + { + T&& value; + }; + template inserter(T&&) -> inserter; } #endif @@ -2098,7 +2105,26 @@ namespace toml return *this; } - [[nodiscard]] friend bool operator == (const value& lhs, value_arg rhs) noexcept { return lhs.val_ == rhs; } + [[nodiscard]] friend bool operator == (const value& lhs, value_arg rhs) noexcept + { + if constexpr (std::is_same_v) + { + static constexpr auto pack = [](auto l, auto r) constexpr noexcept + { + return ((static_cast(l) << 32) | static_cast(r)); + }; + + switch (pack(std::fpclassify(lhs.val_), std::fpclassify(rhs))) + { + case pack(FP_INFINITE, FP_INFINITE): return (lhs.val_ < 0.0) == (rhs < 0.0); + case pack(FP_NAN, FP_NAN): return true; + default: return lhs.val_ == rhs; + } + } + else + return lhs.val_ == rhs; + + } TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, ) [[nodiscard]] friend bool operator < (const value& lhs, value_arg rhs) noexcept { return lhs.val_ < rhs; } [[nodiscard]] friend bool operator < (value_arg lhs, const value& rhs) noexcept { return lhs < rhs.val_; } @@ -2113,7 +2139,7 @@ namespace toml [[nodiscard]] friend bool operator == (const value& lhs, const value& rhs) noexcept { if constexpr (std::is_same_v) - return lhs.val_ == rhs.val_; + return lhs == rhs.val_; //calls asymmetrical value-equality operator defined above else return false; } @@ -2531,6 +2557,14 @@ namespace toml::impl return new value{ std::forward(val) }; } } + + template + [[nodiscard]] + TOML_ALWAYS_INLINE + auto make_node(inserter&& val) noexcept + { + return make_node(std::move(val.value)); + } } namespace toml @@ -3448,7 +3482,7 @@ namespace toml::impl return cp >= U'0' && cp <= U'f' && (1ull << (static_cast(cp) - 0x30ull)) & 0x7E0000007E03FFull; } - #if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys) +#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys) [[nodiscard]] TOML_GNU_ATTR(const) @@ -4142,7 +4176,7 @@ namespace toml::impl } } - #endif // TOML_LANG_UNRELEASED +#endif // TOML_LANG_UNRELEASED } // toml::impl #endif @@ -7246,9 +7280,14 @@ namespace toml::impl // handle 'line ending slashes' in multi-line mode if constexpr (MultiLine) { - if (is_line_break(*cp)) + //consume_leading_whitespace + if (is_line_break(*cp) || is_whitespace(*cp)) { - consume_line_break(); + consume_leading_whitespace(); + if (!consume_line_break()) + set_error_and_return_default( + "line-ending backslashes must be the last non-whitespace character on the line"sv + ); skipping_whitespace = true; return_if_error({}); continue;