summaryrefslogtreecommitdiff
path: root/tomlplusplus/tests/manipulating_tables.cpp
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:44:05 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:44:05 +0300
commit0b24459ac12b6cf9fd5a401d647796ca254a8fa8 (patch)
treef2fd66e2476976a51e2a51330fd95dc6e87b24c1 /tomlplusplus/tests/manipulating_tables.cpp
parentb85e90fc3480da0e6a48da73201a0b22488cc650 (diff)
parent1c8b7466e4946fcc3bf20484c0e1d001202cca5a (diff)
downloadProject-Tick-0b24459ac12b6cf9fd5a401d647796ca254a8fa8.tar.gz
Project-Tick-0b24459ac12b6cf9fd5a401d647796ca254a8fa8.zip
Add 'tomlplusplus/' from commit '1c8b7466e4946fcc3bf20484c0e1d001202cca5a'
git-subtree-dir: tomlplusplus git-subtree-mainline: b85e90fc3480da0e6a48da73201a0b22488cc650 git-subtree-split: 1c8b7466e4946fcc3bf20484c0e1d001202cca5a
Diffstat (limited to 'tomlplusplus/tests/manipulating_tables.cpp')
-rw-r--r--tomlplusplus/tests/manipulating_tables.cpp760
1 files changed, 760 insertions, 0 deletions
diff --git a/tomlplusplus/tests/manipulating_tables.cpp b/tomlplusplus/tests/manipulating_tables.cpp
new file mode 100644
index 0000000000..56f7b3bf3c
--- /dev/null
+++ b/tomlplusplus/tests/manipulating_tables.cpp
@@ -0,0 +1,760 @@
+// This file is a part of toml++ and is subject to the the terms of the MIT license.
+// Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
+
+#include "tests.hpp"
+
+TEST_CASE("tables - moving")
+{
+ static constexpr auto filename = "foo.toml"sv;
+
+ parsing_should_succeed(
+ FILE_LINE_ARGS,
+ R"(test = { val1 = "foo" })"sv,
+ [&](table&& tbl)
+ {
+ // sanity-check initial state of a freshly-parsed table
+ REQUIRE(tbl["test"].as<table>());
+ CHECK(tbl["test"].as<table>()->size() == 1u);
+ CHECK(tbl["test"].as<table>()->source().begin == source_position{ 1, 8 });
+ CHECK(tbl["test"].as<table>()->source().end == source_position{ 1, 24 });
+ CHECK(tbl["test"].node() == tbl.get("test"sv));
+ CHECK(tbl["test"].node() == &tbl.at("test"sv));
+
+ // sanity-check initial state of a freshly-parsed table (const)
+ const table& ctbl = tbl;
+ REQUIRE(ctbl["test"].as<table>());
+ CHECK(ctbl["test"].as<table>()->size() == 1u);
+ CHECK(ctbl["test"].as<table>()->source().begin == source_position{ 1, 8 });
+ CHECK(ctbl["test"].as<table>()->source().end == source_position{ 1, 24 });
+ CHECK(ctbl["test"].node() == ctbl.get("test"sv));
+ CHECK(ctbl["test"].node() == &ctbl.at("test"sv));
+
+ // sanity check the virtual type checks
+ CHECK(tbl.type() == node_type::table);
+ CHECK(tbl.is_table());
+ CHECK(!tbl.is_array());
+ CHECK(!tbl.is_array_of_tables());
+ CHECK(!tbl.is_value());
+ CHECK(!tbl.is_string());
+ CHECK(!tbl.is_integer());
+ CHECK(!tbl.is_floating_point());
+ CHECK(!tbl.is_number());
+ CHECK(!tbl.is_boolean());
+ CHECK(!tbl.is_date());
+ CHECK(!tbl.is_time());
+ CHECK(!tbl.is_date_time());
+
+ // sanity check the virtual type casts (non-const)
+ CHECK(tbl.as_table() == &tbl);
+ CHECK(!tbl.as_array());
+ CHECK(!tbl.as_string());
+ CHECK(!tbl.as_integer());
+ CHECK(!tbl.as_floating_point());
+ CHECK(!tbl.as_boolean());
+ CHECK(!tbl.as_date());
+ CHECK(!tbl.as_time());
+ CHECK(!tbl.as_date_time());
+
+ // sanity check the virtual type casts (const)
+ CHECK(ctbl.as_table() == &ctbl);
+ CHECK(!ctbl.as_array());
+ CHECK(!ctbl.as_string());
+ CHECK(!ctbl.as_integer());
+ CHECK(!ctbl.as_floating_point());
+ CHECK(!ctbl.as_boolean());
+ CHECK(!ctbl.as_date());
+ CHECK(!ctbl.as_time());
+ CHECK(!ctbl.as_date_time());
+
+ // sanity-check initial state of default-constructed table
+ table tbl2;
+ CHECK(tbl2.source().begin == source_position{});
+ CHECK(tbl2.source().end == source_position{});
+ CHECK(!tbl2.source().path);
+ CHECK(tbl2.size() == 0u);
+
+ // check the results of move-assignment
+ tbl2 = std::move(tbl);
+ CHECK(tbl2.source().begin == source_position{ 1, 1 });
+ CHECK(tbl2.source().end == source_position{ 1, 24 });
+ CHECK(tbl2.source().path);
+ CHECK(*tbl2.source().path == filename);
+ CHECK(tbl2.size() == 1u);
+ REQUIRE(tbl2["test"].as<table>());
+ CHECK(tbl2["test"].as<table>()->size() == 1u);
+ CHECK(tbl2["test"]["val1"] == "foo"sv);
+
+ // check that moved-from table is now the same as default-constructed
+ CHECK(tbl.source().begin == source_position{});
+ CHECK(tbl.source().end == source_position{});
+ CHECK(!tbl.source().path);
+ CHECK(tbl.size() == 0u);
+ CHECK(!tbl["test"].as<table>());
+
+ // check the results of move-construction
+ table tbl3{ std::move(tbl2) };
+ CHECK(tbl3.source().begin == source_position{ 1, 1 });
+ CHECK(tbl3.source().end == source_position{ 1, 24 });
+ CHECK(tbl3.source().path);
+ CHECK(*tbl3.source().path == filename);
+ CHECK(tbl3.size() == 1u);
+ REQUIRE(tbl3["test"].as<table>());
+ CHECK(tbl3["test"].as<table>()->size() == 1u);
+ CHECK(tbl3["test"]["val1"] == "foo"sv);
+
+ // check that moved-from table is now the same as default-constructed
+ CHECK(tbl2.source().begin == source_position{});
+ CHECK(tbl2.source().end == source_position{});
+ CHECK(!tbl2.source().path);
+ CHECK(tbl2.size() == 0u);
+ CHECK(!tbl2["test"].as<table>());
+ },
+ filename);
+}
+
+TEST_CASE("tables - copying")
+{
+ static constexpr auto filename = "foo.toml"sv;
+
+ parsing_should_succeed(
+ FILE_LINE_ARGS,
+ R"(test = { val1 = "foo" })"sv,
+ [&](table&& tbl)
+ {
+ // sanity-check initial state of a freshly-parsed table
+ REQUIRE(tbl["test"].as<table>());
+ CHECK(tbl["test"].as<table>()->size() == 1u);
+ CHECK(tbl["test"].as<table>()->source().begin == source_position{ 1, 8 });
+ CHECK(tbl["test"].as<table>()->source().end == source_position{ 1, 24 });
+ CHECK(tbl["test"]["val1"] == "foo");
+
+ // sanity-check initial state of default-constructed table
+ table tbl2;
+ CHECK(tbl2.source().begin == source_position{});
+ CHECK(tbl2.source().end == source_position{});
+ CHECK(!tbl2.source().path);
+ CHECK(tbl2.size() == 0u);
+
+ // check the results of copy-assignment
+ tbl2 = tbl;
+ CHECK(tbl2.source().begin == source_position{});
+ CHECK(tbl2.source().end == source_position{});
+ CHECK(!tbl2.source().path);
+ CHECK(tbl2.size() == 1u);
+ REQUIRE(tbl2["test"].as<table>());
+ CHECK(tbl2["test"].as<table>()->size() == 1u);
+ CHECK(tbl2["test"]["val1"] == "foo"sv);
+ CHECK(tbl2 == tbl);
+
+ // check the results of copy-construction
+ table tbl3{ tbl2 };
+ CHECK(tbl3.source().begin == source_position{});
+ CHECK(tbl3.source().end == source_position{});
+ CHECK(!tbl3.source().path);
+ CHECK(tbl3.size() == 1u);
+ REQUIRE(tbl3["test"].as<table>());
+ CHECK(tbl3["test"].as<table>()->size() == 1u);
+ CHECK(tbl3["test"]["val1"] == "foo"sv);
+ CHECK(tbl3 == tbl2);
+ CHECK(tbl3 == tbl);
+ },
+ filename);
+}
+
+TEST_CASE("tables - construction")
+{
+ {
+ table tbl;
+ CHECK(tbl.size() == 0u);
+ CHECK(tbl.empty());
+ CHECK(tbl.begin() == tbl.end());
+ CHECK(tbl.cbegin() == tbl.cend());
+ CHECK(tbl.source().begin == source_position{});
+ CHECK(tbl.source().end == source_position{});
+ CHECK(!tbl.source().path);
+ }
+
+ {
+ table tbl{ { "foo"sv, 42 } };
+ CHECK(tbl.size() == 1u);
+ CHECK(!tbl.empty());
+ CHECK(tbl.begin() != tbl.end());
+ CHECK(tbl.cbegin() != tbl.cend());
+ REQUIRE(tbl.get_as<int64_t>("foo"sv));
+ CHECK(*tbl.get_as<int64_t>("foo"sv) == 42);
+ }
+
+ {
+ table tbl{ { "foo"sv, 42 }, { "bar"sv, 10.0 }, { "kek"sv, false }, { "qux"sv, array{ 1 } } };
+ CHECK(tbl.size() == 4u);
+ CHECK(!tbl.empty());
+ REQUIRE(tbl.get_as<int64_t>("foo"sv));
+ CHECK(*tbl.get_as<int64_t>("foo"sv) == 42);
+ REQUIRE(tbl.get_as<double>("bar"sv));
+ CHECK(*tbl.get_as<double>("bar"sv) == 10.0);
+ REQUIRE(tbl.get_as<bool>("kek"sv));
+ CHECK(*tbl.get_as<bool>("kek"sv) == false);
+ REQUIRE(tbl.get_as<array>("qux"sv));
+ CHECK(*tbl.get_as<array>("qux"sv) == array{ 1 });
+ }
+
+#if TOML_ENABLE_WINDOWS_COMPAT
+ {
+ table tbl{ { L"foo", L"test1" },
+ { L"bar"sv, L"test2"sv },
+ { L"kek"s, L"test3"sv },
+ { L"qux"sv.data(), L"test4"sv.data() } };
+ CHECK(tbl.size() == 4u);
+ CHECK(!tbl.empty());
+ REQUIRE(tbl.get_as<std::string>("foo"sv));
+ CHECK(*tbl.get_as<std::string>("foo"sv) == "test1"sv);
+ REQUIRE(tbl.get_as<std::string>("bar"sv));
+ CHECK(*tbl.get_as<std::string>("bar"sv) == "test2"sv);
+ REQUIRE(tbl.get_as<std::string>("kek"sv));
+ CHECK(*tbl.get_as<std::string>("kek"sv) == "test3"sv);
+ REQUIRE(tbl.get_as<std::string>("qux"sv));
+ CHECK(*tbl.get_as<std::string>("qux"sv) == "test4"sv);
+ }
+#endif // TOML_ENABLE_WINDOWS_COMPAT
+}
+
+TEST_CASE("tables - equality")
+{
+ static constexpr const char* one = "one";
+
+ table tbl1{ { one, 1 }, { "two", 2 }, { "three", 3 } };
+ CHECK(tbl1 == tbl1);
+
+ table tbl2{ { "one"sv, 1 }, { "two"sv, 2 }, { "three"sv, 3 } };
+ CHECK(tbl1 == tbl2);
+
+ table tbl3{ { "one"sv, 1 }, { "two"sv, 2 } };
+ CHECK(tbl1 != tbl3);
+
+ table tbl4{ { "one"sv, 1 }, { "two"sv, 2 }, { "three"sv, 3 }, { "four"sv, 4 } };
+ CHECK(tbl1 != tbl4);
+
+ table tbl5{ { "one"sv, 1 }, { "two"sv, 2 }, { "three"sv, 3.0 } };
+ CHECK(tbl1 != tbl5);
+
+ table tbl6;
+ CHECK(tbl1 != tbl6);
+ CHECK(tbl6 == tbl6);
+
+ table tbl7;
+ CHECK(tbl6 == tbl7);
+}
+
+namespace
+{
+ template <typename T>
+ static auto advance(T iter, ptrdiff_t offset)
+ {
+ while (offset > 0)
+ {
+ iter++;
+ offset--;
+ }
+ while (offset < 0)
+ {
+ iter--;
+ offset++;
+ }
+ return iter;
+ }
+}
+
+TEST_CASE("tables - insertion and erasure")
+{
+ table tbl;
+ auto res = tbl.insert("a", 42);
+ CHECK(res.first == tbl.begin());
+ CHECK(res.second == true);
+ CHECK(tbl.size() == 1u);
+ CHECK(!tbl.empty());
+ REQUIRE(tbl.get_as<int64_t>("a"sv));
+ CHECK(*tbl.get_as<int64_t>("a"sv) == 42);
+ REQUIRE(tbl == table{ { "a"sv, 42 } });
+
+ res = tbl.insert("a", 69);
+ CHECK(res.first == tbl.begin());
+ CHECK(res.second == false);
+ CHECK(tbl.size() == 1u);
+ REQUIRE(tbl.get_as<int64_t>("a"));
+ CHECK(*tbl.get_as<int64_t>("a") == 42);
+ REQUIRE(tbl == table{ { "a"sv, 42 } });
+
+ static constexpr const char* a = "a";
+ res = tbl.insert_or_assign(a, 69);
+ CHECK(res.first == tbl.begin());
+ CHECK(res.second == false); // should assign
+ CHECK(tbl.size() == 1u);
+ REQUIRE(tbl.get_as<int64_t>("a"));
+ CHECK(*tbl.get_as<int64_t>("a") == 69);
+ REQUIRE(tbl == table{ { "a"sv, 69 } });
+
+ res = tbl.insert_or_assign("b", "kek");
+ CHECK(res.first == advance(tbl.begin(), 1));
+ CHECK(res.second == true); // should insert
+ CHECK(tbl.size() == 2u);
+ REQUIRE(tbl.get_as<std::string>("b"));
+ CHECK(*tbl.get_as<std::string>("b") == "kek"sv);
+ REQUIRE(tbl == table{ { "a"sv, 69 }, { "b"sv, "kek" } });
+
+ res = tbl.emplace<array>("c", 1, 2, 3);
+ CHECK(res.first == advance(tbl.begin(), 2));
+ CHECK(res.second == true);
+ CHECK(tbl.size() == 3u);
+ REQUIRE(tbl.get_as<array>("c"));
+ CHECK(*tbl.get_as<array>("c") == array{ 1, 2, 3 });
+ REQUIRE(tbl == table{ { "a"sv, 69 }, { "b"sv, "kek"sv }, { "c"sv, array{ 1, 2, 3 } } });
+
+ res = tbl.emplace<int64_t>("c", 1);
+ CHECK(res.first == advance(tbl.begin(), 2));
+ CHECK(res.second == false);
+ CHECK(tbl.size() == 3u);
+ REQUIRE(!tbl.get_as<int64_t>("c"));
+ REQUIRE(tbl.get_as<array>("c"));
+ REQUIRE(tbl == table{ { "a"sv, 69 }, { "b"sv, "kek"s }, { "c"sv, array{ 1, 2, 3 } } });
+
+ auto it = tbl.erase(tbl.cbegin());
+ REQUIRE(tbl == table{ { { "b"sv, "kek" }, { "c"sv, array{ 1, 2, 3 } } } });
+ CHECK(it == tbl.begin());
+ CHECK(tbl.size() == 2u);
+
+ res = tbl.insert_or_assign("a"sv, 69);
+ CHECK(res.first == tbl.begin());
+ CHECK(res.second == true); // should insert
+ CHECK(tbl.size() == 3u);
+ REQUIRE(tbl.get_as<int64_t>("a"));
+ CHECK(*tbl.get_as<int64_t>("a") == 69);
+ REQUIRE(tbl == table{ { "a"sv, 69 }, { "b"sv, "kek" }, { "c"sv, array{ 1, 2, 3 } } });
+
+ it = tbl.erase(advance(tbl.cbegin(), 1), advance(tbl.cbegin(), 3));
+ REQUIRE(tbl == table{ { "a"sv, 69 } });
+ CHECK(it == tbl.end());
+ CHECK(tbl.size() == 1u);
+
+ tbl.clear();
+ REQUIRE(tbl == table{});
+ CHECK(tbl.size() == 0u);
+ CHECK(tbl.empty());
+
+ // void insert(Iter first, Iter last)
+ {
+ std::vector<std::pair<std::string, std::string>> vals{ { "foo", "foo" }, { "bar", "bar" }, { "kek", "kek" } };
+ tbl.insert(vals.begin(), vals.end());
+ CHECK(tbl.size() == 3u);
+ REQUIRE(tbl.get_as<std::string>("foo"));
+ CHECK(*tbl.get_as<std::string>("foo") == "foo");
+ REQUIRE(tbl.get_as<std::string>("bar"));
+ CHECK(*tbl.get_as<std::string>("bar") == "bar");
+ REQUIRE(tbl.get_as<std::string>("kek"));
+ CHECK(*tbl.get_as<std::string>("kek") == "kek");
+
+ REQUIRE(vals.size() == 3u);
+ CHECK(vals[0].first == "foo");
+ CHECK(vals[0].second == "foo");
+ CHECK(vals[1].first == "bar");
+ CHECK(vals[1].second == "bar");
+ CHECK(vals[2].first == "kek");
+ CHECK(vals[2].second == "kek");
+
+ tbl.clear();
+ }
+
+ // void insert(Iter first, Iter last) (with move iterators)
+ {
+ std::vector<std::pair<std::string, std::string>> vals{ { "foo", "foo" }, { "bar", "bar" }, { "kek", "kek" } };
+ tbl.insert(std::make_move_iterator(vals.begin()), std::make_move_iterator(vals.end()));
+ CHECK(tbl.size() == 3u);
+ REQUIRE(tbl.get_as<std::string>("foo"));
+ CHECK(*tbl.get_as<std::string>("foo") == "foo");
+ REQUIRE(tbl.get_as<std::string>("bar"));
+ CHECK(*tbl.get_as<std::string>("bar") == "bar");
+ REQUIRE(tbl.get_as<std::string>("kek"));
+ CHECK(*tbl.get_as<std::string>("kek") == "kek");
+
+ REQUIRE(vals.size() == 3u);
+ CHECK(vals[0].first == "");
+ CHECK(vals[0].second == "");
+ CHECK(vals[1].first == "");
+ CHECK(vals[1].second == "");
+ CHECK(vals[2].first == "");
+ CHECK(vals[2].second == "");
+
+ tbl.clear();
+ }
+
+#if TOML_ENABLE_WINDOWS_COMPAT
+
+ tbl.insert(L"a", L"test1");
+ REQUIRE(*tbl.get_as<std::string>(L"a"sv) == "test1"sv);
+ tbl.insert_or_assign(L"a"sv, L"test2");
+ REQUIRE(*tbl.get_as<std::string>(L"a"sv) == "test2"sv);
+ tbl.emplace<std::string>(L"b", L"test3");
+ REQUIRE(*tbl.get_as<std::string>(L"b"sv) == "test3"sv);
+ CHECK(tbl.size() == 2u);
+ tbl.erase(L"b");
+ CHECK(tbl.size() == 1u);
+ tbl.erase(L"a"s);
+ CHECK(tbl.size() == 0u);
+
+#endif // TOML_ENABLE_WINDOWS_COMPAT
+
+ // insert with value_flags
+ {
+ tbl.clear();
+
+ auto hex = toml::value{ 1 };
+ hex.flags(value_flags::format_as_hexadecimal);
+ CHECK(hex.flags() == value_flags::format_as_hexadecimal);
+
+ tbl.insert("hex", hex);
+ CHECK(hex.flags() == value_flags::format_as_hexadecimal);
+ CHECK(tbl["hex"].as_integer()->flags() == value_flags::format_as_hexadecimal);
+
+ tbl.insert("hex2", std::move(hex));
+ CHECK(hex.flags() == value_flags{});
+ CHECK(tbl["hex2"].as_integer()->flags() == value_flags::format_as_hexadecimal);
+ }
+}
+
+TEST_CASE("tables - toml_formatter")
+{
+ static constexpr auto to_string = [](std::string_view some_toml,
+ format_flags flags = toml_formatter::default_flags,
+ format_flags exclude_flags = format_flags::none)
+ {
+ auto val = toml::parse(some_toml);
+ std::stringstream ss;
+ ss << toml_formatter{ val, flags & ~(exclude_flags) };
+ return ss.str();
+ };
+
+ {
+ static constexpr auto some_toml = R"(val1 = 1
+val2 = 2
+val3 = 3)"sv;
+
+ CHECK(to_string(some_toml) == some_toml);
+ }
+
+ {
+ static constexpr auto some_toml = R"([a_table]
+a = 1
+b = 2
+c = 3)"sv;
+
+ CHECK(to_string(some_toml) == some_toml);
+ }
+
+ {
+ static constexpr auto some_toml = R"(val1 = 1
+val2 = 2
+val3 = 3
+
+[a_table]
+a = 1
+b = 2
+c = 3)"sv;
+
+ CHECK(to_string(some_toml) == some_toml);
+ }
+
+ {
+ static constexpr auto some_toml = "[a]\n\n[b]\n\n[c]"sv;
+ CHECK(to_string(some_toml) == some_toml);
+ }
+
+ {
+ static constexpr auto some_toml = "[a]\nkey = 1\n\n[b]\n\n[c]"sv;
+ CHECK(to_string(some_toml) == some_toml);
+ }
+
+ {
+ static constexpr auto some_toml = "key = 1\n\n[a]\nkey = 1\n\n[b]\n\n[c]"sv;
+ CHECK(to_string(some_toml) == some_toml);
+ }
+
+ {
+ static constexpr auto some_toml = "key = 1\n\n[a]\nkey = 1\n\n[b]\n\n[[c]]\n\n[[c]]"sv;
+ CHECK(to_string(some_toml) == some_toml);
+ }
+
+ {
+ constexpr auto input = R"(key1 = 'val1'
+key2 = [ 1, 2, 3, 4, '5' ]
+key3 = [ 'this is a really long array', 'and should be split over multiple lines', 'by the formatter', 'unless i dun goofed', 'i guess thats what tests are for' ]
+
+[sub1]
+key4 = 'val'
+
+[sub2]
+key5 = 'val'
+
+ [sub2.sub3]
+ key6 = 'val'
+ key7 = [ 1, 2, 3, 4, '5' ]
+ key8 = [ 'this is a really long array', 'and should be split over multiple lines', 'by the formatter', 'unless i dun goofed', 'i guess thats what tests are for' ])"sv;
+
+ constexpr auto expected_default = R"(key1 = 'val1'
+key2 = [ 1, 2, 3, 4, '5' ]
+key3 = [
+ 'this is a really long array',
+ 'and should be split over multiple lines',
+ 'by the formatter',
+ 'unless i dun goofed',
+ 'i guess thats what tests are for'
+]
+
+[sub1]
+key4 = 'val'
+
+[sub2]
+key5 = 'val'
+
+ [sub2.sub3]
+ key6 = 'val'
+ key7 = [ 1, 2, 3, 4, '5' ]
+ key8 = [
+ 'this is a really long array',
+ 'and should be split over multiple lines',
+ 'by the formatter',
+ 'unless i dun goofed',
+ 'i guess thats what tests are for'
+ ])"sv;
+ CHECK(to_string(input) == expected_default);
+
+ constexpr auto expected_without_indented_subtables = R"(key1 = 'val1'
+key2 = [ 1, 2, 3, 4, '5' ]
+key3 = [
+ 'this is a really long array',
+ 'and should be split over multiple lines',
+ 'by the formatter',
+ 'unless i dun goofed',
+ 'i guess thats what tests are for'
+]
+
+[sub1]
+key4 = 'val'
+
+[sub2]
+key5 = 'val'
+
+[sub2.sub3]
+key6 = 'val'
+key7 = [ 1, 2, 3, 4, '5' ]
+key8 = [
+ 'this is a really long array',
+ 'and should be split over multiple lines',
+ 'by the formatter',
+ 'unless i dun goofed',
+ 'i guess thats what tests are for'
+])"sv;
+ CHECK(to_string(input, toml_formatter::default_flags, format_flags::indent_sub_tables)
+ == expected_without_indented_subtables);
+
+ constexpr auto expected_without_indented_arrays = R"(key1 = 'val1'
+key2 = [ 1, 2, 3, 4, '5' ]
+key3 = [
+'this is a really long array',
+'and should be split over multiple lines',
+'by the formatter',
+'unless i dun goofed',
+'i guess thats what tests are for'
+]
+
+[sub1]
+key4 = 'val'
+
+[sub2]
+key5 = 'val'
+
+ [sub2.sub3]
+ key6 = 'val'
+ key7 = [ 1, 2, 3, 4, '5' ]
+ key8 = [
+ 'this is a really long array',
+ 'and should be split over multiple lines',
+ 'by the formatter',
+ 'unless i dun goofed',
+ 'i guess thats what tests are for'
+ ])"sv;
+ CHECK(to_string(input, toml_formatter::default_flags, format_flags::indent_array_elements)
+ == expected_without_indented_arrays);
+
+ constexpr auto expected_without_indentation = R"(key1 = 'val1'
+key2 = [ 1, 2, 3, 4, '5' ]
+key3 = [
+'this is a really long array',
+'and should be split over multiple lines',
+'by the formatter',
+'unless i dun goofed',
+'i guess thats what tests are for'
+]
+
+[sub1]
+key4 = 'val'
+
+[sub2]
+key5 = 'val'
+
+[sub2.sub3]
+key6 = 'val'
+key7 = [ 1, 2, 3, 4, '5' ]
+key8 = [
+'this is a really long array',
+'and should be split over multiple lines',
+'by the formatter',
+'unless i dun goofed',
+'i guess thats what tests are for'
+])"sv;
+ CHECK(to_string(input, toml_formatter::default_flags, format_flags::indentation)
+ == expected_without_indentation);
+
+ // forcing multiline arrays: even short arrays become one-per-line (with array elements indented)
+ constexpr auto expected_forced_multiline = R"(key1 = 'val1'
+key2 = [
+ 1,
+ 2,
+ 3,
+ 4,
+ '5'
+]
+key3 = [
+ 'this is a really long array',
+ 'and should be split over multiple lines',
+ 'by the formatter',
+ 'unless i dun goofed',
+ 'i guess thats what tests are for'
+]
+
+[sub1]
+key4 = 'val'
+
+[sub2]
+key5 = 'val'
+
+ [sub2.sub3]
+ key6 = 'val'
+ key7 = [
+ 1,
+ 2,
+ 3,
+ 4,
+ '5'
+ ]
+ key8 = [
+ 'this is a really long array',
+ 'and should be split over multiple lines',
+ 'by the formatter',
+ 'unless i dun goofed',
+ 'i guess thats what tests are for'
+ ])"sv;
+
+ CHECK(to_string(input, toml_formatter::default_flags | format_flags::force_multiline_arrays)
+ == expected_forced_multiline);
+
+ // forcing multiline arrays without indenting array elements
+ constexpr auto expected_forced_without_indented_arrays = R"(key1 = 'val1'
+key2 = [
+1,
+2,
+3,
+4,
+'5'
+]
+key3 = [
+'this is a really long array',
+'and should be split over multiple lines',
+'by the formatter',
+'unless i dun goofed',
+'i guess thats what tests are for'
+]
+
+[sub1]
+key4 = 'val'
+
+[sub2]
+key5 = 'val'
+
+ [sub2.sub3]
+ key6 = 'val'
+ key7 = [
+ 1,
+ 2,
+ 3,
+ 4,
+ '5'
+ ]
+ key8 = [
+ 'this is a really long array',
+ 'and should be split over multiple lines',
+ 'by the formatter',
+ 'unless i dun goofed',
+ 'i guess thats what tests are for'
+ ])"sv;
+
+ CHECK(to_string(input,
+ toml_formatter::default_flags | format_flags::force_multiline_arrays,
+ format_flags::indent_array_elements)
+ == expected_forced_without_indented_arrays);
+ }
+}
+
+TEST_CASE("tables - for_each")
+{
+ const auto tbl = table{ { "a", 1 }, { "b", 2.0 }, { "c", 3 }, { "d", "four" }, { "e", false } };
+
+ SECTION("type checking")
+ {
+ int count = 0;
+ int ints = 0;
+ int floats = 0;
+ int numbers = 0;
+ int strings = 0;
+ int bools = 0;
+ tbl.for_each(
+ [&](const auto& v) noexcept
+ {
+ count++;
+ if constexpr (toml::is_integer<decltype(v)>)
+ ints++;
+ if constexpr (toml::is_floating_point<decltype(v)>)
+ floats++;
+ if constexpr (toml::is_number<decltype(v)>)
+ numbers++;
+ if constexpr (toml::is_string<decltype(v)>)
+ strings++;
+ if constexpr (toml::is_boolean<decltype(v)>)
+ bools++;
+ });
+ CHECK(count == 5);
+ CHECK(ints == 2);
+ CHECK(floats == 1);
+ CHECK(numbers == (ints + floats));
+ CHECK(strings == 1);
+ CHECK(bools == 1);
+ }
+
+#if !TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
+
+ SECTION("early-exit (key, val)")
+ {
+ int count = 0;
+ tbl.for_each([&](const key& /*k*/, const auto& /*v*/) noexcept -> bool { return ++count < 3; });
+ CHECK(count == 3);
+ }
+
+ SECTION("early-exit (val)")
+ {
+ int count = 0;
+ tbl.for_each([&](const auto& /*v*/) noexcept -> bool { return ++count < 3; });
+ CHECK(count == 3);
+ }
+
+#endif
+}