mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-09-18 02:08:09 +08:00
Merge branch 'v3' of gitlab.com:ToruNiina/toml11 into v3
This commit is contained in:
11
README.md
11
README.md
@@ -47,17 +47,17 @@ int main()
|
||||
- [Decoding a toml file](#decoding-a-toml-file)
|
||||
- [In the case of syntax error](#in-the-case-of-syntax-error)
|
||||
- [Invalid UTF-8 Codepoints](#invalid-utf-8-codepoints)
|
||||
- [Finding a toml value](#getting-a-toml-value)
|
||||
- [Finding a toml value](#finding-a-toml-value-from-a-table)
|
||||
- [In the case of type error](#in-the-case-of-type-error)
|
||||
- [Dotted keys](#dotted-keys)
|
||||
- [Casting a toml value](#casting-a-toml-value)
|
||||
- [Checking value type](#checking-value-type)
|
||||
- [More about conversion](#more-about-conversion)
|
||||
- [Getting an array](#getting-an-array)
|
||||
- [Getting a table](#getting-a-table)
|
||||
- [Converting an array](#converting-an-array)
|
||||
- [Converting a table](#converting-a-table)
|
||||
- [Getting an array of tables](#getting-an-array-of-tables)
|
||||
- [Cost of conversion](#cost-of-conversion)
|
||||
- [Getting datetime and its variants](#getting-datetime-and-its-variants)
|
||||
- [Converting datetime and its variants](#converting-datetime-and-its-variants)
|
||||
- [Getting with a fallback](#getting-with-a-fallback)
|
||||
- [Expecting conversion](#expecting-conversion)
|
||||
- [Visiting a toml::value](#visiting-a-tomlvalue)
|
||||
@@ -67,7 +67,6 @@ int main()
|
||||
- [TOML literal](#toml-literal)
|
||||
- [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types)
|
||||
- [Formatting user-defined error messages](#formatting-user-defined-error-messages)
|
||||
- [Getting comments related to a value](#getting-comments)
|
||||
- [Serializing TOML data](#serializing-toml-data)
|
||||
- [Underlying types](#underlying-types)
|
||||
- [Breaking Changes from v2](#breaking-changes-from-v2)
|
||||
@@ -711,7 +710,7 @@ const auto value = toml::expect<int>(data.at("number"))
|
||||
}).unwrap_or(/*default value =*/ 3.14);
|
||||
```
|
||||
|
||||
## Visiting toml::value
|
||||
## Visiting a toml::value
|
||||
|
||||
toml11 provides `toml::visit` to apply a function to `toml::value` in the
|
||||
same way as `std::variant`.
|
||||
|
@@ -134,14 +134,15 @@ BOOST_AUTO_TEST_CASE(test_conversion_by_member_methods)
|
||||
}
|
||||
|
||||
{
|
||||
const toml::basic_value<toml::discard_comment, std::map, std::deque>
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque>
|
||||
v{{"a", 42}, {"b", "baz"}};
|
||||
|
||||
const auto foo = toml::get<extlib2::foo>(v);
|
||||
BOOST_CHECK_EQUAL(foo.a, 42);
|
||||
BOOST_CHECK_EQUAL(foo.b, "baz");
|
||||
|
||||
const toml::value v2(foo);
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque>
|
||||
v2(foo);
|
||||
|
||||
BOOST_CHECK_EQUAL(v, v2);
|
||||
}
|
||||
@@ -172,14 +173,15 @@ BOOST_AUTO_TEST_CASE(test_conversion_by_specialization)
|
||||
BOOST_CHECK_EQUAL(v, v2);
|
||||
}
|
||||
{
|
||||
const toml::basic_value<toml::discard_comment, std::map, std::deque>
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque>
|
||||
v{{"a", 42}, {"b", "baz"}};
|
||||
|
||||
const auto bar = toml::get<extlib2::bar>(v);
|
||||
BOOST_CHECK_EQUAL(bar.a, 42);
|
||||
BOOST_CHECK_EQUAL(bar.b, "baz");
|
||||
|
||||
const toml::value v2(bar);
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque>
|
||||
v2(bar);
|
||||
|
||||
BOOST_CHECK_EQUAL(v, v2);
|
||||
}
|
||||
@@ -253,12 +255,12 @@ BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
||||
}
|
||||
|
||||
{
|
||||
const toml::basic_value<toml::discard_comment, std::map, std::deque>
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque>
|
||||
v{
|
||||
toml::table{{"a", 42}, {"b", "baz"}},
|
||||
toml::table{{"a", 43}, {"b", "qux"}},
|
||||
toml::table{{"a", 44}, {"b", "quux"}},
|
||||
toml::table{{"a", 45}, {"b", "foobar"}},
|
||||
toml::table{{"a", 45}, {"b", "foobar"}}
|
||||
};
|
||||
|
||||
const auto foos = toml::get<std::vector<extlib2::foo>>(v);
|
||||
|
@@ -193,6 +193,206 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(bit, "multi_line_array") ==
|
||||
expected_multi_line_array);
|
||||
}
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/hard_example.toml");
|
||||
const auto the = toml::find(data, "the");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(the, "test_string"),
|
||||
"You'll hate me after this - #");
|
||||
|
||||
const auto hard = toml::find(the, "hard");
|
||||
const std::vector<std::string> expected_the_hard_test_array{"] ", " # "};
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(hard, "test_array") ==
|
||||
expected_the_hard_test_array);
|
||||
const std::vector<std::string> expected_the_hard_test_array2{
|
||||
"Test #11 ]proved that", "Experiment #9 was a success"};
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(hard, "test_array2") ==
|
||||
expected_the_hard_test_array2);
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(hard, "another_test_string"),
|
||||
" Same thing, but with a string #");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(hard, "harder_test_string"),
|
||||
" And when \"'s are in the string, along with # \"");
|
||||
|
||||
const auto bit = toml::find(hard, "bit#");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(bit, "what?"),
|
||||
"You don't think some user won't do that?");
|
||||
const std::vector<std::string> expected_multi_line_array{"]"};
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(bit, "multi_line_array") ==
|
||||
expected_multi_line_array);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(data, "title"), "TOML Example");
|
||||
const auto& owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "name"), "Tom Preston-Werner");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "organization"), "GitHub");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "bio"),
|
||||
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
|
||||
BOOST_CHECK_EQUAL(toml::find<toml::offset_datetime>(owner, "dob"),
|
||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||
BOOST_CHECK_EQUAL(toml::find(owner, "dob").comments().at(0),
|
||||
" First class dates? Why not?");
|
||||
}
|
||||
|
||||
const auto& database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(database, "server"), "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
BOOST_CHECK(toml::find<std::vector<int>>(database, "ports") == expected_ports);
|
||||
BOOST_CHECK_EQUAL(toml::find<int >(database, "connection_max"), 5000);
|
||||
BOOST_CHECK_EQUAL(toml::find<bool>(database, "enabled"), true);
|
||||
}
|
||||
|
||||
const auto& servers = toml::find(data, "servers");
|
||||
{
|
||||
const auto& alpha = toml::find(servers, "alpha");
|
||||
BOOST_CHECK_EQUAL(alpha.comments().at(0),
|
||||
" You can indent as you please. Tabs or spaces. TOML don't care.");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(alpha, "ip"), "10.0.0.1");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(alpha, "dc"), "eqdc10");
|
||||
|
||||
const auto& beta = toml::find(servers, "beta");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "ip"), "10.0.0.2");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "dc"), "eqdc10");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "country"),
|
||||
"\xE4\xB8\xAD\xE5\x9B\xBD");
|
||||
BOOST_CHECK_EQUAL(toml::find(beta, "country").comments().at(0),
|
||||
" This should be parsed as UTF-8");
|
||||
}
|
||||
|
||||
const auto& clients = toml::find(data, "clients");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find(clients, "data").comments().at(0),
|
||||
" just an update to make sure parsers support it");
|
||||
|
||||
|
||||
toml::array clients_data = toml::find<toml::array>(clients, "data");
|
||||
std::vector<std::string> expected_name{"gamma", "delta"};
|
||||
BOOST_CHECK(toml::get<std::vector<std::string>>(clients_data.at(0)) ==
|
||||
expected_name);
|
||||
std::vector<int> expected_number{1, 2};
|
||||
BOOST_CHECK(toml::get<std::vector<int>>(clients_data.at(1)) ==
|
||||
expected_number);
|
||||
std::vector<std::string> expected_hosts{"alpha", "omega"};
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(clients, "hosts") ==
|
||||
expected_hosts);
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(clients, "hosts").comments().at(0),
|
||||
" Line breaks are OK when inside arrays");
|
||||
}
|
||||
|
||||
std::vector<toml::table> products =
|
||||
toml::find<std::vector<toml::table>>(data, "products");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(0).at("name")),
|
||||
"Hammer");
|
||||
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(0).at("sku")),
|
||||
738594937);
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("name")),
|
||||
"Nail");
|
||||
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(1).at("sku")),
|
||||
284758393);
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("color")),
|
||||
"gray");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque
|
||||
>("toml/tests/example.toml");
|
||||
|
||||
static_assert(std::is_same<typename decltype(data)::table_type,
|
||||
std::map<toml::key, typename std::remove_cv<decltype(data)>::type>
|
||||
>::value, "");
|
||||
static_assert(std::is_same<typename decltype(data)::array_type,
|
||||
std::deque<typename std::remove_cv<decltype(data)>::type>
|
||||
>::value, "");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(data, "title"), "TOML Example");
|
||||
const auto& owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "name"), "Tom Preston-Werner");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "organization"), "GitHub");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "bio"),
|
||||
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
|
||||
BOOST_CHECK_EQUAL(toml::find<toml::offset_datetime>(owner, "dob"),
|
||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||
BOOST_CHECK_EQUAL(toml::find(owner, "dob").comments().at(0),
|
||||
" First class dates? Why not?");
|
||||
}
|
||||
|
||||
const auto& database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(database, "server"), "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
BOOST_CHECK(toml::find<std::vector<int>>(database, "ports") == expected_ports);
|
||||
BOOST_CHECK_EQUAL(toml::find<int >(database, "connection_max"), 5000);
|
||||
BOOST_CHECK_EQUAL(toml::find<bool>(database, "enabled"), true);
|
||||
}
|
||||
|
||||
const auto& servers = toml::find(data, "servers");
|
||||
{
|
||||
const auto& alpha = toml::find(servers, "alpha");
|
||||
BOOST_CHECK_EQUAL(alpha.comments().at(0),
|
||||
" You can indent as you please. Tabs or spaces. TOML don't care.");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(alpha, "ip"), "10.0.0.1");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(alpha, "dc"), "eqdc10");
|
||||
|
||||
const auto& beta = toml::find(servers, "beta");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "ip"), "10.0.0.2");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "dc"), "eqdc10");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "country"),
|
||||
"\xE4\xB8\xAD\xE5\x9B\xBD");
|
||||
BOOST_CHECK_EQUAL(toml::find(beta, "country").comments().at(0),
|
||||
" This should be parsed as UTF-8");
|
||||
}
|
||||
|
||||
const auto& clients = toml::find(data, "clients");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find(clients, "data").comments().at(0),
|
||||
" just an update to make sure parsers support it");
|
||||
|
||||
|
||||
toml::array clients_data = toml::find<toml::array>(clients, "data");
|
||||
std::vector<std::string> expected_name{"gamma", "delta"};
|
||||
BOOST_CHECK(toml::get<std::vector<std::string>>(clients_data.at(0)) ==
|
||||
expected_name);
|
||||
std::vector<int> expected_number{1, 2};
|
||||
BOOST_CHECK(toml::get<std::vector<int>>(clients_data.at(1)) ==
|
||||
expected_number);
|
||||
std::vector<std::string> expected_hosts{"alpha", "omega"};
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(clients, "hosts") ==
|
||||
expected_hosts);
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(clients, "hosts").comments().at(0),
|
||||
" Line breaks are OK when inside arrays");
|
||||
}
|
||||
|
||||
std::vector<toml::table> products =
|
||||
toml::find<std::vector<toml::table>>(data, "products");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(0).at("name")),
|
||||
"Hammer");
|
||||
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(0).at("sku")),
|
||||
738594937);
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("name")),
|
||||
"Nail");
|
||||
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(1).at("sku")),
|
||||
284758393);
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("color")),
|
||||
"gray");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// after here, the test codes generate the content of a file.
|
||||
@@ -695,174 +895,3 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(data, "title"), "TOML Example");
|
||||
const auto& owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "name"), "Tom Preston-Werner");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "organization"), "GitHub");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "bio"),
|
||||
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
|
||||
BOOST_CHECK_EQUAL(toml::find<toml::offset_datetime>(owner, "dob"),
|
||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||
BOOST_CHECK_EQUAL(toml::find(owner, "dob").comments().at(0),
|
||||
" First class dates? Why not?");
|
||||
}
|
||||
|
||||
const auto& database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(database, "server"), "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
BOOST_CHECK(toml::find<std::vector<int>>(database, "ports") == expected_ports);
|
||||
BOOST_CHECK_EQUAL(toml::find<int >(database, "connection_max"), 5000);
|
||||
BOOST_CHECK_EQUAL(toml::find<bool>(database, "enabled"), true);
|
||||
}
|
||||
|
||||
const auto& servers = toml::find(data, "servers");
|
||||
{
|
||||
const auto& alpha = toml::find(servers, "alpha");
|
||||
BOOST_CHECK_EQUAL(alpha.comments().at(0),
|
||||
" You can indent as you please. Tabs or spaces. TOML don't care.");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(alpha, "ip"), "10.0.0.1");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(alpha, "dc"), "eqdc10");
|
||||
|
||||
const auto& beta = toml::find(servers, "beta");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "ip"), "10.0.0.2");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "dc"), "eqdc10");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "country"),
|
||||
"\xE4\xB8\xAD\xE5\x9B\xBD");
|
||||
BOOST_CHECK_EQUAL(toml::find(beta, "country").comments().at(0),
|
||||
" This should be parsed as UTF-8");
|
||||
}
|
||||
|
||||
const auto& clients = toml::find(data, "clients");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find(clients, "data").comments().at(0),
|
||||
" just an update to make sure parsers support it");
|
||||
|
||||
|
||||
toml::array clients_data = toml::find<toml::array>(clients, "data");
|
||||
std::vector<std::string> expected_name{"gamma", "delta"};
|
||||
BOOST_CHECK(toml::get<std::vector<std::string>>(clients_data.at(0)) ==
|
||||
expected_name);
|
||||
std::vector<int> expected_number{1, 2};
|
||||
BOOST_CHECK(toml::get<std::vector<int>>(clients_data.at(1)) ==
|
||||
expected_number);
|
||||
std::vector<std::string> expected_hosts{"alpha", "omega"};
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(clients, "hosts") ==
|
||||
expected_hosts);
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(clients, "hosts").comments().at(0),
|
||||
" Line breaks are OK when inside arrays");
|
||||
}
|
||||
|
||||
std::vector<toml::table> products =
|
||||
toml::find<std::vector<toml::table>>(data, "products");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(0).at("name")),
|
||||
"Hammer");
|
||||
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(0).at("sku")),
|
||||
738594937);
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("name")),
|
||||
"Nail");
|
||||
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(1).at("sku")),
|
||||
284758393);
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("color")),
|
||||
"gray");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque
|
||||
>("toml/tests/example.toml");
|
||||
|
||||
static_assert(std::is_same<typename decltype(data)::table_type,
|
||||
std::map<toml::key, typename std::remove_cv<decltype(data)>::type>
|
||||
>::value, "");
|
||||
static_assert(std::is_same<typename decltype(data)::array_type,
|
||||
std::deque<typename std::remove_cv<decltype(data)>::type>
|
||||
>::value, "");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(data, "title"), "TOML Example");
|
||||
const auto& owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "name"), "Tom Preston-Werner");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "organization"), "GitHub");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(owner, "bio"),
|
||||
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
|
||||
BOOST_CHECK_EQUAL(toml::find<toml::offset_datetime>(owner, "dob"),
|
||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||
BOOST_CHECK_EQUAL(toml::find(owner, "dob").comments().at(0),
|
||||
" First class dates? Why not?");
|
||||
}
|
||||
|
||||
const auto& database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(database, "server"), "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
BOOST_CHECK(toml::find<std::vector<int>>(database, "ports") == expected_ports);
|
||||
BOOST_CHECK_EQUAL(toml::find<int >(database, "connection_max"), 5000);
|
||||
BOOST_CHECK_EQUAL(toml::find<bool>(database, "enabled"), true);
|
||||
}
|
||||
|
||||
const auto& servers = toml::find(data, "servers");
|
||||
{
|
||||
const auto& alpha = toml::find(servers, "alpha");
|
||||
BOOST_CHECK_EQUAL(alpha.comments().at(0),
|
||||
" You can indent as you please. Tabs or spaces. TOML don't care.");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(alpha, "ip"), "10.0.0.1");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(alpha, "dc"), "eqdc10");
|
||||
|
||||
const auto& beta = toml::find(servers, "beta");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "ip"), "10.0.0.2");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "dc"), "eqdc10");
|
||||
BOOST_CHECK_EQUAL(toml::find<std::string>(beta, "country"),
|
||||
"\xE4\xB8\xAD\xE5\x9B\xBD");
|
||||
BOOST_CHECK_EQUAL(toml::find(beta, "country").comments().at(0),
|
||||
" This should be parsed as UTF-8");
|
||||
}
|
||||
|
||||
const auto& clients = toml::find(data, "clients");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::find(clients, "data").comments().at(0),
|
||||
" just an update to make sure parsers support it");
|
||||
|
||||
|
||||
toml::array clients_data = toml::find<toml::array>(clients, "data");
|
||||
std::vector<std::string> expected_name{"gamma", "delta"};
|
||||
BOOST_CHECK(toml::get<std::vector<std::string>>(clients_data.at(0)) ==
|
||||
expected_name);
|
||||
std::vector<int> expected_number{1, 2};
|
||||
BOOST_CHECK(toml::get<std::vector<int>>(clients_data.at(1)) ==
|
||||
expected_number);
|
||||
std::vector<std::string> expected_hosts{"alpha", "omega"};
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(clients, "hosts") ==
|
||||
expected_hosts);
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(clients, "hosts").comments().at(0),
|
||||
" Line breaks are OK when inside arrays");
|
||||
}
|
||||
|
||||
std::vector<toml::table> products =
|
||||
toml::find<std::vector<toml::table>>(data, "products");
|
||||
{
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(0).at("name")),
|
||||
"Hammer");
|
||||
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(0).at("sku")),
|
||||
738594937);
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("name")),
|
||||
"Nail");
|
||||
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(1).at("sku")),
|
||||
284758393);
|
||||
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("color")),
|
||||
"gray");
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/example.toml");
|
||||
@@ -31,6 +30,31 @@ BOOST_AUTO_TEST_CASE(test_example)
|
||||
BOOST_CHECK(data == serialized);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_with_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
|
||||
{
|
||||
std::ofstream ofs("tmp1_com.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
}
|
||||
|
||||
auto serialized = toml::parse<toml::preserve_comments>("tmp1_com.toml");
|
||||
{
|
||||
auto& owner = toml::find<typename decltype(serialized)::table_type>(serialized, "owner");
|
||||
auto& bio = toml::get<std::string>(owner.at("bio"));
|
||||
const auto CR = std::find(bio.begin(), bio.end(), '\r');
|
||||
if(CR != bio.end())
|
||||
{
|
||||
bio.erase(CR);
|
||||
}
|
||||
}
|
||||
BOOST_CHECK(data == serialized);
|
||||
{
|
||||
std::ofstream ofs("tmp1_com1.toml");
|
||||
ofs << std::setw(80) << serialized;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_fruit)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/fruit.toml");
|
||||
@@ -42,6 +66,17 @@ BOOST_AUTO_TEST_CASE(test_fruit)
|
||||
BOOST_CHECK(data == serialized);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_fruit_with_comments)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/fruit.toml");
|
||||
{
|
||||
std::ofstream ofs("tmp2_com.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
}
|
||||
const auto serialized = toml::parse<toml::preserve_comments>("tmp2_com.toml");
|
||||
BOOST_CHECK(data == serialized);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/hard_example.toml");
|
||||
@@ -52,3 +87,18 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
|
||||
const auto serialized = toml::parse("tmp3.toml");
|
||||
BOOST_CHECK(data == serialized);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example_with_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/hard_example.toml");
|
||||
{
|
||||
std::ofstream ofs("tmp3_com.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
}
|
||||
const auto serialized = toml::parse<toml::preserve_comments>("tmp3_com.toml");
|
||||
{
|
||||
std::ofstream ofs("tmp3_com1.toml");
|
||||
ofs << std::setw(80) << serialized;
|
||||
}
|
||||
BOOST_CHECK(data == serialized);
|
||||
}
|
||||
|
@@ -55,6 +55,17 @@ struct preserve_comments
|
||||
explicit preserve_comments(std::vector<std::string>&& c)
|
||||
: comments(std::move(c))
|
||||
{}
|
||||
preserve_comments& operator=(const std::vector<std::string>& c)
|
||||
{
|
||||
comments = c;
|
||||
return *this;
|
||||
}
|
||||
preserve_comments& operator=(std::vector<std::string>&& c)
|
||||
{
|
||||
comments = std::move(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit preserve_comments(const discard_comments&) {}
|
||||
|
||||
explicit preserve_comments(size_type n): comments(n) {}
|
||||
@@ -278,6 +289,9 @@ struct discard_comments
|
||||
|
||||
explicit discard_comments(const std::vector<std::string>&) noexcept {}
|
||||
explicit discard_comments(std::vector<std::string>&&) noexcept {}
|
||||
discard_comments& operator=(const std::vector<std::string>&) noexcept {return *this;}
|
||||
discard_comments& operator=(std::vector<std::string>&&) noexcept {return *this;}
|
||||
|
||||
explicit discard_comments(const preserve_comments&) noexcept {}
|
||||
|
||||
explicit discard_comments(size_type) noexcept {}
|
||||
|
@@ -1703,6 +1703,44 @@ result<Value, std::string> parse_toml_file(location<Container>& loc)
|
||||
return ok(value_type(table_type{}));
|
||||
}
|
||||
|
||||
// put the first line as a region of a file
|
||||
const region<Container> file(loc, loc.iter(),
|
||||
std::find(loc.iter(), loc.end(), '\n'));
|
||||
|
||||
// The first successive comments that are separated from the first value
|
||||
// by an empty line are for a file itself.
|
||||
// ```toml
|
||||
// # this is a comment for a file.
|
||||
//
|
||||
// key = "the first value"
|
||||
// ```
|
||||
// ```toml
|
||||
// # this is a comment for "the first value".
|
||||
// key = "the first value"
|
||||
// ```
|
||||
std::vector<std::string> comments;
|
||||
using lex_first_comments = sequence<
|
||||
repeat<sequence<maybe<lex_ws>, lex_comment, lex_newline>, at_least<1>>,
|
||||
sequence<maybe<lex_ws>, lex_newline>
|
||||
>;
|
||||
if(const auto token = lex_first_comments::invoke(loc))
|
||||
{
|
||||
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
||||
while(inner_loc.iter() != inner_loc.end())
|
||||
{
|
||||
maybe<lex_ws>::invoke(inner_loc); // remove ws if exists
|
||||
if(lex_newline::invoke(inner_loc))
|
||||
{
|
||||
assert(inner_loc.iter() == inner_loc.end());
|
||||
break; // empty line found.
|
||||
}
|
||||
auto com = lex_comment::invoke(inner_loc).unwrap().str();
|
||||
com.erase(com.begin()); // remove # sign
|
||||
comments.push_back(std::move(com));
|
||||
lex_newline::invoke(inner_loc);
|
||||
}
|
||||
}
|
||||
|
||||
table_type data;
|
||||
// root object is also a table, but without [tablename]
|
||||
if(auto tab = parse_ml_table<value_type>(loc))
|
||||
@@ -1752,7 +1790,11 @@ result<Value, std::string> parse_toml_file(location<Container>& loc)
|
||||
return err(format_underline("[error]: toml::parse_toml_file: "
|
||||
"unknown line appeared", {{std::addressof(loc), "unknown format"}}));
|
||||
}
|
||||
return ok(data);
|
||||
|
||||
Value v(std::move(data), file);
|
||||
v.comments() = comments;
|
||||
|
||||
return ok(std::move(v));
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
@@ -304,38 +304,45 @@ struct region final : public region_base
|
||||
// # this also.
|
||||
// a = value # not this.
|
||||
// ```
|
||||
auto iter = this->line_begin(); // points the first character
|
||||
while(iter != this->begin())
|
||||
|
||||
// # this is a comment for `a`, not array elements.
|
||||
// a = [1, 2, 3, 4, 5]
|
||||
if(this->first() == std::find_if(this->line_begin(), this->first(),
|
||||
[](const char c) noexcept -> bool {return c == '[' || c == '{';}))
|
||||
{
|
||||
iter = std::prev(iter);
|
||||
auto iter = this->line_begin(); // points the first character
|
||||
while(iter != this->begin())
|
||||
{
|
||||
iter = std::prev(iter);
|
||||
|
||||
// range [line_start, iter) represents the previous line
|
||||
const auto line_start = std::find(
|
||||
rev_iter(iter), rev_iter(this->begin()), '\n').base();
|
||||
const auto comment_found = std::find(line_start, iter, '#');
|
||||
if(comment_found == iter)
|
||||
{
|
||||
break; // comment not found.
|
||||
}
|
||||
// range [line_start, iter) represents the previous line
|
||||
const auto line_start = std::find(
|
||||
rev_iter(iter), rev_iter(this->begin()), '\n').base();
|
||||
const auto comment_found = std::find(line_start, iter, '#');
|
||||
if(comment_found == iter)
|
||||
{
|
||||
break; // comment not found.
|
||||
}
|
||||
|
||||
// exclude the following case.
|
||||
// > a = "foo" # comment // <-- this is not a comment for b but a.
|
||||
// > b = "current value"
|
||||
if(std::all_of(line_start, comment_found,
|
||||
[](const char c) noexcept -> bool {
|
||||
return c == ' ' || c == '\t';
|
||||
}))
|
||||
{
|
||||
// unwrap the first '#' by std::next.
|
||||
auto str = make_string(std::next(comment_found), iter);
|
||||
if(str.back() == '\r') {str.pop_back();}
|
||||
com.push_back(std::move(str));
|
||||
// exclude the following case.
|
||||
// > a = "foo" # comment // <-- this is not a comment for b but a.
|
||||
// > b = "current value"
|
||||
if(std::all_of(line_start, comment_found,
|
||||
[](const char c) noexcept -> bool {
|
||||
return c == ' ' || c == '\t';
|
||||
}))
|
||||
{
|
||||
// unwrap the first '#' by std::next.
|
||||
auto str = make_string(std::next(comment_found), iter);
|
||||
if(str.back() == '\r') {str.pop_back();}
|
||||
com.push_back(std::move(str));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
iter = line_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
iter = line_start;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -333,6 +333,11 @@ struct serializer
|
||||
current_line += ',';
|
||||
}
|
||||
}
|
||||
if(!current_line.empty())
|
||||
{
|
||||
if(current_line.back() != '\n') {current_line += '\n';}
|
||||
token += current_line;
|
||||
}
|
||||
token += "]\n";
|
||||
return token;
|
||||
}
|
||||
|
@@ -779,18 +779,17 @@ class basic_value
|
||||
}
|
||||
|
||||
template<typename T, typename std::enable_if<
|
||||
detail::is_convertible_to_toml_value<T, value_type>::value,
|
||||
std::is_convertible<T, value_type>::value,
|
||||
std::nullptr_t>::type = nullptr>
|
||||
basic_value(std::initializer_list<T> list)
|
||||
: type_(value_t::array),
|
||||
region_info_(std::make_shared<region_base>(region_base{}))
|
||||
{
|
||||
array_type ary; ary.reserve(list.size());
|
||||
for(auto& elem : list) {ary.emplace_back(std::move(elem));}
|
||||
array_type ary(list.begin(), list.end());
|
||||
assigner(this->array_, std::move(ary));
|
||||
}
|
||||
template<typename T, typename std::enable_if<
|
||||
detail::is_convertible_to_toml_value<T, value_type>::value,
|
||||
std::is_convertible<T, value_type>::value,
|
||||
std::nullptr_t>::type = nullptr>
|
||||
basic_value& operator=(std::initializer_list<T> list)
|
||||
{
|
||||
@@ -798,8 +797,7 @@ class basic_value
|
||||
this->type_ = value_t::array;
|
||||
this->region_info_ = std::make_shared<region_base>(region_base{});
|
||||
|
||||
array_type ary; ary.reserve(list.size());
|
||||
for(auto& elem : list) {ary.emplace_back(std::move(elem));}
|
||||
array_type ary(list.begin(), list.end());
|
||||
assigner(this->array_, std::move(ary));
|
||||
return *this;
|
||||
}
|
||||
|
Reference in New Issue
Block a user