Compare commits

...

752 Commits

Author SHA1 Message Date
ToruNiina
dcfe39a783 chore: update version number 2022-03-13 01:44:29 +09:00
ToruNiina
2f07030d43 doc: update the list of contributors 2022-03-13 01:40:43 +09:00
ToruNiina
97cc0ef62b fix #166: reorder local/gmtime wrapper for MSVC 2022-03-13 00:20:00 +09:00
ToruNiina
0e80cabe65 Merge branch 'check-specialized-conversion' 2022-03-12 19:00:29 +09:00
ToruNiina
cd97dfcec1 Merge branch 'insertion-to-table-defined-by-dotted-key' 2022-03-12 19:00:07 +09:00
ToruNiina
e60442c6db fix: check if re-open dotkey by a table
like:
```
a.b.c = "foo"
[a.b] # this is invalid
d = "bar"
```
2022-03-12 18:22:01 +09:00
Toru Niina
d39fd88a17 Merge pull request #185 from ax3l/topic-installEmbed
CMake: Optional Install if Embedded
2022-03-07 23:12:33 +09:00
Axel Huebl
7fb8b84143 CMake: Optional Install if Embedded
When adding this library as embedded library with private
"target link", e.g., only used inside private source files, the
library does not need to be installed when the main project gets
installed.

This adds an additional option `toml11_INSTALL` similar to the
test-build control switch in order to skip installing headers and
CMake config files if requested.

Avoids using
```cmake
add_subdirectory(path/to/toml11 EXCLUDE_FROM_ALL)
```

which has further side-effects:
https://cmake.org/cmake/help/v3.0/command/add_subdirectory.html
2022-03-03 18:55:55 -08:00
ToruNiina
03259e2003 fix #177: check specific conversion function
when converting toml::value to array-like
2021-12-25 14:08:55 +09:00
ToruNiina
bf2384d8da fix #182: Merge branch 'workaround-msvc-cplusplus-macro' 2021-12-18 15:41:43 +09:00
ToruNiina
8ebf9c984b ci: check if it works w/o /Zc:__cplusplus 2021-12-18 14:23:58 +09:00
ToruNiina
7354e91924 fix: Allow MSVC to have old version 2021-12-18 00:36:20 +09:00
ToruNiina
4522070391 ci: check if MSVC 14 2015 (19.0.24241.7) (1900)
passes ci build if we skip _MSVC_LANG
2021-12-18 00:21:55 +09:00
ToruNiina
02fd8a577b feat: workaround __cplusplus problem on MSVC 2021-12-17 22:29:57 +09:00
ToruNiina
40777070ad fix: disallow dotkey and inline table migration 2021-12-16 22:16:24 +09:00
ToruNiina
cc1cc27613 fix: disallow merging dotted key and inline table
current code mistakenly allows the following TOML file.
```toml
a.b = 42       # table "a" is defined here, implicitly
a = {c = 3.14} # table "a" is overwritten here
```
But we need to allow the following (structually similar) TOML file.
```toml
a.b = 42   # table "a" is defined here, implicitly
a.c = 3.14 # table "a" is merged with {c = 3.14}
```
To distinguish those, we check whether the current table is defined as
an inline table or via dotted key. If the table we are inserting is
defined via dotted key, we accept it and merge the table. If the table
being inserted is defined as an inline table, then we report an error.
2021-12-16 01:11:47 +09:00
ToruNiina
75e297eb47 fix: Merge branch 'check-datetime'
Briefly check if a given date and time is valid
2021-12-15 22:35:56 +09:00
ToruNiina
0d0605e290 fix #181: Merge branch 'no-null-char' 2021-12-15 22:35:31 +09:00
ToruNiina
23f6c931e5 test: add valid/invalid datetime cases 2021-12-15 00:51:07 +09:00
ToruNiina
518e6d4ae2 feat: check date and time are valid or not 2021-12-15 00:31:41 +09:00
ToruNiina
db2aa55d20 fix: disallow null char at the end of input
since std::string and ""_toml literal actually does not include null
char, we don't need to check if the last char is null or not
2021-12-14 22:33:58 +09:00
ToruNiina
1b5107e5e3 fix #180: Merge branch 'linefeed-at-eof' 2021-12-11 23:13:42 +09:00
ToruNiina
2152c85cd1 test: add test_file_ends_without_lf 2021-12-10 23:46:47 +09:00
ToruNiina
2e4c7fb95e fix: line-feed is not required at the EOF 2021-12-10 23:39:54 +09:00
ToruNiina
2ddcfb4b61 doc: update constributors in README 2021-12-08 21:50:09 +09:00
Toru Niina
3f233d57be Merge pull request #178 from marascio/lrm-resolve-173-free-nonheap-object
Resolve g++ warning: free-nonheap-object
2021-12-05 19:46:38 +09:00
Louis R. Marascio
21732fce45 Resolve g++ warning: free-nonheap-object
As described in issue #173, this warning is raised on various platforms
and in various build types. For example, g++ 11 in release mode will
cause this warning to be raised. This change fixes this warning.
2021-12-01 14:43:43 -06:00
Toru Niina
1dc09d0332 Merge pull request #176 from GMLC-TDC/fix_warnings
Fix warnings
2021-11-25 00:13:36 +09:00
Philip Top
9c1708c988 Update toml/traits.hpp
Co-authored-by: Toru Niina <niina.toru.68u@gmail.com>
2021-11-24 06:40:09 -08:00
Philip Top
84f61f7dc8 match the cmake condition to upstream 2021-11-23 16:16:16 -08:00
Philip Top
eef7106fbe fix more warnings 2021-11-19 10:22:37 -08:00
Philip Top
a919190490 tweak the cmake a little 2021-11-19 08:47:18 -08:00
Philip Top
7f98740c9c update from changes in cmake standard 2021-11-19 08:43:04 -08:00
Philip Top
e08c579e36 fix a change in the key_value name from upstream merge 2021-11-19 08:43:03 -08:00
Philip Top
6dd44dc672 fix project issue with cmake 2021-11-19 08:41:24 -08:00
Philip Top
99e483c447 [ci skip] use a policy in the CMakeLists.txt for toml11 fix some more string_view errors 2021-11-19 08:41:00 -08:00
Philip Top
26a066ad07 skip ci
ci skip

update another string_view issue
2021-11-19 08:39:00 -08:00
Philip Top
acad8b1a61 add additional check for invocability 2021-11-19 08:37:02 -08:00
Philip Top
605cd8ef4a fix shadow and some undef warnings 2021-11-19 08:37:01 -08:00
ToruNiina
bcee9f25a2 fix: check if subtable key conflicts 2021-10-10 20:58:28 +09:00
Toru Niina
f2f2b44d87 Merge pull request #172 from estshorter/fix_readme
fix a compile error in a code example
2021-10-10 14:44:00 +09:00
estshorter
e40dfc28eb fix a compile error in a code example 2021-10-10 14:07:34 +09:00
Toru Niina
24284c70ee Merge pull request #171 from estshorter/issue_170
fix a compile warning C26478
2021-10-10 13:29:37 +09:00
estshorter
dced71224d fix a compile warning C26478 2021-10-09 11:12:58 +09:00
Toru Niina
177c09f43d Merge pull request #169 from ohdarling/fix_force_inline
fix: serializer has wrong constructor params order when format root object
2021-09-24 00:29:14 +09:00
ohdarling
e434c96b7f fix: serializer has wrong constructor params order when format root object 2021-09-22 11:38:42 +08:00
Toru Niina
fda0a2b9ab Merge pull request #167 from karl-nilsson/spelling
Spelling fixes
2021-08-30 01:01:27 +09:00
Karl Nilsson
3eee515ce1 Spelling fixes 2021-08-27 19:52:45 -04:00
ToruNiina
ca9e36a484 fix: avoid duplicated-branches in result
when both two types are trivially destructible, both branches of cleanup
function results in the same code...
2021-07-01 00:46:56 +09:00
ToruNiina
0858fbfced fix: avoid max macro expansion on Windows
in numeric_limits<T>::max
2021-06-30 01:43:27 +09:00
ToruNiina
fe240e1ffc ci: trying to run toml_test 2021-06-30 01:28:53 +09:00
ToruNiina
d9959fcdeb ci: trying to make go get work 2021-06-30 01:18:52 +09:00
ToruNiina
1d0b003312 ci: add a patch to avoid nan comparison 2021-06-30 01:18:42 +09:00
ToruNiina
0aa3773860 feat: add bare minimum utf8 seq validity check 2021-06-30 00:58:50 +09:00
ToruNiina
9745c0005f ci: fix setup of toml-test 2021-06-27 18:58:44 +09:00
ToruNiina
4adf36d9fd test: update typename in json for toml-test 2021-06-27 18:58:10 +09:00
ToruNiina
c72b27bb4b fix: escape control characters in a string 2021-06-27 18:57:20 +09:00
ToruNiina
be5ffaf662 feat: check if width == max before using ml-string 2021-06-27 18:56:57 +09:00
ToruNiina
47a2a3332b fix: use empty quoted string for empty key 2021-06-27 18:56:33 +09:00
ToruNiina
9d28afa012 fix: fix serialization of inf/nan 2021-06-27 18:56:05 +09:00
ToruNiina
f09bd5b035 feat: easy check for datetime 2021-06-27 18:54:55 +09:00
ToruNiina
0dc51f95d9 fix: disallow trailing comma in an inline table 2021-06-27 18:54:28 +09:00
ToruNiina
cf9e86a84f fix: disallow control characters
in basic/literal string and comment
2021-06-27 18:53:48 +09:00
ToruNiina
5190e5148b ci: update go version to 1.16 2021-06-27 16:32:49 +09:00
ToruNiina
45bd566f7a fix: serialization of array containing a table
table in a (hetero-) array should be force-inlined
2021-06-27 16:28:41 +09:00
ToruNiina
2c72329530 ci: remove needless flag and allow hetero array
the example of hetero array (that was not allowed in v0.5.0 but allowed
in v1.0.0-rc1) has been moved from invalid/ to valid/
2021-06-27 16:12:01 +09:00
ToruNiina
1b7ca8566b fix: out_of_range with malformed toml file #164 2021-06-27 15:58:40 +09:00
ToruNiina
647381020e chore: update version number 2021-05-27 10:14:29 +09:00
ToruNiina
f04cf596eb doc: update README 2021-05-26 23:16:03 +09:00
Toru Niina
c281539b26 Merge pull request #161 from cubiest/bugfix/empty_files_missing_filename_in_error
Preserve empty location for empty files
2021-05-26 12:28:38 +09:00
Oliver Kahrmann
58542d36be Preserve empty location for empty files
Without a region, error messages in exceptions are unable to print
a filename.

By retaining the location in a zero-length region and detecting this
when formatting the exception text it is possible to print the filename
and explicitly state that the file is completely empty.

Fixes #160
2021-05-25 20:52:33 +02:00
ToruNiina
c38079f7c0 fix: remove needless include file
that might cause compilation error
2021-05-25 21:40:41 +09:00
ToruNiina
0c4594f59a doc: add TOML11_PRESERVE_COMMENTS_BY_DEFAULT 2021-05-15 21:53:13 +09:00
ToruNiina
e73c98490b doc: add recursive find_or to README 2021-05-15 21:47:03 +09:00
ToruNiina
7b9a1abdb3 feat: add test_find_or_recursive 2021-05-15 20:51:43 +09:00
ToruNiina
891f68eab0 feat: support all &/const&/&& variants 2021-05-15 20:41:11 +09:00
ToruNiina
4b1df61142 Merge branch 'master' into recursive-find-or 2021-05-15 20:01:30 +09:00
ToruNiina
392a260db8 doc: write about precedence 2021-05-15 00:24:51 +09:00
ToruNiina
7339ce39d5 fix: #159 Merge branch 'conversion-precedence' 2021-05-14 20:10:03 +09:00
ToruNiina
287be5a575 ci: clang11 is too new to install it
without adding a new ppa
2021-05-14 18:25:29 +09:00
ToruNiina
798856946f ci: add new compilers
gcc 10, 11, clang 11
2021-05-14 18:19:44 +09:00
ToruNiina
07c1d10212 ci: avoid clang-9 + C++20 because it lacks <=>
And the operator<=> is used in the (GNU-) standard library
implementation installed by default.
Note: consider using libc++ library
2021-05-14 16:16:23 +09:00
ToruNiina
0ac3919e08 feat: from<T> and from_toml precede constructor
constructor sometimes has `template<T> ctor(const T&)` and it causes
ambiguity. To avoid it, from<T> and T.from_toml precedes any
constructor. But, to check the ambiguity between from<T> and from_toml,
they do not precede each other. If anyone define both from<T> and
from_toml, it causes compilation error.
2021-05-14 16:05:54 +09:00
ToruNiina
e622595426 fix: fix has_specialized_from/into
to avoid ambiguity
2021-05-14 16:01:43 +09:00
ToruNiina
72ee8caf09 refactor: use has_specialized_from<T>
to check if toml::from<T> exists for a specific T
2021-05-14 15:53:34 +09:00
ToruNiina
b6e2c6e235 feat: add detail::has_specialization_from/into 2021-05-14 15:46:00 +09:00
ToruNiina
c5a22b9d88 fix: #158 Merge branch 'gcc-wshadow'
The -Wshadow warning is avoided from the source code level
2021-05-11 00:08:32 +09:00
ToruNiina
7e90282175 fix: add region where -Wshadow is ignored on GCC 4 2021-05-10 23:00:30 +09:00
ToruNiina
b8291af42b fix: rename func args to avoid -Wshadow in GCC 4.x 2021-05-10 22:56:16 +09:00
ToruNiina
cd60045014 fix: gcc 7 introduces wshadow variants 2021-05-10 21:51:51 +09:00
ToruNiina
db0d9a024b test: add -Wshadow while compiling tests 2021-05-10 20:49:41 +09:00
ToruNiina
4acc563b28 feat: explicitly avoid -Wshadow=global in GCC 2021-05-10 20:49:20 +09:00
ToruNiina
dce50142e6 fix: avoid argname key to supress warning
about shadowing
2021-05-10 20:47:08 +09:00
ToruNiina
06e8b853ba test: add Wshadow=local 2021-05-04 17:50:14 +09:00
ToruNiina
e3092335aa Merge branch 'enable-to-change-default-comment-handling' 2021-04-30 20:28:38 +09:00
ToruNiina
31b9b79312 ci: suppress clang-8 / c++20 because of gcc header 2021-04-28 15:12:04 +09:00
ToruNiina
beb665ba58 test: explicitly specify if comments are preserved 2021-04-27 13:19:55 +09:00
ToruNiina
b51ef5e869 test: explicitly specify the comment preservation 2021-04-27 13:18:39 +09:00
ToruNiina
21ea4a348d test: explicitly specify template arguments
toml::value is an alias of default parameters, so we need to avoid
conflict of definitions between default and non-default parameters
2021-04-27 13:12:37 +09:00
ToruNiina
c4a803df50 test: add comment/no-comment cases to parse_array
When we add a macro to change the default comment preservation scheme,
some of the current tests that assume comments are discarded by defualt
fails. To make it more robust, we need to explicitly specify the comment
preservation scheme and add test cases for both of discard_ and
preserve_comments.
2021-04-27 13:05:03 +09:00
ToruNiina
c40e0dbd37 feat: use comment macro everywhere 2021-04-16 15:29:24 +09:00
ToruNiina
d90c26f9ac feat: add TOML11_PRESERVE_COMMENTS_BY_DEFAULT 2021-04-16 15:28:58 +09:00
ToruNiina
b592ddcca2 fix: add SFINAE to avoid incorrect matching 2021-04-14 13:09:51 +09:00
ToruNiina
5518b2b155 refactor: simplify last_one_in_pack meta func 2021-04-14 13:09:25 +09:00
ToruNiina
ba3d41d913 feat(#156): add find_or(value, keys..., opt) 2021-04-14 11:22:19 +09:00
ToruNiina
8bc09d552a fix(#139): Merge branch 'auto-conversion-macro' 2021-04-02 19:29:04 +09:00
ToruNiina
03c846dc9d doc: add conversion macro to README 2021-04-02 19:28:45 +09:00
ToruNiina
e658a0126c test: disable macro testing if the macro is diabled 2021-04-02 18:26:24 +09:00
ToruNiina
6e3967e26e ci: check compiler version detected by cmake 2021-04-02 18:24:17 +09:00
ToruNiina
db1f42b5da fix: enable to control macro definition 2021-04-02 17:21:25 +09:00
ToruNiina
c7d6d793cb ci: install compiler 2021-04-02 17:00:00 +09:00
ToruNiina
14c6430dda Merge branch 'master' into auto-conversion-macro 2021-04-02 16:25:41 +09:00
ToruNiina
b4bc704e6e fix: trying to workaround MSVC preprocessor 2021-04-02 15:39:23 +09:00
ToruNiina
3f6e873aba fix: merge branch 'uneven-spacing-between-tables' 2021-03-31 11:53:54 +09:00
ToruNiina
a3b8dd6787 fix(#152): add newline btw kv-pair and subtables 2021-03-31 10:52:18 +09:00
ToruNiina
c121492071 fix: uneven spacing between tables
related: issue #152
2021-03-29 17:48:03 +09:00
ToruNiina
5e3f8f9105 chore: update version values 2021-03-25 22:43:37 +09:00
ToruNiina
17a15d3c18 doc: update contributor list and link in README 2021-03-25 22:33:05 +09:00
ToruNiina
42cc111b05 ci: activate linux/windows
confirmed that macos works.
2021-03-25 15:01:40 +09:00
ToruNiina
5e0ee32854 ci: trying to add macos to github actions [skip travis] [skip appveyor]
it is already listed in travis CI, but not in the GH actions
2021-03-25 14:53:28 +09:00
ToruNiina
2c5cc431fe ci: re-activate linux CI 2021-03-25 14:33:55 +09:00
ToruNiina
970f7cb36a ci: trying to update boost installation settings [skip travis] [skip appveyor] 2021-03-25 14:03:26 +09:00
ToruNiina
b924e70e3c feat: add a simple way to disable <filesystem>
As jwillikers pointed out in #150, there is a case where compiler
defines the corresponding feature test macro of <filesystem> but is
actually not available. The macro is a way to disable the feature
regardless of the status of feature test macro.
2021-03-25 11:44:11 +09:00
Toru Niina
7782258e68 Merge pull request #148 from sneakypete81/patch-1
Fix typo in error message
2021-01-31 14:26:02 +09:00
sneakypete81
08859c36d0 Fix typo in error message 2021-01-30 20:04:00 +00:00
ToruNiina
d3de136562 doc: simplity example code a bit 2021-01-25 17:25:29 +09:00
ToruNiina
43183e2ad1 Merge branch 'master' of github.com:ToruNiina/toml11 2020-12-29 18:54:58 +09:00
ToruNiina
e9144b41fb test: returning toml::value directly from into<T> 2020-12-29 18:53:10 +09:00
ToruNiina
2fb8793f1a doc: add document about basic_value and toml::into
related to #146.
2020-12-29 18:52:07 +09:00
Toru Niina
6c8a53915a Merge pull request #144 from amerry/sstream-include-fix
Add missing standard includes
2020-12-10 01:53:31 +09:00
Alex Merry
db2d33ca4b Add missing header for std::out_of_range exception
Failure seen on GCC 4.8.5 when including "toml/value.hpp".
2020-12-09 10:39:10 +00:00
Alex Merry
935da51769 Add missing include for ostringstream
Since region.hpp no longer includes <iostream> (but only <iomanip>),
source_location.hpp no longer includes a header that provides
std::ostringstream. Including <sstream> fixes this.
2020-12-09 10:19:07 +00:00
ToruNiina
be0d4bd0a9 fix: fix #141; Merge branch 'issue-141' 2020-11-05 00:01:41 +09:00
ToruNiina
9b472a6c72 fix: check it is empty before calling back 2020-11-04 23:24:59 +09:00
ToruNiina
1ead14589e fix: check if it is empty before calling back() 2020-11-04 23:24:02 +09:00
ToruNiina
b13065b1b5 fix: #142 Merge branch 'issue-142' 2020-11-03 21:05:03 +09:00
ToruNiina
a6581ee66b fix: an empty array is not an array of table 2020-11-03 20:34:01 +09:00
ToruNiina
0dafa7ee42 test: add case where a table should be inlined
array-of-table implicitly defines an array. If the array itself has a
comment, we need to format it explicitly.
2020-10-18 20:45:12 +09:00
ToruNiina
908b91079b fix: distinguish the comments and try to keep it
If a value has a comment, we need to try to write it explicitly.
2020-10-18 20:43:33 +09:00
ToruNiina
fce6ff317e refactor: distinguish the reason of failure 2020-10-18 18:36:05 +09:00
ToruNiina
fd50b11523 refactor: add write_comments() 2020-10-18 18:35:56 +09:00
ToruNiina
9090b8273c refactor: move array-of-table stuff to a function 2020-10-18 17:20:06 +09:00
ToruNiina
bfae1ab86c test: add test for auto-generated conversion 2020-10-16 21:40:54 +09:00
ToruNiina
88882b523f feat: add a macro defines convertion automatically 2020-10-16 21:40:47 +09:00
ToruNiina
382e3dc3ab refactor: use serializer::is_array_of_tables 2020-10-14 22:27:29 +09:00
ToruNiina
f7bfcdd7aa fix: check all the elements in an array
while checking if the array is array-of-tables or not (heterogeneous
arrays are allowed, so there might be an array that has a table and
an integer at the same time)
2020-10-14 18:00:04 +09:00
ToruNiina
2e41a26785 Merge branch 'master' of github.com:ToruNiina/toml11 into master 2020-10-14 15:35:18 +09:00
ToruNiina
f3378f0ac1 fix: #131 distinguish implicitly declared array 2020-10-14 15:32:08 +09:00
ToruNiina
12ee73d6a9 ci: suppress some of the combinations in CI
clang-7 with C++20 fails with the same reason, 'undefined reference to
std::allocator<char>::(de)allocate'.
2020-10-14 00:38:46 +09:00
ToruNiina
503baf52ed ci: suppress clang 6 + cxx20
Since the main branch that passed the same check 9 days ago also fails
with clang-6 and C++20 because of the same error, "undefined reference
to allocator_traits<char>::allocate". It could be a change in upstream
and since others (e.g. gcc) works well, I suppress the setting at this
moment.
2020-10-14 00:05:55 +09:00
ToruNiina
2deb75052c ci: use the same version of clang
I don't think it resolves the problem, undefined reference to
'std::allocator<char>::deallocate(char*, unsigned long)', though
2020-10-13 23:37:52 +09:00
ToruNiina
290dca3d67 test: add test for comment duplication 2020-10-13 22:04:28 +09:00
ToruNiina
f283a257d2 Revert "quick temporary patch for comment dup"
This reverts commit a6d38c1ec0.
Since the problem is solved, we don't need this patch any more.
2020-10-13 22:02:32 +09:00
ToruNiina
3d86f3a4e1 fix: avoid comment duplication in array of tables 2020-10-13 21:59:46 +09:00
ToruNiina
dc5a8069a9 refactor: require comments while construction
Note: at this commit, the code would not compile.
2020-10-13 21:58:08 +09:00
Toru Niina
4f31b90665 Merge pull request #136 from chronoxor/master
Fixed: Compile toml11 with MinGW cause error in <filesystem> #135
2020-10-04 18:53:34 +09:00
Ivan Shynkarenka
5d8c573357 Fixed: Compile toml11 with MinGW cause error in <filesystem> #136 2020-10-03 23:16:58 +03:00
Ivan Shynkarenka
6e1e5ccd84 Fixed: Compile toml11 with MinGW cause error in <filesystem> #136 2020-10-03 23:06:47 +03:00
Ivan Shynkarenka
f2d9fd1d1f Fixed: Compile toml11 with MinGW cause error in <filesystem> #136 2020-10-03 22:36:59 +03:00
Ivan Shynkarenka
97c8cbdaf5 Fixed: Compile toml11 with MinGW cause error in <filesystem> #135 2020-10-02 19:10:04 +03:00
ToruNiina
05ceb5ae79 fix: workaround for error around SFINAE in MSVC
avoid lambda with template argument
2020-09-29 02:26:16 +09:00
ToruNiina
96cfdb260a fix: update version in macro and cmake 2020-09-29 01:41:38 +09:00
ToruNiina
0fec125688 feat: remove default value from internal src 2020-09-29 01:40:49 +09:00
ToruNiina
a6d38c1ec0 fix: add a quick temporary patch for comment dup
first aid for #131
2020-09-22 17:36:24 +09:00
ToruNiina
c037913b2c doc: update link to the TOML spec 2020-09-20 19:24:48 +09:00
ToruNiina
6a328fe890 doc: recommend to set /Zc:__cplusplus 2020-09-20 18:07:58 +09:00
ToruNiina
7c18cbb1d9 doc: update section "contributors" 2020-09-19 20:35:37 +09:00
ToruNiina
ba7d49f452 test: use normal string literal
as a workaround for older version of gcc
2020-09-19 19:08:20 +09:00
ToruNiina
b0784ce286 test: in case of comment-before-comma 2020-09-19 18:24:23 +09:00
ToruNiina
670186fac7 Merge branch 'master' into allow-comment-before-comma 2020-09-19 18:10:45 +09:00
ToruNiina
5005998709 Merge branch 'master' into cpp20-mode-u8literal-workaround 2020-09-19 13:42:12 +09:00
ToruNiina
84fb703e04 ci: add utf-8 option to MSVC 2020-09-19 00:41:05 +09:00
ToruNiina
8c2560761b chore: enable to use __cplusplus on MSVC
related: https://github.com/ToruNiina/toml11/issues/112
2020-09-19 00:40:44 +09:00
ToruNiina
07ea5e52e2 ci: pass REQ_FS_LIB=ON in case of g++-8 & C++20 2020-09-16 22:16:20 +09:00
ToruNiina
d2b1e962c9 ci: add std=20 to some compilers on github actions 2020-09-16 21:28:19 +09:00
ToruNiina
528031012d test: add test for u8""_toml literals 2020-09-16 21:25:38 +09:00
ToruNiina
c205c762fe test: remove needless u8s from ascii characters 2020-09-16 21:25:04 +09:00
ToruNiina
a32cd6cb61 feat: enable to use u8""_toml literal in C++20 2020-09-16 21:24:03 +09:00
ToruNiina
38e113d2dc ci: set BUILD_TEST=ON on appveyor 2020-09-15 22:40:24 +09:00
Toru Niina
f15480ae4d Merge pull request #130 from MoAlyousef/master
Make toml11_BUILD_TEST Off by default
2020-09-15 22:28:34 +09:00
MoAlyousef
00bec8ae45 update Running Tests heading 2020-09-14 22:05:15 +03:00
MoAlyousef
d599edd1d4 make testing optional 2020-09-14 20:34:19 +03:00
MoAlyousef
a9534579c6 make testing optional 2020-09-14 20:25:38 +03:00
ToruNiina
c8ff302c94 test: add test for no-eof-newline cases 2020-09-14 16:39:05 +09:00
ToruNiina
003bc16c1b fix: skip the last zero in the file 2020-09-14 16:35:51 +09:00
Toru Niina
9132abc5c4 Merge pull request #127 from kenichiice/fix-include
Fix include path in README
2020-09-07 16:19:29 +09:00
OGAWA KenIchi
99d565bcc4 doc: fix include path
* see #72
2020-09-07 15:32:28 +09:00
ToruNiina
5f38127692 feat: allow comments before comma
replace ws by ws_comment_newline, as suggested.
discussed here: toml-lang/toml/issues/766
2020-08-16 11:03:58 +09:00
ToruNiina
3c3ebd88b4 feat: improve error message about invalid keys 2020-08-09 18:38:50 +09:00
ToruNiina
08f7ea9c56 refactor: remove extraneous whitespaces in errmsg 2020-08-09 18:38:21 +09:00
ToruNiina
cde29399f4 fix: use 1 in source_location as the default pos 2020-08-07 22:24:01 +09:00
ToruNiina
eec429e31b ci: add REQUIRE_FILESYSTEM_LIBRARY on CI 2020-08-06 16:35:49 +09:00
ToruNiina
79ddcaece6 chore: add CMake option to link with (std)c++fs 2020-08-06 16:29:24 +09:00
ToruNiina
8398b9a08b test: use array for char*
forgot to delete
2020-08-05 20:43:48 +09:00
ToruNiina
9c5abf0bfd test: check each overload compiles 2020-08-05 20:29:07 +09:00
ToruNiina
4fa94d45b3 fix: use const char* instead of &char[N]
to enable to pass char*, not only string literal
2020-08-04 20:08:58 +09:00
ToruNiina
46e84a9cc2 refactor: Merge branch 'refactor-region' 2020-07-31 12:45:52 +09:00
ToruNiina
4e6ae9a994 refactor: avoid string construct in format_ul 2020-07-30 16:11:35 +09:00
ToruNiina
f23c003d2f fix: add missing namespace specifier 2020-07-28 00:04:25 +09:00
ToruNiina
4b719f0806 refactor: use location() instead of get_region 2020-07-27 23:15:14 +09:00
ToruNiina
22ace027de refactor: rm template from detail::change_region 2020-07-27 23:04:24 +09:00
ToruNiina
bc219af5b5 refactor: use location() member instead of ctor 2020-07-27 23:03:33 +09:00
ToruNiina
68e8a31659 refactor: remove needless addressof() call 2020-07-27 23:00:40 +09:00
ToruNiina
32a5341d09 refactor: use source_location, not region_base* 2020-07-27 22:29:18 +09:00
ToruNiina
ce68f6f4c2 refactor: check (always-valid) ptr before deref 2020-07-27 21:32:35 +09:00
ToruNiina
e696aabd11 refactor: change internal interface to reduce code
to remove `std::addressof` calls, get_region(toml::value) now
returns a pointer to region.
2020-07-27 00:48:04 +09:00
ToruNiina
7fb93e2f54 fix: add missing explicit to detail::region 2020-07-27 00:20:26 +09:00
ToruNiina
19cc9a2edf refactor: remove template from detail::region 2020-07-25 22:01:34 +09:00
ToruNiina
72f5afb6af refactor: remove template from detail::location 2020-07-25 21:06:26 +09:00
ToruNiina
a8fa14d159 refactor: remove vec() method, use a constructor 2020-07-21 20:55:18 +09:00
ToruNiina
75999aa9ad refactor: add a constructor to location
By adding the constructor, vec() would not be not needed. But inserting
Container = std::string makes the constructor ambiguous, so it breaks
the current code.
2020-07-21 20:53:44 +09:00
ToruNiina
259da54edb refactor: always use vector<char> in location
`location` and `region` have a (shared_ptr to the) container of TOML
contents. Those take a template argument to allow both std::vector<char>
and std::string as an interanal container. But since those are internal
feature, i.e. it should not be used by a user directly, this template
can be removed by re-writing a parser a bit. This introduces a
complexity to toml11 error reporting system, so I'm removing this.
First, remove all the location<std::string> from the parser. Then the
template argument can be removed because everyone uses std::vector<char>
now.
2020-07-20 19:52:11 +09:00
ToruNiina
b461f363da refactor: add a method to reduce complexity later 2020-07-20 19:40:55 +09:00
ToruNiina
d43139a471 doc: update Contributors section 2020-07-19 19:50:02 +09:00
ToruNiina
a344668fa2 doc: update version to 3.5.0 2020-07-19 19:12:18 +09:00
ToruNiina
25aa97a435 doc: add actions status badge to README 2020-07-19 19:09:47 +09:00
ToruNiina
af70d3dfed ci [skip ci]: add github actions workflow file 2020-07-19 17:13:39 +09:00
ToruNiina
8b5cfb4105 test: add missing binary flag to ifstream 2020-07-19 16:57:20 +09:00
ToruNiina
4e0624aa60 feat: make sure the last null is removed 2020-07-19 16:56:31 +09:00
ToruNiina
3ac2c065eb Merge branch 'reorder-headers' to master 2020-07-17 15:17:40 +09:00
ToruNiina
470f81dc94 fix: #123 merge branch 'windows-nominmax' 2020-07-10 20:55:53 +09:00
ToruNiina
93a9f2711c test: add windows.h test 2020-07-10 18:32:59 +09:00
ToruNiina
761e576991 fix: workaround for windows.h that defines min/max
related to #123
2020-07-10 15:07:13 +09:00
ToruNiina
e6e84714c5 Merge branch 'master' into reorder-headers 2020-07-10 00:06:22 +09:00
Toru Niina
1efc99e11c Merge pull request #121 from SeverinLeonhardt/fix_msvc_c4866
Fix MSVC warning C4866
2020-07-03 21:37:22 +09:00
Marius Maaß
92aa42a58e Fix MSVC warning C4866
This fixes the warning "compiler may not enforce left-to-right
evaluation order for call to" that is caused by Visual Studio if this is
compiled with a target of C++17.
2020-07-03 08:00:47 +02:00
ToruNiina
b1c9df8998 feat: reorder headers following google c++ style
related to: #115
2020-06-28 00:58:20 +09:00
ToruNiina
9633e5fe5a doc: add iteration examples into as_xxx section
related to #120
2020-06-21 14:11:26 +09:00
ToruNiina
2164fd39f7 doc: explain about the type of the top-level value
fix #120.
2020-06-21 14:04:20 +09:00
ToruNiina
c22a3fd227 feat: support parse(std::filesystem::path) #113 2020-06-07 15:11:48 +09:00
ToruNiina
57c6652360 Merge branch 'master' into std-filesystem 2020-06-06 17:25:26 +09:00
ToruNiina
defde33544 fix: avoid ambiguity in overload resolution
Since both `std::string` and `std::filesystem::path` can be convertible
from `const char &[N]` (like, `parse("file.toml")`), after adding
`parse(std::filesystem::path)`, the overload resolution of
`parse("file.toml")` becomes ambiguous. By adding `parse(...)` that
exactly matches to `parse("file.toml")`, we can remove this ambiguity.
2020-06-06 17:18:02 +09:00
ToruNiina
46ed051740 fix: pass path.string as a filename 2020-06-05 23:15:19 +09:00
ToruNiina
2963d9a25b feat: add std::filesystem::path support 2020-06-05 19:43:23 +09:00
Toru Niina
531f335417 Merge pull request #119 from halfelf/fix/readme_finding_value_in_table
fix: "Finding a value in an array" example in README
2020-05-20 00:27:33 +09:00
Shu Wang
f29f42277e fix: "Finding a value in an array" example in README 2020-05-18 13:53:48 +08:00
Toru Niina
b03cde566a Merge pull request #117 from usefulcat/master
when parsing a local_time, parse up to 9 digits worth (nanoseconds) o…
2020-05-11 13:36:23 +09:00
Scott McCaskill
57d4e196a3 when parsing a local_time, parse up to 9 digits worth (nanoseconds) of fractional seconds 2020-05-10 16:06:52 -05:00
ToruNiina
deb3ab6617 ci: add DISALLOW_HETEROGENEOUS_ARRAYS 2020-04-03 23:57:52 +09:00
ToruNiina
bf992e8f94 doc: update README for v1-rc1 2020-04-03 23:45:45 +09:00
ToruNiina
7c07f4382c ci: add DISALLOW_HETEROGENEOUS_ARRAYS to toml-test 2020-04-03 23:43:59 +09:00
ToruNiina
125f608fa5 feat: remove TOML11_UNRELEASED_FEATURES.
v1.0.0-rc.1 has been released
2020-04-03 23:42:58 +09:00
ToruNiina
4d0ed847f9 test: remove default ctor from test code 2020-03-30 15:04:51 +09:00
ToruNiina
79594709fe fix: don't use default ctor when converting to map 2020-03-30 15:02:26 +09:00
ToruNiina
55a738c11f Merge branch 'do-not-require-default-ctor-108'
fix #108.
2020-03-28 23:19:52 +09:00
ToruNiina
eebe1f87e6 fix: update cmake version 3.4.0 2020-03-28 17:59:10 +09:00
ToruNiina
95c3b5f538 feat: use push_back instead of resize 2020-03-27 18:06:26 +09:00
ToruNiina
e2790c9e7b test: remove test_resize and add test_try_reserve 2020-03-27 18:06:02 +09:00
ToruNiina
9b52dc0131 feat: remove resize and add try_reserve 2020-03-27 18:05:31 +09:00
ToruNiina
5212992f05 feat: add is_std_forward_list
std::forward_list does not have push_back, insert, or emplace but
push_front, insert_after, and emplace_after. We need to distinguish it
from other continers.
2020-03-27 18:02:37 +09:00
ToruNiina
fcd6e47500 feat: add meta funcs, has_reserve/push_back_method 2020-03-27 18:01:47 +09:00
ToruNiina
31826b55ce feat: avoid double checking in helper methods 2020-03-25 22:49:19 +09:00
ToruNiina
e3fc354e8d Merge branch 'shorten-switch-cast' 2020-03-24 22:43:09 +09:00
ToruNiina
ea87f92358 doc: update exception section in README (fix #107) 2020-03-23 20:57:36 +09:00
ToruNiina
c259456282 ci: fix Travis.CI OS X build 2020-03-22 20:40:02 +09:00
ToruNiina
d7662347f2 refactor: shorten switch_cast definition by macro 2020-03-21 17:44:23 +09:00
ToruNiina
5f5539d402 feat: throw informative error from value.at(...) 2020-03-21 17:09:04 +09:00
ToruNiina
c2151cab0b refactor: show func name in bad_cast from helpers 2020-03-21 17:06:34 +09:00
ToruNiina
653c87592c feat: enable to show function name in bad_cast 2020-03-21 17:04:05 +09:00
ToruNiina
bdf4e75122 refactor: move helper function from get to value 2020-03-21 16:57:12 +09:00
ToruNiina
60d23116ba Merge branch 'master' of github.com:ToruNiina/toml11 2020-03-13 14:38:33 +09:00
ToruNiina
af8cf9ddc5 refactor: remove redundant functions in serializer 2020-03-13 13:55:14 +09:00
ToruNiina
f125cca010 refactor: simplify serializer's template argument 2020-03-12 13:46:17 +09:00
ToruNiina
a20a2c0b80 doc: update README 2020-03-01 00:35:27 +09:00
ToruNiina
9694afbe32 Merge branch 'improve-error-message' 2020-02-29 23:43:23 +09:00
ToruNiina
d11e42ca7e fix: explicitly say the table is top-level
The top-level table has its region at the first character of the file.
That means that, in the case when a key is not found in the top-level
table, the error message points to the first character. If the file has
its first table at the first line, the error message would be like this.
```console
[error] key "a" not found
 --> example.toml
   |
 1 | [table]
   | ^------ in this table
```
It actually points to the top-level table at the first character,
not `[table]`. But it is too confusing. To avoid the confusion, the
error message should explicitly say "key not found in the top-level
table".
2020-02-29 22:56:29 +09:00
ToruNiina
128b66bda9 refactor: add missing whitespace 2020-02-29 22:54:50 +09:00
ToruNiina
d1af42f151 refactor: add throw_key_not_found_error
and replace related throw statements with it
2020-02-29 22:23:15 +09:00
ToruNiina
8acf105b56 doc: update contributor list and test commands 2020-02-27 19:30:34 +09:00
Toru Niina
b86b5364ba Merge pull request #103 from jwillikers/fix_tests
Use FetchContent to retrieve TOML test data
2020-02-27 19:13:02 +09:00
Jordan Williams
bfe57340f4 no longer explicitly clone the TOML repository in CI builds 2020-02-24 08:03:29 -06:00
Jordan Williams
02a6f029ad use ExternalProject to download the toml tests
In order to evaluate the relative paths correctly, add_test should use the current binary directory as the working directory.
2020-02-24 07:59:59 -06:00
Jordan Williams
9017900ff3 set version directly from CMake project command
This silences the warning for CMake policy CMP0048: https://cmake.org/cmake/help/v3.0/policy/CMP0048.html
2020-02-24 07:35:59 -06:00
Jordan Williams
3c5ebd73d7 require CMake version 3.1 2020-02-24 07:31:48 -06:00
Jordan Williams
2223eb4f62 Revert "no longer explicitly clone the TOML repository in CI builds"
This reverts commit fe644ea4b7.
2020-02-24 07:31:15 -06:00
Jordan Williams
a655a71cef Revert "use FetchContent to retrieve TOML test data"
This reverts commit 4c34986db0.
2020-02-24 07:31:06 -06:00
ToruNiina
c34001725c Merge branch 'workaround-gcc-48x' 2020-02-20 11:59:49 +09:00
ToruNiina
5e3ffb70dd fix: check clang macro when checking gcc is used 2020-02-19 17:00:22 +09:00
ToruNiina
2265ca41c6 ci: test with gcc 4.8 and 4.9 on CI 2020-02-19 15:47:34 +09:00
ToruNiina
82fec38e37 refactor: simplify internally-used function 2020-02-19 15:46:25 +09:00
ToruNiina
189b910384 fix: solve #97 in the naivest way, macros 2020-02-19 15:44:38 +09:00
Jordan Williams
fe644ea4b7 no longer explicitly clone the TOML repository in CI builds 2020-02-18 20:21:02 -06:00
Jordan Williams
4c34986db0 use FetchContent to retrieve TOML test data 2020-02-18 19:37:28 -06:00
ToruNiina
ac1130f9f4 tag: update patch version v3.3.1 2020-02-16 22:02:40 +09:00
ToruNiina
d290c3b7e5 doc: add contributor to README 2020-02-14 19:25:41 +09:00
Toru Niina
e4140ac1fd Merge pull request #102 from jwillikers/cmake_cache_variables
Set CMake Standard Cache Variables. Fixes #101
2020-02-13 13:22:25 +09:00
Jordan Williams
ef33c10ba8 use cache variables for the CMake standard and extensions settings 2020-02-12 07:44:47 -06:00
Toru Niina
ced710bb4c Merge pull request #100 from jwillikers/clang_warnings
Silence Clang Warnings. Fixes #98 & #99
2020-02-12 13:37:58 +09:00
Jordan Williams
6b5944e839 fix -Wundef warnings 2020-02-11 06:30:18 -06:00
Jordan Williams
76cae8c057 enable -Wundef flag for tests 2020-02-11 06:25:10 -06:00
Jordan Williams
3930a44ccd enable range-loop-analysis flag for tests 2020-02-11 06:17:54 -06:00
Jordan Williams
3b6417de00 fix clang range-loop-analysis warnings 2020-02-11 06:13:55 -06:00
ToruNiina
573a6f1d81 test: use JSON format_key to format a key in JSON
The rule to format a basic string and a key is different. `"""` cannot
be used with JSON keys. Also, toml key is basically not wrapped by `"`.
So we need a function to format a key in JSON.
2020-02-06 01:28:37 +09:00
ToruNiina
f6a41d986c feat: handle quotes in strings in the better way
- if a basic string contains any double quote, make it multiline.
  - because 1 or 2 consecutive "s do not require escape sequence in it.
- if a basic string will be sufficiently long, make it multiline.
- if 3 consecutive "s appeared, insert backslash to break it down.
2020-02-05 22:42:10 +09:00
ToruNiina
16fc172b21 feat: check string length before adding newline
In literal strings, only the first newline will be trimmed.
```toml
str = '''
The first newline will be trimmed.'''
```
The previous code always adds this first-newline, but after this commit
it checks the length of the string and adds newline if the string is
sufficiently long.
2020-02-05 22:39:08 +09:00
ToruNiina
7d03eb489a test: add test cases with quotes in ml-string
some of these example strings are copied from toml-lang/toml:README.md
and some are modified.
2020-02-04 22:37:11 +09:00
ToruNiina
0582e1535b fix: handle edge-cases with quotes in ml-string
See comments in the code for detail.
2020-02-04 22:36:39 +09:00
ToruNiina
d495df93a6 refactor: remove trailing whitespaces 2020-02-04 22:21:37 +09:00
ToruNiina
5ca3a3c262 refactor: change ifdef UNRELEASED_FEATURE region
to eliminate dead code after returning from a function
2020-02-04 21:05:03 +09:00
ToruNiina
aa8d574dfe chore: update minor version 2020-01-24 22:08:12 +09:00
ToruNiina
49fdb61731 refactor: add explicit to ctors of internal types 2020-01-24 15:58:24 +09:00
ToruNiina
b2bb21a473 doc: update year of copyright notice 2020-01-23 22:18:04 +09:00
ToruNiina
0c58549fc6 Merge branch 'master' of github.com:ToruNiina/toml11 2020-01-22 12:20:34 +09:00
ToruNiina
b7b5e847d3 ci: test with C++14, not only 11/17 2020-01-22 12:19:53 +09:00
ToruNiina
22d630fec1 feat: replace detail::stuff by std if possible 2020-01-20 12:18:05 +09:00
ToruNiina
f7bf341452 fix: add missing noexcept specifier 2020-01-19 21:06:10 +09:00
ToruNiina
0934d90f90 refactor: move ctors that are only used internally 2020-01-19 18:30:27 +09:00
ToruNiina
f2c8d0e279 refactor: add missing explicit to toml::exception 2020-01-19 17:51:24 +09:00
ToruNiina
8c7d83d985 Merge branch 'add-value-member-methods' 2020-01-17 20:30:26 +09:00
ToruNiina
5ce44adbdc doc: add description about toml::value memfuns 2020-01-17 20:26:36 +09:00
ToruNiina
5c5b1320d0 test: add test for map/vector methods 2020-01-16 20:58:36 +09:00
ToruNiina
8b737dc21f feat: add member methods to toml::value 2020-01-16 20:58:10 +09:00
ToruNiina
ee654b6c3f chore: add -Werror when building test codes 2020-01-13 11:31:03 +09:00
ToruNiina
c59782d180 fix: remove useless conversions in the test codes 2020-01-13 11:29:17 +09:00
ToruNiina
9bef715ccd fix: use u32 as a result of binary operation 2020-01-13 11:26:53 +09:00
ToruNiina
d2b1cf5123 refactor: just use a constructor
to remove conversions
2020-01-13 11:26:29 +09:00
ToruNiina
9f92916d1d fix: suppress -Wuseless-conversion
`{integer} + 1` will automatically be an int, so static_cast<int>(a+1)
will be useless conversion.
2020-01-13 11:24:48 +09:00
ToruNiina
666e4cf9dc fix: suppress sign-conversion warnings 2020-01-13 00:46:21 +09:00
ToruNiina
cafee29c64 test: add some combinations of types in toml::find 2020-01-13 00:27:39 +09:00
ToruNiina
a7a2272b29 chore: turn more diagnostic flags on 2020-01-13 00:16:33 +09:00
ToruNiina
dc0bca2bb6 fix: update patch version ... 2020-01-12 23:18:03 +09:00
ToruNiina
490abe04fd refactor: remove redundant template argument 2020-01-12 23:07:17 +09:00
ToruNiina
81ed4c0e9d Merge branch 'master' of github.com:ToruNiina/toml11 2020-01-10 21:17:17 +09:00
ToruNiina
1b07baf184 doc: add toml::get specialization using ctor 2020-01-10 20:46:54 +09:00
ToruNiina
9073d52159 test: check get<foo> works with constructor 2020-01-10 20:39:56 +09:00
ToruNiina
55260654bf feat: get user-defined value by constructor
If a user-defined constructor has constructor(const toml::value&),
then it should be convertible in `toml::get` and `toml::find`.
2020-01-10 20:38:52 +09:00
ToruNiina
aa6271af75 doc: update README 2020-01-09 01:40:05 +09:00
ToruNiina
c54a03f189 Merge branch 'master' into find-idx 2020-01-09 00:27:51 +09:00
ToruNiina
c153c0e8c3 ci: test with sanitizers 2020-01-08 23:28:17 +09:00
ToruNiina
1f90af8e67 ci: refactor list of env vars 2020-01-08 23:17:38 +09:00
ToruNiina
a0c5192b74 chore: add option to use sanitizers 2020-01-08 23:07:05 +09:00
ToruNiina
7f020f3f44 refactor: remove error prefix
that will automatically be added in format_underline
2020-01-07 22:27:13 +09:00
ToruNiina
827b433389 Merge branch 'master' into find-idx 2020-01-07 22:13:15 +09:00
ToruNiina
b1827e6fca test: check immutability of inline tables 2019-12-20 19:46:54 +09:00
ToruNiina
18f84088b4 perf: avoid tmp str construction while checking 2019-12-19 22:13:47 +09:00
ToruNiina
c199bd8b49 feat: enable to access the 1st char of region 2019-12-19 22:13:33 +09:00
ToruNiina
5b35c1a74e fix: prohibit modification on inline table
According to toml-lang/toml:36d3091b3 "Clarify that inline tables are
immutable", check if it adds key-value pair to an inline table.
  This is one of the unreleased (after-0.5.0) toml feature. But this is
marked as "Clarify", so TOML-lang intended that inline tables are
immutable in all version.
2019-12-19 22:02:17 +09:00
ToruNiina
d3513c0f84 fix: fmt line num in err msg correctly 2019-12-17 19:35:26 +09:00
ToruNiina
8567f09cbf chore: update version info in CMake 2019-12-13 20:25:52 +09:00
ToruNiina
a6d24b02d5 Merge branch 'colorize-err-msg' 2019-12-13 20:23:27 +09:00
ToruNiina
08bf5ffbdf doc: put screenshot to colorize-error-message 2019-12-13 17:28:43 +09:00
ToruNiina
a945bd6eac ci: pass TOML11_COLORIZE_ERROR_MESSAGE on CircleCI 2019-12-13 16:47:33 +09:00
ToruNiina
f4ac286b0f doc: add description about format_error 2019-12-12 21:31:21 +09:00
ToruNiina
f31dc6ba37 doc: add example of hints in an error message 2019-12-12 18:09:13 +09:00
ToruNiina
fecd50dfeb doc: add contributors 2019-12-12 18:02:16 +09:00
ToruNiina
d48d454a61 doc: modify README a bit 2019-12-12 17:55:20 +09:00
ToruNiina
4688c235f5 refactor: rename internal macro value 2019-12-12 17:38:29 +09:00
ToruNiina
5c146857a3 Merge branch 'master' into colorize-err-msg 2019-12-11 22:49:38 +09:00
ToruNiina
bc51699415 Merge branch 'bracket-operator' 2019-12-11 19:36:21 +09:00
Toru Niina
8b923d56e9 Merge pull request #96 from kenichiice/icpc_warning2
Suppress warning on Intel C++ Compiler
2019-12-11 18:30:44 +09:00
OGAWA KenIchi
3190c1da9f fix: suppress warning on Intel C++ Compiler 2019-12-11 17:47:16 +09:00
ToruNiina
a41dc08025 doc: add document of operator[] 2019-12-10 20:06:01 +09:00
ToruNiina
0c084b3a5c test: add test: accessing via bracket operator 2019-12-10 00:08:40 +09:00
ToruNiina
8fbeaabfd9 feat: add operator[] to access table/array 2019-12-10 00:00:05 +09:00
ToruNiina
331de4ea5d fix: use datetime info while getting time offset
to convert offset_datetime to system_clock::time_point.
2019-12-08 22:44:12 +11:00
ToruNiina
b246f5ac5c fix: combine date and time to convert loc datetime
Normally DST begins at A.M. 3 or 4. If we re-use conversion operator
of local_date and local_time independently, the conversion fails if
it is the day when DST begins or ends. Since local_date considers the
time is 00:00 A.M. and local_time does not consider DST because it
does not have any date information. We need to consider both date and
time information at the same time to convert it correctly.
2019-12-08 22:38:49 +11:00
ToruNiina
89714fb24b doc: note about local timezone and datetime 2019-12-06 21:15:31 +09:00
ToruNiina
62c01f9826 fix: consider timezone correctly
explicitly set tm.tm_isdst = 0 and use UTC offset
2019-12-06 20:57:51 +09:00
ToruNiina
5a8d368927 feat: add thread-safe detail::gmtime_s 2019-12-06 20:33:15 +09:00
ToruNiina
28519f5712 doc: add colorize section to README 2019-12-02 17:08:00 +09:00
Toru Niina
63fdbd25cf Merge pull request #95 from blockparty-sh/unused-variable-warning
Suppress unused variable warning
2019-11-23 12:59:21 +09:00
blockparty
6d41a1adb9 Suppress unused variable warning 2019-11-22 05:59:55 -06:00
Toru Niina
26a09b2f65 Merge pull request #93 from blockparty-sh/fix_compile_error
Check if features are defined
2019-11-21 21:57:26 +09:00
blockparty
7e62dad6dc Check if features are defined 2019-11-21 05:51:31 -06:00
ToruNiina
2fd466a3c3 fix: skip only the prefix, keep spaces 2019-11-14 15:32:17 +09:00
ToruNiina
6f7539dc6a fix: deduplicate [error] prefix in the messages 2019-11-14 15:31:27 +09:00
ToruNiina
f290390c63 fix: consider the no-space cases like [error]: 2019-11-13 18:14:42 +09:00
ToruNiina
571baa2c26 refactor: remove nocolor:: operations
since color can be on-off at runtime
2019-11-13 18:08:31 +09:00
ToruNiina
bbe33e87d9 feat: detect [error] prefix duplication 2019-11-13 18:05:37 +09:00
ToruNiina
4c5076f263 feat: add runtime colorize flag 2019-11-13 18:01:47 +09:00
ToruNiina
d47174954f feat: colorize user-defined msg by format_error 2019-11-13 18:00:55 +09:00
ToruNiina
821eb9632b feat: add a macro-dependent constant 2019-11-13 17:59:47 +09:00
ToruNiina
af116991b6 fix: remove overlapping [error] sign 2019-11-13 17:35:23 +09:00
ToruNiina
87bebbc37d feat: put color to the internal error messages 2019-11-13 17:35:05 +09:00
ToruNiina
c2d0351e69 feat: add (ANSI) terminal colorize operators 2019-11-13 17:24:51 +09:00
ToruNiina
1526b9feee Merge branch 'heterogeneous-array' 2019-11-09 11:03:18 +09:00
ToruNiina
281206dcc6 doc: add heterogeneous array to README 2019-11-08 19:03:16 +09:00
ToruNiina
adf8fa9234 fix: fix typos in an error message in toml::get
when converting toml::value to std::tuple
2019-11-08 16:12:18 +09:00
ToruNiina
0a66be3257 test: add test for parsing heterogeneous array
this test case is activated only if TOML11_USE_UNRELEASED_TOML_FEATURES
is defined.
2019-11-08 15:52:31 +09:00
ToruNiina
160537360c test: deactivate error check for hetero array
if TOML11_USE_UNRELEASED_TOML_FEATURES is activated.
2019-11-08 15:39:14 +09:00
ToruNiina
9af2d65417 feat: allow heterogenous array
if TOML11_USE_UNRELEASED_TOML_FEATURES is activated.
In TOML v0.5.0, heterogenous arrays are not allowed. But after some
discussions in toml-lang/toml, it is decided to allow it in the next
release (toml-lang/toml/pull/676).
To support it, disable type check in parse_array function.
2019-11-08 15:36:58 +09:00
ToruNiina
429763377f Merge branch 'add-src-loc-to-exception' #87 2019-11-02 13:42:14 +09:00
ToruNiina
c774beb79a doc: write about source_location in exceptions 2019-11-02 13:03:50 +09:00
ToruNiina
8240fffeca Merge branch 'master' into add-src-loc-to-exception 2019-11-02 12:53:16 +09:00
ToruNiina
047611764c fix: silly typo 2019-11-01 21:15:20 +09:00
ToruNiina
bc3eb9d967 feat: add src_loc to all the exceptions
including internal_error.
2019-11-01 21:14:33 +09:00
ToruNiina
6862264bde feat: use the first char as the top-level region
A bit related to #89
2019-11-01 20:47:25 +09:00
ToruNiina
2ee69fc420 fix: improve error messages about strings a bit 2019-11-01 13:34:15 +09:00
ToruNiina
6a15e8360f refactor: remove redundant namespace specifier 2019-10-31 23:13:49 +09:00
ToruNiina
b4c6d26842 Merge origin/add-src-loc-to-exception #87 2019-10-31 23:11:53 +09:00
ToruNiina
41eb1d6887 feat: pass source_location to exception 2019-10-31 22:23:31 +09:00
ToruNiina
3ca712a8da feat: check line_num before converting it to int 2019-10-31 22:21:24 +09:00
ToruNiina
8e589ff4d7 feat: add source_location to (syntax_|type_)error 2019-10-31 22:04:16 +09:00
ToruNiina
56812114c3 refactor: simplify inclusion dependencies 2019-10-31 21:58:28 +09:00
ToruNiina
f98615d0df fix: check file content is empty or not 2019-10-30 16:49:49 +09:00
ToruNiina
37769e28f0 fix #88: check if input is null-terminated or not 2019-10-30 16:33:22 +09:00
ToruNiina
2acdec00aa Merge branch 'refactor-ci' 2019-10-15 23:13:44 +09:00
ToruNiina
354cfc979a ci: cache brew directory 2019-10-15 23:13:11 +09:00
ToruNiina
3dc3b001ff ci: update clang 3.x from 3.7 to 3.9 2019-10-15 23:13:06 +09:00
ToruNiina
ea24a91f4c ci: use sourceline 2019-10-15 20:32:09 +09:00
ToruNiina
5bba73a8ca ci: use addons in OS X on Travis.CI 2019-10-15 20:27:27 +09:00
ToruNiina
54eced6c82 test: add test for toml::string::operator+= 2019-10-09 21:51:33 +09:00
ToruNiina
258e62f8f3 feat: add operator+= to toml::string 2019-10-09 21:51:14 +09:00
ToruNiina
06086a9ff7 doc: add note about value::at 2019-10-09 21:09:38 +09:00
ToruNiina
b4b35ea33e feat: allow 0-prefix exponent if the flag is on
If unreleased feature is activated, zero-prefixes in an exponent part of
a floating point is allowed. If the flag TOML11_UNRELEASED_TOML_FEATURES
is turned on, we don't need to check whether there is a zero prefix in
the exponent part that is formatted by a standard library.
2019-10-08 23:23:53 +09:00
ToruNiina
d7b4d104d3 refactor: reduce checking; just check once 2019-10-08 23:15:03 +09:00
ToruNiina
1148d01c70 Merge branch 'master' into find-idx 2019-10-07 11:11:08 +09:00
ToruNiina
e12fd4d944 doc: add contributors 2019-10-04 14:28:43 +09:00
ToruNiina
36af02cb3a test: add test cases for one-way conversion 2019-10-04 13:01:15 +09:00
ToruNiina
488015df49 fix: toml -> T is required; related to #83 2019-10-04 13:00:34 +09:00
Toru Niina
1f951e49b1 Merge pull request #84 from jcmoyer/master
Update documentation for toml::from and toml::into
2019-10-04 12:58:13 +09:00
J.C. Moyer
6a7dbb7875 Update documentation for toml::from and toml::into 2019-10-03 21:28:06 -04:00
ToruNiina
17d78553ff test: add test cases for find(v, idx)
- check whether find(v, idx) throws
- check find(v, ks...) works with both indices and strings
2019-10-03 15:48:04 +09:00
ToruNiina
4c12dad51f feat: add find<T>(value, idx) for arrays (#79) 2019-10-03 15:27:25 +09:00
ToruNiina
ad7eb56634 fix: avoid potential memory bugs related to move 2019-10-03 14:42:52 +09:00
ToruNiina
b01c5534ed test: add test cases for const-ref version 2019-10-03 13:52:12 +09:00
ToruNiina
22dac3c9f2 Merge branch 'value-at' 2019-09-28 19:40:51 +09:00
ToruNiina
d5adfe8c7d refactor: use as_xxx instead of cast<enum>
because cast<enum>() requires `template` specifier inside a template
function. it makes code long.
2019-09-28 17:01:45 +09:00
ToruNiina
4bb8045c84 doc: add basic_value::at. 2019-09-28 16:31:45 +09:00
ToruNiina
babb6ab3fe test: add test case for basic_value::at 2019-09-28 16:22:01 +09:00
ToruNiina
d73bc6076c feat: add basic_value::at(key) and at(idx) 2019-09-28 16:21:51 +09:00
ToruNiina
8d1da6e8b5 test: add test cases for find_or(&&) + conversion 2019-09-28 14:01:33 +09:00
ToruNiina
8276e12f06 test: add test cases for toml::find_or(value&&) 2019-09-28 13:38:59 +09:00
ToruNiina
f3d3f63ff9 fix: return values from find_or(value&&) 2019-09-28 13:38:26 +09:00
ToruNiina
d9689c878d test: add test cases for toml::find(value&&, key) 2019-09-28 13:05:13 +09:00
ToruNiina
df097cb09a test: add test cases of get_or(value&&, U) 2019-09-28 12:13:59 +09:00
ToruNiina
a425e3b7c6 test: add test cases of toml::get_or(value&&, T&&) 2019-09-28 12:08:14 +09:00
ToruNiina
e4b4503b81 style: add comment to test::operator<< 2019-09-28 12:07:53 +09:00
ToruNiina
b44fbad925 fix: remove needless ::type 2019-09-28 11:14:14 +09:00
ToruNiina
826c9444ac refactor: use remove_cvref 2019-09-28 11:03:46 +09:00
ToruNiina
a1095f3e4c refactor: use std::map::at instead of [] 2019-09-28 11:03:14 +09:00
ToruNiina
483a39beb4 refactor: remove unsupported overload
expect<T>(table, ...)
2019-09-28 11:00:35 +09:00
ToruNiina
1409114c96 refactor: add utility meta-func for internal use 2019-09-28 10:58:02 +09:00
ToruNiina
ecfc9d0c5a fix: make return type rvalue when rvalue is passed 2019-09-28 10:31:10 +09:00
ToruNiina
94f76137a3 doc: add description of unreleased toml features 2019-09-05 14:31:05 +09:00
ToruNiina
c2e1aa9a3c Merge branch 'master' into fp-exp-leading-zeroes 2019-09-05 13:50:58 +09:00
ToruNiina
5b5ece6c32 fix: add "unreleased" flag to raw-tab-in-string 2019-09-04 18:10:15 +09:00
ToruNiina
b696e327d7 ci: add options to test toml-head features 2019-09-04 13:37:08 +09:00
ToruNiina
757e5d60be test: add flag for toml-head features to tests 2019-09-04 13:36:42 +09:00
ToruNiina
c02093de7f chore: add an option to tests
that enable/disable to use unreleased toml features
2019-09-04 13:34:28 +09:00
ToruNiina
4f8b62a7e9 feat: add TOML11_USE_UNRELEASED_TOML_FEATURES flag
to choose to use unreleased toml feature
2019-09-04 13:32:05 +09:00
ToruNiina
d9b8582c47 test: add test for toml::get<T>(std::move(v)) 2019-09-01 19:39:37 +09:00
ToruNiina
c9543d8d9e test: add test of find_or with conversion 2019-08-31 13:05:05 +09:00
ToruNiina
15b68a89c6 fix: suppress warnings by forwarding argument 2019-08-31 13:04:25 +09:00
ToruNiina
64e7bdb835 test: add test for leading zeroes in fp exp 2019-08-28 17:49:12 +09:00
ToruNiina
1acf87679e feat: permit leading 0s in exp parts of floats
This is an unreleased feature of toml language, but is merged into
toml-lang/toml:master.
2019-08-28 16:02:10 +09:00
ToruNiina
7a1b5bd64e fix: skip whitespaces without newline 2019-08-26 18:16:09 +09:00
ToruNiina
e332e018db feat: allow raw tab characters in basic strings
This feature is planned to be incorporated in toml v1.0.0 but not
released yet.
2019-08-21 11:19:47 +09:00
ToruNiina
b1ec6d87bd chore: update patch version 2019-08-07 15:58:28 +09:00
ToruNiina
8dded288b4 Merge branch 'master' into find-or-value 2019-08-07 14:58:56 +09:00
ToruNiina
0f491c7f3a fix: add overload for find_or with toml::value 2019-08-07 14:55:30 +09:00
ToruNiina
5edf43a1d2 test: add missing include file to test code 2019-07-23 22:32:32 +09:00
ToruNiina
cffc605505 fix: stop including iostream 2019-07-23 22:27:20 +09:00
ToruNiina
fb91936a1d fix #76: correct version description in CMakeLists 2019-07-21 13:16:48 +09:00
ToruNiina
8833292858 doc: rearrange toml::find section in README 2019-07-19 20:42:47 +09:00
ToruNiina
3fe04aff77 doc: fix sample script in README 2019-07-19 20:13:12 +09:00
ToruNiina
138f030b5d doc: fix sample codes in README 2019-07-18 17:39:24 +09:00
ToruNiina
2eb2e0a753 doc: update README 2019-07-13 15:11:01 +09:00
ToruNiina
87e0ba201e feat: enable to swap comment and strings 2019-07-13 14:33:14 +09:00
ToruNiina
24a05c7c93 doc: update serialization section #73 2019-07-10 09:12:38 +09:00
ToruNiina
c3653b85f1 doc: fix include directory #72 2019-07-10 08:45:09 +09:00
ToruNiina
00b05c63b9 doc: add explanation about os << toml::string 2019-07-07 21:24:33 +09:00
ToruNiina
35b7c79ebd doc: update README 2019-07-03 17:33:24 +09:00
ToruNiina
9ef146d022 🔀 Merge branch 'v3' 2019-07-03 17:31:45 +09:00
ToruNiina
2c192af35d test: add test for toml::string format 2019-06-29 20:20:31 +09:00
ToruNiina
c2435b0d56 feat:boom:: format toml::string as TOML format 2019-06-29 20:19:47 +09:00
ToruNiina
9b12b17d5e ci: fix ci job script 2019-06-29 17:36:16 +09:00
ToruNiina
e61b38fac2 ci: add test_serialization to the jobs 2019-06-29 16:45:59 +09:00
ToruNiina
716f7bacba ci: run serialization test to circleci 2019-06-29 16:43:11 +09:00
ToruNiina
299d1098e4 test: add serialization test for arbitrary file 2019-06-29 16:40:42 +09:00
ToruNiina
c272188060 fix: check inline table does not include LF 2019-06-29 16:39:54 +09:00
ToruNiina
0fc0967f6f fix: remove CR before comparing to the reference 2019-06-29 15:38:28 +09:00
ToruNiina
df0d870c97 test: add test for serialization with nocomment 2019-06-29 15:00:00 +09:00
ToruNiina
d5299fef04 feat: add no_comment option to serializer 2019-06-29 14:59:18 +09:00
ToruNiina
937a3b4a2e test: add test for nocomment/showcomment 2019-06-28 19:09:05 +09:00
ToruNiina
0502924d25 feat: add nocomment and showcomment 2019-06-28 19:08:48 +09:00
ToruNiina
6182f3ee9d test: add test for operator<<(os, non-table-value) 2019-06-28 17:56:41 +09:00
ToruNiina
3624e4b690 fix: put comment just after non-table values
When non-table value is passed to the `operator<<`, it assumes that the
original C++ code looks like the following.

```cpp
std::cout << "key = " << v << std::endl;
```

In this case, the comment associated to `v` should be put just after
`v`, not before.
```toml
key = # comment <= bad
"value"

key = "value" # comment <= good
```

So, if `v` is not a table it would put comments just after the value.
2019-06-28 17:53:19 +09:00
ToruNiina
37e96ed8dc test: add test for format_key() 2019-06-28 17:47:42 +09:00
ToruNiina
79e7511871 feat: add format_key to help serialization 2019-06-28 17:47:19 +09:00
ToruNiina
284f122433 refactor: replace for-loop by comment output 2019-06-28 14:58:47 +09:00
ToruNiina
134475e292 test: check ostream op for comment containers 2019-06-28 14:58:16 +09:00
ToruNiina
28b3f7d6fb feat: add ostream operator to comment containers 2019-06-28 14:57:45 +09:00
ToruNiina
6b5fd349aa fix: initialize source_location correctly 2019-06-26 21:35:01 +09:00
ToruNiina
76e44a0c48 refactor: remove needless inline specifier 2019-06-26 21:34:36 +09:00
ToruNiina
b4bbd0a005 chore: update version string in CMakeLists 2019-06-26 21:31:35 +09:00
ToruNiina
f9ee645dc2 doc: add link to v3 branch 2019-06-23 21:00:59 +09:00
ToruNiina
6a251f582e refactor: remove needless code snippet 2019-06-22 17:52:01 +09:00
ToruNiina
74ef494797 feat: remove unused trait types 2019-06-22 17:35:40 +09:00
ToruNiina
3a5f8a4b88 test: rename test source file 2019-06-22 17:23:51 +09:00
ToruNiina
4d2b24b647 test: add test_find_or 2019-06-22 16:58:45 +09:00
ToruNiina
3fcb6bb20d test: fix test module name 2019-06-22 16:58:21 +09:00
ToruNiina
1e8af710a0 test: add test for get_or 2019-06-22 16:39:01 +09:00
ToruNiina
0ca8eeeb09 test: add missing include files 2019-06-21 17:11:21 +09:00
ToruNiina
a343ffd2a1 doc: update README 2019-06-21 17:02:30 +09:00
ToruNiina
b79797d2c7 refactor: replace BOOST_CHECK_EQUAL by BOOST_TEST 2019-06-21 16:01:14 +09:00
ToruNiina
90918b6d76 test: add basic_value type to serialization tests 2019-06-21 16:01:08 +09:00
ToruNiina
dd9b04ae3b fix: fix test case name 2019-06-21 16:01:04 +09:00
ToruNiina
4032b438c0 fix: time offset may change while conversion 2019-06-21 16:00:48 +09:00
ToruNiina
7b37d876ae refactor: update Boost.Test v2 to v3 2019-06-21 14:50:17 +09:00
ToruNiina
713b42e589 refactor: use CHECK_THROW macro to check it throws 2019-06-21 14:47:27 +09:00
ToruNiina
1694f74510 chore: update boost test library usage (v2->v3) 2019-06-21 14:43:13 +09:00
ToruNiina
9f69ffa993 fix: add unsigned symbol to integer literals 2019-06-21 14:42:44 +09:00
ToruNiina
0cee58b0b1 Merge branch 'v3' of github.com:ToruNiina/toml11 into v3 2019-06-21 14:31:52 +09:00
ToruNiina
ab1ef63da6 doc: add value ctor with comments to README 2019-06-21 14:31:28 +09:00
ToruNiina
e8d535e485 test: add tests for constructors with comments 2019-06-21 14:26:49 +09:00
ToruNiina
d4afed5bbb feat: construct value with a list of comments 2019-06-21 14:26:05 +09:00
ToruNiina
3ef8bddb6d doc: update README 2019-06-21 13:23:15 +09:00
ToruNiina
a68543a895 fix: detect comment in stricter way 2019-06-21 13:10:02 +09:00
ToruNiina
ec839bbd75 chore: add -Wextra when compiling tests 2019-06-21 00:29:45 +09:00
ToruNiina
ecf55f86d6 refactor: add explicit type conversion 2019-06-21 00:25:57 +09:00
ToruNiina
3b71f80652 refactor: streamsize is a signed integer 2019-06-21 00:00:37 +09:00
ToruNiina
be2d2aec52 refactor: explicitly convert difference_t to size_t 2019-06-20 23:59:16 +09:00
ToruNiina
be04bf1302 refactor: convert file size to size_t 2019-06-20 23:58:35 +09:00
ToruNiina
427706d671 fix: explicitly add float conversion 2019-06-20 23:58:15 +09:00
ToruNiina
71ff54e76c fix: rearrange internal int types in datetimes 2019-06-20 23:58:08 +09:00
ToruNiina
8208bbf236 fix: check and convert value manually
I totally have no idea when std::count returns a negative value, but the
result type of `std::count` is a differnce_type. So when it is added
with size_t value, implicit sign conversion happens. This changes check
this kind of (almost trivial but required) checking.
2019-06-20 22:27:16 +09:00
ToruNiina
f689d26294 refactor: add conversion function to utf8 encoder 2019-06-20 22:25:40 +09:00
ToruNiina
9e6d8e76d0 fix: replace null deref by terminate for safety
Since empty_iterator never points anything, so it always points null
(it returns nullptr by operator->). but dereferencing null causes UB.
Just calling std::terminate is of course better.
2019-06-20 20:56:49 +09:00
ToruNiina
0e2e4a26be ci: Revert "ci: use libstdc++ when compiling"
Ok, it already worked without this.
This reverts commit 092db50700.
2019-06-20 20:48:17 +09:00
ToruNiina
092db50700 ci: use libstdc++ when compiling
because some of the earlier versions of libc++ does not conform c++11
2019-06-20 20:43:57 +09:00
ToruNiina
295e9bb795 ci: try to update system library 2019-06-20 20:24:12 +09:00
ToruNiina
dd2238e1ad ci: change apt source on travis
clang 3.7 trusty version seems to be restricted. I don't know why, but
precise version seems to be working.
2019-06-20 20:21:06 +09:00
ToruNiina
5dfa88a1b3 ci: rename package to be installed 2019-06-20 20:13:16 +09:00
ToruNiina
37b4442d7f ci: upgrade boost on Travis Linux 2019-06-20 20:00:56 +09:00
ToruNiina
48aa0a4c67 ci: update boost version on appveyor 2019-06-20 19:53:27 +09:00
ToruNiina
86a1f7ad75 fix: add missing include files 2019-06-20 16:23:51 +09:00
ToruNiina
99c10dd6bc fix: enable to deduce what basic_value to be used 2019-06-20 16:21:01 +09:00
ToruNiina
7d087ef2a8 doc: update README 2019-06-20 15:22:20 +09:00
ToruNiina
a0d74a5542 doc: add info about breaking changes to README 2019-06-20 14:58:18 +09:00
ToruNiina
c3922c0d51 test: move some test_cases across test files 2019-06-20 14:43:31 +09:00
ToruNiina
5e5a757208 fix: conversion between different basic_value s 2019-06-20 14:35:38 +09:00
ToruNiina
f178379c07 test: add test_find 2019-06-20 14:34:42 +09:00
ToruNiina
321db42b1c Merge branch 'master' into v3 2019-06-19 23:44:09 +09:00
ToruNiina
1bf9e42835 chore: update version 2019-06-19 21:12:05 +09:00
ToruNiina
3379ed82ec refactor: remove meaningless meta conditions 2019-06-19 20:06:06 +09:00
ToruNiina
9663a6bbdb Merge branch 'master' into v3 2019-06-19 19:53:08 +09:00
ToruNiina
4a2c823d56 fix: comparison between values that has a table 2019-06-19 19:32:25 +09:00
ToruNiina
9a47c2a15a Merge branch 'v3' of gitlab.com:ToruNiina/toml11 into v3 2019-06-19 19:03:47 +09:00
ToruNiina
3311d00845 Merge branch 'v3' of gitlab.com:ToruNiina/toml11 into v3 2019-06-19 19:05:22 +09:00
ToruNiina
24c28c7f4f fix: correct some SFINAE expressions 2019-06-19 18:59:12 +09:00
ToruNiina
cab3144507 style: format CMakelists.txt 2019-06-19 16:53:45 +09:00
ToruNiina
7e5859ba73 Merge branch 'master' into v3 2019-06-19 15:36:27 +09:00
ToruNiina
dee32e7d5e style: make hint messages clearer 2019-06-19 12:58:34 +09:00
ToruNiina
53a185e7a9 fix: revert misjudgement as a bug
Probably I'm too tired.

This reverts commit adcd75e017.
2019-06-18 21:41:30 +09:00
ToruNiina
fd980a8c5d 🔀 Merge branch 'guess-type-error' 2019-06-18 21:29:45 +09:00
ToruNiina
73ac43d70c doc: add contributor 2019-06-18 21:28:50 +09:00
ToruNiina
adcd75e017 fix: correctly initialize offset 2019-06-18 21:27:16 +09:00
ToruNiina
3613580bb3 doc: update README 2019-06-18 21:26:17 +09:00
ToruNiina
d9f9df61a2 fix: fix links in README 2019-06-18 01:39:36 +09:00
ToruNiina
32d5c9e924 fix: serialize array correctly 2019-06-18 01:27:52 +09:00
ToruNiina
262f9c5fcc fix: avoid duplicating comment: array/table elems 2019-06-18 01:26:40 +09:00
ToruNiina
86e55c3bf7 test: check serialization keeps comments 2019-06-18 01:26:16 +09:00
ToruNiina
159283fdad test: check preserve_comment keep it read 2019-06-18 01:25:43 +09:00
ToruNiina
fb5834caab refactor: exchange order of test section 2019-06-18 00:45:30 +09:00
ToruNiina
ca084abe90 feat: consider the first comments as a file comment 2019-06-18 00:44:49 +09:00
ToruNiina
7b1a788e2d feat: enable to convert vector<string> to comments 2019-06-18 00:43:25 +09:00
ToruNiina
228487eafd test: fix typos in tests 2019-06-17 23:46:42 +09:00
ToruNiina
f744a792e2 fix: constructor with array-like types 2019-06-17 23:45:43 +09:00
ToruNiina
bf2dc76d5e test: add test for templatized conversions 2019-06-17 23:21:18 +09:00
ToruNiina
4d267cadf4 doc: add templatized conversion to README 2019-06-17 23:12:46 +09:00
ToruNiina
bc68a9d9ee refactor: remove needless include file 2019-06-17 23:07:14 +09:00
ToruNiina
4008c24e84 test: add test for init-list-map to value conversion 2019-06-17 22:50:38 +09:00
ToruNiina
c2b0de623f feat: enable to convert map-like to toml::value 2019-06-17 22:50:14 +09:00
ToruNiina
af11d56e79 fix: correctly move value from find_or to get_or 2019-06-17 22:40:52 +09:00
ToruNiina
5cb7c961aa fix: update README 2019-06-17 22:26:41 +09:00
ToruNiina
bf4eae0b76 test: drop test for find_or(table) 2019-06-17 22:14:26 +09:00
ToruNiina
6399d44e3b fix: consider comments while serialization 2019-06-17 22:13:58 +09:00
ToruNiina
d10c0725fd fix: consider closing bracket when collect comments
table = {key = "value"} # comment.
a value named "table" ({key = "value"}) has the above comment.
but a value named "key" ("value") does not have any comment.
2019-06-17 22:12:20 +09:00
ToruNiina
7eac3a3028 feat: support serialization of basic_value 2019-06-17 20:34:42 +09:00
ToruNiina
57b5545ba2 fix: add _type suffix to value::xxx_type 2019-06-17 20:34:13 +09:00
ToruNiina
f36b39c04f fix: consider comments while comparing values 2019-06-17 20:33:57 +09:00
Toru Niina
569341a514 Merge pull request #69 from KerstinKeller/cmake_install
Allow to install toml11 library with CMake.
2019-06-17 18:03:00 +09:00
KerstinKeller
0357d8fb57 Add newline to end of CMake files. 2019-06-17 10:04:39 +02:00
ToruNiina
00d40140ac doc: add an example of error message to README 2019-06-17 12:59:29 +09:00
ToruNiina
1bfe8f1f54 Merge branch 'master' into guess-type-error 2019-06-17 12:48:36 +09:00
ToruNiina
b3300fad2a fix: move element of map in toml::find(val&&) 2019-06-17 12:13:59 +09:00
ToruNiina
94bcf0aae9 Merge branch remote into v3 2019-06-17 12:10:45 +09:00
ToruNiina
bc143263cd Merge branch 'revert-recursive-find' 2019-06-17 11:54:52 +09:00
ToruNiina
0ef232a1e0 feat: 💥 remove toml::find_or for toml::table 2019-06-17 01:26:05 +09:00
ToruNiina
0604cf813a feat: 💥 remove toml::find for tables 2019-06-17 01:24:32 +09:00
ToruNiina
10f410a02c doc: add some notes and comments to README 2019-06-17 00:48:06 +09:00
ToruNiina
12ef0f6287 doc: add containers and comments to README 2019-06-17 00:29:43 +09:00
ToruNiina
d9ad0e4b92 doc: add source_location to README 2019-06-16 23:44:54 +09:00
ToruNiina
1b19d5f1eb doc: update README 2019-06-16 21:44:59 +09:00
ToruNiina
fd7da05798 doc: update README 2019-06-16 20:31:08 +09:00
ToruNiina
cbaaaaca7c revert recursive find function
I found that in a user-code (I'm also one of the users of this library),
this new feature sometimes causes an error. Some of my code won't
compile because of this change. Since toml::table is convertible to
toml::value *implicitly*, if toml::find(table, key, tablename) was
called, the overload resolution becomes ambiguous with toml::find(
value, key1, key2). But dropping support for toml::find(toml::table,
key, tablename) is a breaking change. So I concluded that now is not
the right time yet.
2019-06-16 19:55:40 +09:00
ToruNiina
cf1c9371b6 fix: correct example and positions in err msgs 2019-06-16 17:52:42 +09:00
ToruNiina
62e8d58d8d feat: guess possible format errors 2019-06-16 17:32:29 +09:00
ToruNiina
fec4e1db9a doc(WIP): add source_location to README 2019-06-15 20:34:20 +09:00
ToruNiina
8665272bab test: add test for custom basic_value type 2019-06-15 20:25:19 +09:00
ToruNiina
cc4a9c8d5d fix: consider identity conversion in SFINAE 2019-06-15 20:20:14 +09:00
ToruNiina
af19dfe032 fix: conversion between different basic_values 2019-06-15 20:19:51 +09:00
ToruNiina
64dc086878 doc(WIP): re-write README 2019-06-15 19:50:31 +09:00
ToruNiina
9acc55a7ac test: add test for discard_comment 2019-06-15 17:18:25 +09:00
ToruNiina
177022b2cb test: update tests for comment 2019-06-15 17:13:25 +09:00
ToruNiina
5726d10339 feat: save comment information in value 2019-06-15 17:13:02 +09:00
ToruNiina
a6706f7879 fix: templatize internal function for value 2019-06-15 17:12:30 +09:00
ToruNiina
558349170d fix: correct the order and remove last CR 2019-06-15 17:11:49 +09:00
ToruNiina
eb4eca86db feat: 💥 change comment interface in region 2019-06-15 16:11:05 +09:00
ToruNiina
d8a9ee4f72 🔀 Merge branch 'master' into v3 2019-06-15 15:17:08 +09:00
KerstinKeller
acbc2a73cb Allow to install tom11 library with CMake.
Add option to build tests.
2019-06-14 17:24:21 +02:00
ToruNiina
b2daf916b3 doc: add contributor to README 2019-06-11 22:45:46 +09:00
Toru Niina
e66bb3d359 Merge pull request #67 from ToruNiina/hotfix
suppress warnings on clang v7+
2019-06-10 10:54:54 +09:00
Toru Niina
cfaa94f072 Merge pull request #68 from khoitd1997/master
fix sign-compare warning
2019-06-10 10:49:49 +09:00
khoitd1997
2f4f3efbf0 fix sign-compare warning 2019-06-09 12:00:28 -07:00
ToruNiina
06ae67502a fix: move argument correctly 2019-06-09 21:05:46 +09:00
ToruNiina
6345910c3e 🔀 Merge branch 'master' into v3 2019-06-08 20:05:05 +09:00
ToruNiina
9948549b62 fix: add missing template parameters 2019-06-08 19:53:50 +09:00
ToruNiina
54d46f08c3 🔀 Merge branch 'master' into v3 2019-06-08 19:40:11 +09:00
ToruNiina
57cb806e14 Merge branch 'master' into throw-from-as-something 2019-06-08 19:23:32 +09:00
ToruNiina
d6f3654185 refactor: reduce test code by using CHECK_THROW 2019-06-08 19:23:12 +09:00
ToruNiina
8befe3f1ad test: add test for throw/nothrow versions of as_* 2019-06-08 19:20:09 +09:00
ToruNiina
2d43119ac7 doc: change README a bit 2019-06-07 21:05:33 +09:00
ToruNiina
436af12815 doc: update README 2019-06-07 19:43:01 +09:00
ToruNiina
4f4d4380f2 feat: throw from as_* if type differs 2019-06-07 19:34:04 +09:00
ToruNiina
31debcb8aa 🔀 Merge branch 'master' into recursive-find 2019-06-07 19:02:20 +09:00
ToruNiina
2afa0ff0c3 doc: add find(value, key1, key2, ...) to README 2019-06-07 19:01:46 +09:00
ToruNiina
46047c48bf doc: add note about is|as_float to README 2019-06-07 13:40:21 +09:00
ToruNiina
897aecf5d4 test: avoid deprecated functions in the test codes 2019-06-07 13:32:02 +09:00
ToruNiina
7db8388d17 fix: avoid deprecated stuff in the internal code 2019-06-07 13:27:10 +09:00
ToruNiina
62c993e096 feat: add as|is_floating and deprecate as|is_float
to make the function names consistent with snake_case_typenames
2019-06-07 00:10:12 +09:00
ToruNiina
014d882f8f feat: enable to find value by recursive search 2019-06-07 00:06:14 +09:00
ToruNiina
e781545c53 feat(WIP): diable test for comments once
because the interfaces would be changed a lot.
2019-06-06 22:34:08 +09:00
ToruNiina
a8b5fef827 feat(WIP): add workaround to make literal compiles 2019-06-06 22:32:51 +09:00
ToruNiina
7258c52334 feat: enable to edit comments through memfun 2019-06-03 22:17:10 +09:00
ToruNiina
407d9223f6 feat: 💥 is_float -> is_floating 2019-06-03 22:01:47 +09:00
ToruNiina
53efaed179 test: update interfaces of parse_* and value 2019-06-03 22:01:16 +09:00
ToruNiina
d7c5606dcf fix: update as_float -> floating 2019-06-03 21:46:48 +09:00
ToruNiina
761718b3b9 test: update retval of parse and related get/find 2019-06-03 21:44:47 +09:00
ToruNiina
ae2bafa907 fix: correct SFINAE conditions and types 2019-06-03 21:44:11 +09:00
ToruNiina
f19b3822bb feat: 💥 change as_float -> as_floating 2019-06-03 21:43:35 +09:00
ToruNiina
2cbb93d86e fix: #65 Merge branch 'hotfix' 2019-06-03 21:27:25 +09:00
ToruNiina
a19b94511b fix: add space between operator"" and _toml
In C++11, it is required.
2019-06-03 20:58:35 +09:00
ToruNiina
cf1114b47b test: update typenames from Camel to snake 2019-06-02 22:13:36 +09:00
ToruNiina
ad3c1950f2 test: use find instead of get<T>(v.at("")) 2019-06-02 22:12:52 +09:00
ToruNiina
296ba060ef test: update typename from CamelCase to snake_case 2019-06-02 22:11:37 +09:00
ToruNiina
fe8a909213 fix: correctly put references 2019-06-02 22:09:26 +09:00
ToruNiina
c313e1382c test: update test for multiple translation units 2019-06-02 22:00:56 +09:00
ToruNiina
5fe166e375 fix: update value_t::* names in serializer
Although currently serializer does not support basic_value, it compiles.
2019-06-02 21:51:37 +09:00
ToruNiina
319365f86b feat: update types in format_error 2019-06-02 21:50:27 +09:00
ToruNiina
89f0ace6ee fix: initialize comment container correctly 2019-06-02 21:50:01 +09:00
ToruNiina
2e34035e7a feat: 💥 update types and retval of parser
- change return value from toml::table to toml::value
- enable to change container types and comment policy by template
2019-06-02 21:47:57 +09:00
ToruNiina
7d34436535 test: update value_t::* names in the test code 2019-06-02 21:36:09 +09:00
ToruNiina
8456186eac fix: remove inclusion of removed file 2019-06-02 21:34:57 +09:00
ToruNiina
e094d6e85a refactor: move type alias from get to trait 2019-06-02 20:43:08 +09:00
ToruNiina
4664f91517 feat: remove unused meta-function alias 2019-06-02 20:40:44 +09:00
ToruNiina
c0b6ca762a feat: 💥 drop from_toml support 2019-06-02 19:27:03 +09:00
ToruNiina
5ef9890d0c feat: update find_or for basic_value 2019-06-02 19:22:17 +09:00
ToruNiina
bda337b51f feat: support conversion between basic_values 2019-06-02 19:09:56 +09:00
ToruNiina
6569c26e1b feat: make SFINAE condition strict 2019-06-02 19:04:32 +09:00
ToruNiina
6d17d5f60f feat: update expect for basic_value 2019-06-02 19:02:25 +09:00
ToruNiina
c00eeb18ef feat: add meta function that detects toml::basic_value 2019-06-02 19:02:01 +09:00
ToruNiina
3ce1aa31f3 feat: update get_or for basic_value 2019-06-02 18:55:02 +09:00
ToruNiina
cf28c3fb95 feat: update toml::find for basic_value 2019-06-02 18:36:49 +09:00
ToruNiina
6de494598a fix: remove unused argument to suppress warnings 2019-06-02 18:32:47 +09:00
ToruNiina
b06ae03deb feat: update toml::get<T> for basic_value 2019-06-02 17:53:08 +09:00
ToruNiina
725d915ba9 feat(WIP): update toml::get 2019-06-02 17:31:49 +09:00
ToruNiina
e1556183d1 refactor: remove unused include files 2019-06-02 17:12:01 +09:00
ToruNiina
9676499ab5 refactor: move file inclusion to correct position 2019-06-02 15:29:34 +09:00
ToruNiina
5792411d5e feat: add default template argument to basic_value 2019-06-02 15:15:43 +09:00
ToruNiina
44184026f9 feat: enable to convert different basic_values 2019-06-02 00:13:12 +09:00
ToruNiina
898423166f feat: enable to convert preserve/discard comments 2019-06-02 00:02:31 +09:00
ToruNiina
f9b5166c09 refactor: move default value types to value.hpp 2019-06-01 23:58:17 +09:00
ToruNiina
5c5d8b686a feat: introduce basic_value
it is capable to change comment policy, backend container of an array
and a table.
2019-06-01 20:18:57 +09:00
ToruNiina
5c3c1bd0e7 feat: add missing default array/table type 2019-06-01 20:18:15 +09:00
ToruNiina
696e5bb66f feat: extend has_from_toml_method to be generic 2019-06-01 20:16:59 +09:00
ToruNiina
65540fbb5c fix: typos 2019-06-01 19:47:10 +09:00
ToruNiina
351320491d fix: fix has_from_toml using basic_value 2019-06-01 19:46:20 +09:00
ToruNiina
d30700517d fix: add missing include file 2019-06-01 19:43:35 +09:00
ToruNiina
14ad8d0556 fix: fix typos and invalid names 2019-06-01 19:43:15 +09:00
ToruNiina
f04c97b587 refactor: simplify format_underline a bit 2019-06-01 19:06:08 +09:00
ToruNiina
b8d3038d38 feat: add meta function to detect conversions 2019-06-01 16:03:26 +09:00
ToruNiina
eaa3604dce refactor: introduce value_t_constant
as an alias for integral_constant
2019-06-01 16:01:48 +09:00
ToruNiina
8acc348106 feat: 💥 change interface around types
- change value_t::typename from CamelCase to snake_case.
- drop CamelCase typename supports.
The changes are introduced to make the interfaces uniform. For some
(historical) reasons, toml11 has both CamelCase names and snake_case
names for types. Additionally, since `float` is a keyword, snake_case
names uses `floating` to avoid collision and CamelCase name uses `Float`
because toml official calls it `Float`. This is too confusing.
Since it is a major upgrade, I think it is a big chance to make them
uniform.
2019-06-01 13:33:57 +09:00
ToruNiina
2567f2a787 feat: add source_location for error message generation. 2019-06-01 13:25:02 +09:00
ToruNiina
84b5749c6b feat: implement comment containers 2019-06-01 13:24:54 +09:00
ToruNiina
70d0049511 refactor: move some meta-funcs to traits.hpp 2019-06-01 12:35:40 +09:00
ToruNiina
717f5929c2 feat: use detail::none_t instead of char
Although the error value from combinators currently does not have any
information, it can have an information because it is a char value. It
is better to use no-information-type explicitly to make it clear that
it does not have any information. So I added none_t in toml::detai and
use it in combinators and parsers as an error value from combinators.
2019-05-31 17:07:52 +09:00
ToruNiina
81abb6c9d7 perf: remove err-msg from combinator
Generate error message in `parse_something()`, not in `lex_something`.
Since the error message generated by `lex_something` is too difficult to
read for humans, I've disabled the error message generation for the sake
of efficiency (it takes time to generate error message that will never
be read). I think now the error message generation itself safely can be
removed from combinators. At this stage, `lex_something` does not need
to return `result<T, E>` because all the error type would be discarded.
Now it is turned out that returing `optional<T>` from lex_* is enough.
Maybe later I would change the return type itself, but currently I
changed the error type from std::string to char because implementing
optional takes time and effort. It makes the parsing process a bit
faster.
2019-05-30 20:08:37 +09:00
ToruNiina
8bba3c8a14 refactor: use literal instead of empty string
so far, the error value of the lexer is just ignored because they are
not readable (results from all the nested combinator are concatenated,
so they are too redundant). those ones are replaced by a simple literal.
2019-05-30 19:33:25 +09:00
ToruNiina
b13e727b90 refactor: remove unused func, combinator::pattern
because it is not human-readable (too long and redundant)
2019-05-30 18:05:47 +09:00
ToruNiina
d352c9e66f perf: suppress unused error message generation 2019-05-30 17:47:06 +09:00
ToruNiina
c0aaba06d0 Merge branch 'refactoring' 2019-05-30 16:25:10 +09:00
ToruNiina
1633268d57 refactor: use snake_case typename only 2019-05-30 14:39:15 +09:00
ToruNiina
3bf1c2b820 Merge branch 'refactoring' to master 2019-05-30 00:18:07 +09:00
ToruNiina
4dbd2cb9fe refactor: use as_* to avoid needless checking 2019-05-29 21:22:32 +09:00
ToruNiina
65124a8d2e refactor: use is_something instead of is(...)
to reduce the code size a bit
2019-05-29 21:20:22 +09:00
ToruNiina
1b78f161f5 refactor: use is_something/as_something in parser
this reduces the size of the code. And also it skips needless
double-checking, so we can expect it makes parsing a bit faster.
2019-05-29 21:18:17 +09:00
ToruNiina
0ce259ada0 refactor: split throw_bad_cast from value::cast 2019-05-29 21:06:25 +09:00
ToruNiina
74da49f87f refactor: move switch_cast from inside of value
use as_something() instead of it. To realize this, the implementation of
as_something() is also changed. Now as_something does not depends on
`cast`. This reduces complexity around casting toml::value to other types.
2019-05-29 20:18:15 +09:00
ToruNiina
d5d697639c docs: add contributor to README 2019-05-10 23:02:23 +09:00
Toru Niina
0b365ca7d3 Merge pull request #63 from chronoxor/master
Fix Visual Studio 2019 warnings in pedantic compilation mode (/W4 /WX)
2019-05-10 22:58:17 +09:00
Ivan Shynkarenka
db6f3d5d11 Fix Visual Studio 2019 warnings in pedantic compilation mode (/W4 /WX) 2019-05-10 14:58:22 +03:00
ToruNiina
87be890e07 feat: remove deprecated functions 2019-04-28 15:59:09 +09:00
Toru Niina
d72dc706d0 Merge pull request #61 from ToruNiina/as-something
feat: add as_something functions for convenience
2019-04-28 15:02:19 +09:00
ToruNiina
4cbbcd8f62 Merge branch 'master' into as-something 2019-04-27 19:04:44 +09:00
Toru Niina
a2631ecacb Merge pull request #60 from ToruNiina/string-view
support std::string_view
2019-04-27 18:33:59 +09:00
ToruNiina
4bcc5e8375 Merge branch 'master' into as-something 2019-04-27 17:42:12 +09:00
Toru Niina
90f84000ba Merge pull request #59 from ToruNiina/preserve-comments
Preserve comments; related to #48
2019-04-27 17:40:26 +09:00
ToruNiina
20a13754a7 chore: update README for as_* functions 2019-04-27 16:50:44 +09:00
ToruNiina
aa7b9a3965 refactor: rename as_floating -> as_float
Actually, since `floating` is used for toml::types, `as_floating`
seems to be clearer. But currently `is_*` functions uses `float`,
not `floating`, so `as_float` is chosen for the consistency.
In a future release, possibly v3, those names may need to be
re-considered for clarity.
2019-04-27 16:45:25 +09:00
ToruNiina
84ac1d10f3 test: add test for toml::value::as_something 2019-04-27 16:22:50 +09:00
ToruNiina
0d623856a7 feat: add value::as_something() for convenience 2019-04-27 16:22:23 +09:00
ToruNiina
ec0d4e4e8c chore: update README for comments 2019-04-27 15:50:54 +09:00
ToruNiina
80ea736b3f ci: try to update standard library on travis 2019-04-27 14:46:40 +09:00
ToruNiina
ebaa5dfb51 chore: fix build settings for OS X on Travis 2019-04-26 21:10:29 +09:00
ToruNiina
f3bdf083fe fix: fix typo in test code for string_view 2019-04-26 16:51:23 +09:00
ToruNiina
1ce54a9cf9 chore: add auto test with c++17 + latest compilers 2019-04-26 16:35:03 +09:00
ToruNiina
6383a93ce7 chore: check CXX_STANDARD exists or not 2019-04-26 16:33:48 +09:00
ToruNiina
01aa2ef5b2 feat: add ctor to value to init with string_view 2019-04-26 16:33:09 +09:00
ToruNiina
819351f5a4 test: add test for init toml::value by string_view 2019-04-26 16:32:23 +09:00
ToruNiina
2967cebfb3 test: add test to get a toml::value as string_view 2019-04-26 16:31:59 +09:00
ToruNiina
32e9a2c1c7 test: add test for comments in an array 2019-04-26 15:35:41 +09:00
ToruNiina
8e0a40a1aa test: add test for getting comments 2019-04-25 22:34:12 +09:00
ToruNiina
e460826084 feat: enable to get a comment related to a value
- comment_before(): get comments just before a value.
- comment_inline(): get a comment in the same line as a value.
- comment(): get comment_before() + comment_inline().
2019-04-25 22:32:39 +09:00
ToruNiina
aa3445f38c feat: add functions to get comments around region 2019-04-25 22:32:18 +09:00
ToruNiina
408b7bf35e Merge branch 'master' into string-view 2019-04-23 23:32:08 +09:00
ToruNiina
6185dfee14 chore: fix typo in README 2019-04-23 23:31:37 +09:00
ToruNiina
37aa2739a5 chore: add description about string_view to README 2019-04-23 23:27:53 +09:00
ToruNiina
d061c33a16 feat: enable toml::get with std::string_view 2019-04-23 23:24:23 +09:00
ToruNiina
0c7d2d07d4 feat: do not consider string_view as a container
it is a kind of string.
2019-04-23 23:23:57 +09:00
ToruNiina
62cf4373bd feat: conversion toml::string <-> string_view 2019-04-22 23:18:05 +09:00
Toru Niina
a74ad23514 Merge pull request #58 from ToruNiina/improve-err-msg-literal
Improve error message from toml literal
2019-04-22 20:50:11 +09:00
ToruNiina
2d9b4992ec fix: restrict length of underline by size of line
in some cases, `region` contains several lines and `region::size`
returns the whole size that is a sum of lengthes of all the lines.
To avoid too long underlines, restrict the length of underline by
the length of the line that is shown in the message.
2019-04-21 16:38:08 +09:00
ToruNiina
82e8c1e68b fix: skip first ws/newlines in toml literal
when ""_toml literal is used with C++11 raw-string literal,
it normally starts with newline like the following.
```cpp
const auto v = u8R"(
    [table]
    key = "value"
    )"_toml;
```
With this, the error message shows the first empty line that starts just
after `u8R"(` and thus the error message shows nothing. To avoid this,
skip the first empty lines and whitespaces in literal.
2019-04-21 16:31:24 +09:00
ToruNiina
46be054ce9 fix: improve err msg for multiline inline table
show "missing curly brace" instead of "missing table key-value separator"
2019-04-19 13:22:13 +09:00
ToruNiina
789d784769 chore: update README; about literals 2019-04-19 13:18:35 +09:00
ToruNiina
81deb8efde chore: update README 2019-04-19 12:41:24 +09:00
Toru Niina
072dccd05d Merge pull request #56 from ToruNiina/optimization
Optimization
2019-04-19 01:30:29 +09:00
ToruNiina
637c99d637 refactor: generate error message in parser 2019-04-18 15:09:58 +09:00
ToruNiina
0f48852730 perf: check value type before parsing
to avoid needless error message generation
2019-04-18 14:26:27 +09:00
ToruNiina
0499b2907d Merge branch 'master' into optimization 2019-04-18 14:10:08 +09:00
ToruNiina
61e69c9251 fix: count line number from 1, not 0 2019-04-18 13:56:19 +09:00
ToruNiina
4a560ea1e5 fix: show correct error message 2019-04-18 00:04:33 +09:00
ToruNiina
c5b6ee6f81 feat: add yet another constructor to value
to make implementation of parse_value easier
2019-04-17 23:43:42 +09:00
ToruNiina
1a7bf63622 Merge branch 'master' into optimization 2019-04-17 14:58:28 +09:00
Toru Niina
8847cdc0a9 Merge pull request #55 from wbenny/master
fix /W4 warnings on MSVC
2019-04-17 13:16:19 +09:00
ToruNiina
c82e76a111 perf: check string type before parsing it
to avoid unncessary error message generation, check the first some
characters before parsing it. It makes parsing process faster and
is also helpful to generate more accurate error messages.
2019-04-16 21:47:24 +09:00
ToruNiina
4db486d76d perf: check integer prefix before trying to parse
all the parsers generate error messages and error message generation is
not a lightweight task. It concatenates a lot of strings, it formats
many values, etc. To avoid useless error-message generation, first check
which prefix is used and then parse special integers. Additionally, by
checking that, the quality of the error message can be improved (later).
2019-04-16 21:37:12 +09:00
ToruNiina
91966a6917 perf: do not use concat_string if it is not needed
At the earlier stage of the development, I thought that it is useful if
lexer-combinators generate error messages, because by doing this,
parser would not need to generate an error message. But now it turned
out that to show an appropriate error message, parser need to generate
according to the context. And almost all the messages from lexer are
discarded. So I added another parameter to lexer-combinator to suppress
error message generation. In the future, we may want to remove messages
completely from lexers, but currently I will keep it. Removing those
unused message generation makes the parsing process faster.
2019-04-16 21:09:59 +09:00
ToruNiina
b3917aaadf refactor: use snprintf to show char in hex
instead of std::ostringstream.
2019-04-16 20:54:29 +09:00
Petr Benes
ba307003c4 fix /W4 warnings on MSVC 2019-04-16 13:25:45 +02:00
Toru Niina
21fd1271d9 Merge pull request #54 from ToruNiina/hotfix
fix: resolve ambiguity in the `""_toml` literal
2019-04-15 13:34:35 +09:00
ToruNiina
f9ab7d6f56 chore: add note about literals to README.md 2019-04-14 20:08:23 +09:00
ToruNiina
0a3a41a708 test: add test for literals for difficult case 2019-04-14 20:06:11 +09:00
ToruNiina
6c2a536fa5 fix: check literal has a table or an array first
The literal like this `"[[table]]"_toml` caused a syntax error. It is
because the literal parser first check that it might be a bare value
without a key, and parse_array directory throws syntax_error. This
change makes the parser first check a literal is a name of table, and
then parse the content.
2019-04-14 19:48:43 +09:00
Toru Niina
26eced3640 Merge pull request #52 from ToruNiina/speedup-for-large-files
Speedup parsing large files
2019-04-13 16:11:21 +09:00
ToruNiina
6f950c9ec8 perf: cache current line number in location
`location::line_num()` function used to be implemented by using
`std::count`, so each time the parser encounters a type mismatch,
`std::count` was called with almost whole file. It decelerates the
parsing process too much, so I decided to add `line_number_` member
variable to `location` and add `advance/retrace/reset` to `location`
in order to modify the position that is pointed.
2019-04-12 18:32:46 +09:00
ToruNiina
ea13e40889 feat: add static_assert for location/range
to check the container is randomly-accessible
2019-04-12 18:00:53 +09:00
ToruNiina
595fb1aef3 refactor: remove unused function parameter names 2019-04-06 19:39:13 +09:00
ToruNiina
18986978fb chore: add short example code to README 2019-03-24 21:30:27 +09:00
72 changed files with 14807 additions and 4498 deletions

View File

@@ -2,10 +2,8 @@ version: 2.1
jobs:
test_suite:
environment:
- GOPATH: /home/circleci/go
docker:
- image: circleci/golang:1.9
- image: cimg/go:1.16
steps:
- checkout
- run:
@@ -13,8 +11,38 @@ jobs:
g++ --version
cd tests/
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test
go get github.com/BurntSushi/toml-test
$GOPATH/bin/toml-test ./check_toml_test
export PATH=$(pwd):${PATH}
git clone https://github.com/BurntSushi/toml-test.git
cd toml-test/
go install -v ./cmd/toml-test
cd -
toml-test check_toml_test
# go clean -modcache
# go get github.com/BurntSushi/toml-test/cmd/toml-test
# $GOPATH/bin/toml-test ./check_toml_test
test_serialization:
docker:
- image: circleci/buildpack-deps:bionic
steps:
- checkout
- run:
command: |
g++ --version
cd tests/
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -I../ check_serialization.cpp -o check_serialization
git clone https://github.com/BurntSushi/toml-test.git
cp check_serialization toml-test/tests/valid
cd toml-test/tests/valid
for f in $(ls ./*.toml);
do echo "==> ${f}";
cat ${f};
echo "---------------------------------------";
./check_serialization ${f};
if [ $? -ne 0 ] ; then
exit 1
fi
echo "=======================================";
done
output_result:
docker:
- image: circleci/buildpack-deps:bionic
@@ -24,7 +52,7 @@ jobs:
command: |
g++ --version
cd tests/
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check.cpp -o check
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -I../ check.cpp -o check
git clone https://github.com/BurntSushi/toml-test.git
cp check toml-test/tests/invalid
cp check toml-test/tests/valid
@@ -56,4 +84,5 @@ workflows:
test:
jobs:
- test_suite
- test_serialization
- output_result

149
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,149 @@
name: build
on: [push, pull_request]
jobs:
build-linux-gcc:
runs-on: Ubuntu-18.04
strategy:
matrix:
# g++-4.8 and 4.9 are tested on Travis.CI.
compiler: ['g++-11', 'g++-10', 'g++-9', 'g++-8', 'g++-7', 'g++-6', 'g++-5']
standard: ['11', '14', '17', '20']
exclude:
- {compiler: 'g++-5', standard: '17'}
- {compiler: 'g++-6', standard: '17'}
- {compiler: 'g++-5', standard: '20'}
- {compiler: 'g++-6', standard: '20'}
- {compiler: 'g++-7', standard: '20'}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Install
run: |
sudo apt-add-repository ppa:mhier/libboost-latest
sudo apt-get update
sudo apt-get install boost1.70
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install ${{ matrix.compiler }}
- name: Configure
run: |
mkdir build && cd build
if [[ "${{ matrix.compiler }}" == "g++-8" && ( "${{ matrix.standard }}" == "17" || "${{ matrix.standard }}" == "20" ) ]] ; then
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_REQUIRE_FILESYSTEM_LIBRARY=ON
else
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }}
fi
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-linux-clang:
runs-on: Ubuntu-18.04
strategy:
matrix:
compiler: ['10', '9', '8', '7', '6.0', '5.0', '4.0', '3.9']
standard: ['11', '14', '17', '20']
exclude:
- {compiler: '3.9', standard: '17'}
- {compiler: '4.0', standard: '17'}
- {compiler: '5.0', standard: '17'}
- {compiler: '3.9', standard: '20'}
- {compiler: '4.0', standard: '20'}
- {compiler: '5.0', standard: '20'}
- {compiler: '6.0', standard: '20'}
- {compiler: '7', standard: '20'}
- {compiler: '8', standard: '20'}
- {compiler: '9', standard: '20'}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Install
run: |
sudo apt-add-repository ppa:mhier/libboost-latest
sudo apt-get update
sudo apt-get install boost1.70
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install clang-${{ matrix.compiler }}
- name: Configure
run: |
mkdir build && cd build
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_C_COMPILER=clang-${{ matrix.compiler }} -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }}
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-osx:
runs-on: macos-10.15
strategy:
matrix:
standard: ['11', '14', '17', '20']
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Install
run: |
brew install boost
- name: Configure
run: |
mkdir build && cd build
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }}
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-windows-msvc:
runs-on: windows-2019
strategy:
matrix:
standard: ['11', '14', '17', '20']
config: ['Release', 'Debug']
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Install
run: |
(New-Object System.Net.WebClient).DownloadFile("https://github.com/actions/boost-versions/releases/download/1.72.0-20200608.4/boost-1.72.0-win32-msvc14.2-x86_64.tar.gz", "$env:TEMP\\boost.tar.gz")
7z.exe x "$env:TEMP\\boost.tar.gz" -o"$env:TEMP\\boostArchive" -y | Out-Null
7z.exe x "$env:TEMP\\boostArchive" -o"$env:TEMP\\boost" -y | Out-Null
Push-Location -Path "$env:TEMP\\boost"
Invoke-Expression .\\setup.ps1
- uses: ilammy/msvc-dev-cmd@v1
- name: Configure
shell: cmd
run: |
file --mime-encoding tests/test_literals.cpp
mkdir build
cd build
cmake ../ -G "NMake Makefiles" -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DBoost_NO_BOOST_CMAKE=ON -DBOOST_ROOT="C:\\hostedtoolcache\\windows\\Boost\\1.72.0\\x86_64"
- name: Build
working-directory: ./build
run: |
cmake --build . --config "${{ matrix.config }}"
- name: Test
working-directory: ./build
run: |
./tests/test_literals --log_level=all
file --mime-encoding tests/toml/tests/example.toml
file --mime-encoding tests/toml/tests/fruit.toml
file --mime-encoding tests/toml/tests/hard_example.toml
file --mime-encoding tests/toml/tests/hard_example_unicode.toml
ctest --build-config "${{ matrix.config }}" --output-on-failure

View File

@@ -5,127 +5,333 @@ matrix:
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-5"
env: COMPILER="g++-4.8" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-4.8
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-4.9" CXX_STANDARD=11
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-4.9
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-5" CXX_STANDARD=11
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-5
- libboost-all-dev
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-6"
env: COMPILER="g++-6" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-6
- libboost-all-dev
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-7"
env: COMPILER="g++-7" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-7
- libboost-all-dev
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8"
env: COMPILER="g++-8" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- libboost-all-dev
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-3.7"
compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=11 TOML_HEAD=ON
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- clang-3.7
- libboost-all-dev
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-4.0"
compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=14
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=17 REQUIRE_FILESYSTEM_LIBRARY=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=17 TOML_HEAD=ON REQUIRE_FILESYSTEM_LIBRARY=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-3.9" CXX_STANDARD=11
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-3.9
packages:
- g++-8
- clang-3.9
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-4.0" CXX_STANDARD=11
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-4.0
packages:
- g++-8
- clang-4.0
- libboost-all-dev
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-5.0"
env: COMPILER="clang++-5.0" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-5.0
packages:
- g++-8
- clang-5.0
- libboost-all-dev
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-6.0"
env: COMPILER="clang++-6.0" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-6.0
packages:
- g++-8
- clang-6.0
- libboost-all-dev
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-7"
env: COMPILER="clang++-7" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-7
packages:
- g++-8
- clang-7
- libboost-all-dev
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8"
env: COMPILER="clang++-8" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- g++-8
- clang-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=11 TOML_HEAD=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- g++-8
- clang-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=14
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- clang-8
- libboost-all-dev
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=17 REQUIRE_FILESYSTEM_LIBRARY=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- clang-8
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=17 TOML_HEAD=ON REQUIRE_FILESYSTEM_LIBRARY=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- clang-8
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=11 WITH_ASAN=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- clang-8
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=11 WITH_UBSAN=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- clang-8
- g++-8
- boost1.70
- os: osx
language: cpp
compiler: clang
script:
- |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
mkdir -p cmake
travis_retry wget "https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.tar.gz"
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
fi
- |
if [[ "${CXX_STANDARD}" == "" ]]; then
export CXX_STANDARD="11"
fi
- |
if [[ "${TOML_HEAD}" != "ON" ]]; then
export TOML_HEAD="OFF"
fi
- echo "TOML_HEAD = ${TOML_HEAD}"
- |
if [[ "${WITH_ASAN}" != "ON" ]]; then
export WITH_ASAN="OFF"
fi
- echo "WITH_ASAN = ${WITH_ASAN}"
- |
if [[ "${WITH_UBSAN}" != "ON" ]]; then
export WITH_UBSAN="OFF"
fi
- echo "WITH_UBSAN = ${WITH_UBSAN}"
- echo "REQUIRE_FILESYSTEM_LIBRARY = ${REQUIRE_FILESYSTEM_LIBRARY}"
- |
if [[ "${REQUIRE_FILESYSTEM_LIBRARY}" != "ON" ]]; then
export REQUIRE_FILESYSTEM_LIBRARY="OFF"
fi
- echo "REQUIRE_FILESYSTEM_LIBRARY = ${REQUIRE_FILESYSTEM_LIBRARY}"
- cmake --version
- mkdir build
- cd build
- git clone https://github.com/toml-lang/toml.git
- cmake -DCMAKE_CXX_COMPILER=$COMPILER ..
- echo "COMPILER = ${COMPILER}"
- echo "CXX_STANDARD = ${CXX_STANDARD}"
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_REQUIRE_FILESYSTEM_LIBRARY=${REQUIRE_FILESYSTEM_LIBRARY} -Dtoml11_BUILD_TEST=ON -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} -Dtoml11_TEST_WITH_ASAN=${WITH_ASAN} -Dtoml11_TEST_WITH_UBSAN=${WITH_UBSAN} ..
- make
- ctest --output-on-failure

View File

@@ -1,11 +1,20 @@
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.1)
enable_testing()
project(toml11)
project(toml11 VERSION 3.7.1)
option(toml11_BUILD_TEST "Build toml tests" OFF)
option(toml11_INSTALL "Install CMake targets during install step." ON)
option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF)
option(toml11_TEST_WITH_UBSAN "use LLVM undefined behavior sanitizer" OFF)
include(CheckCXXCompilerFlag)
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
set(CMAKE_CXX_STANDARD 11)
set(CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Boolean specifying whether compiler specific extensions are requested.")
if(NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11 CACHE STRING "The C++ standard whose features are requested to build all targets.")
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Boolean describing whether the value of CXX_STANDARD is a requirement.")
else()
# Manually check for C++11 compiler flag.
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
@@ -31,5 +40,77 @@ else()
endif()
endif()
include_directories(${PROJECT_SOURCE_DIR})
add_subdirectory(tests)
if(MSVC)
# add_definitions("/Zc:__cplusplus") # define __cplusplus value correctly
add_definitions("/utf-8") # enable to use u8"" literal
if(MSVC_VERSION LESS 1910)
message(STATUS "MSVC < 1910. DEFINE_CONVERSION_NON_INTRUSIVE is disabled")
add_definitions(-DTOML11_WITHOUT_DEFINE_NON_INTRUSIVE)
elseif(MSVC_VERSION LESS 1920)
add_definitions("/experimental:preprocessor") # MSVC 2017
else()
add_definitions("/Zc:preprocessor") # MSVC 2019
endif()
endif()
# Set some common directories
include(GNUInstallDirs)
set(toml11_install_cmake_dir ${CMAKE_INSTALL_LIBDIR}/cmake/toml11)
set(toml11_install_include_dir ${CMAKE_INSTALL_INCLUDEDIR})
set(toml11_config_dir ${CMAKE_CURRENT_BINARY_DIR}/cmake/)
set(toml11_config ${toml11_config_dir}/toml11Config.cmake)
set(toml11_config_version ${toml11_config_dir}/toml11ConfigVersion.cmake)
add_library(toml11 INTERFACE)
target_include_directories(toml11 INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${toml11_install_include_dir}>
)
add_library(toml11::toml11 ALIAS toml11)
# Write config and version config files
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${toml11_config_version}
VERSION ${toml11_VERSION}
COMPATIBILITY SameMajorVersion
)
if (toml11_INSTALL)
configure_package_config_file(
cmake/toml11Config.cmake.in
${toml11_config}
INSTALL_DESTINATION ${toml11_install_cmake_dir}
PATH_VARS toml11_install_cmake_dir
)
# Install config files
install(FILES ${toml11_config} ${toml11_config_version}
DESTINATION ${toml11_install_cmake_dir}
)
# Install header files
install(
FILES toml.hpp
DESTINATION "${toml11_install_include_dir}"
)
install(
DIRECTORY "toml"
DESTINATION "${toml11_install_include_dir}"
FILES_MATCHING PATTERN "*.hpp"
)
# Export targets and install them
install(TARGETS toml11
EXPORT toml11Targets
)
install(EXPORT toml11Targets
FILE toml11Targets.cmake
DESTINATION ${toml11_install_cmake_dir}
NAMESPACE toml11::
)
endif()
if (toml11_BUILD_TEST)
add_subdirectory(tests)
endif ()

1652
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -17,10 +17,9 @@ build_script:
- cd C:\toml11
- mkdir build
- cd build
- git clone https://github.com/toml-lang/toml.git
- file --mime-encoding toml/tests/hard_example_unicode.toml
- cmake -G"%generator%" -DBOOST_ROOT=C:/Libraries/boost_1_63_0 ..
- cmake -G"%generator%" -DBOOST_ROOT=C:/Libraries/boost_1_69_0 -Dtoml11_BUILD_TEST=ON ..
- cmake --build . --config "%configuration%"
- file --mime-encoding tests/toml/tests/hard_example_unicode.toml
test_script:
- ctest --build-config "%configuration%" --timeout 300 --output-on-failure

View File

@@ -0,0 +1,2 @@
@PACKAGE_INIT@
include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake")

View File

@@ -1,5 +1,15 @@
include(ExternalProject)
ExternalProject_Add(toml
SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/toml
GIT_REPOSITORY https://github.com/toml-lang/toml
GIT_TAG v0.5.0
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
set(TEST_NAMES
test_datetime
test_string
test_utility
test_result
test_traits
@@ -21,9 +31,13 @@ set(TEST_NAMES
test_parse_key
test_parse_table_key
test_literals
test_comments
test_get
test_get_related_func
test_from_toml
test_get_or
test_find
test_find_or
test_find_or_recursive
test_expect
test_parse_file
test_serialize_file
test_parse_unicode
@@ -32,16 +46,72 @@ set(TEST_NAMES
test_extended_conversions
)
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
CHECK_CXX_COMPILER_FLAG("-Wextra" COMPILER_SUPPORTS_WEXTRA)
CHECK_CXX_COMPILER_FLAG("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC)
CHECK_CXX_COMPILER_FLAG("-Werror" COMPILER_SUPPORTS_WERROR)
CHECK_CXX_COMPILER_FLAG("-Wsign-conversion" COMPILER_SUPPORTS_WSIGN_CONVERSION)
CHECK_CXX_COMPILER_FLAG("-Wconversion" COMPILER_SUPPORTS_WCONVERSION)
CHECK_CXX_COMPILER_FLAG("-Wduplicated-cond" COMPILER_SUPPORTS_WDUPLICATED_COND)
CHECK_CXX_COMPILER_FLAG("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
CHECK_CXX_COMPILER_FLAG("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
CHECK_CXX_COMPILER_FLAG("-Wuseless-cast" COMPILER_SUPPORTS_WUSELESS_CAST)
CHECK_CXX_COMPILER_FLAG("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
CHECK_CXX_COMPILER_FLAG("-Wrange-loop-analysis" COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
CHECK_CXX_COMPILER_FLAG("-Wundef" COMPILER_SUPPORTS_WUNDEF)
CHECK_CXX_COMPILER_FLAG("-Wshadow" COMPILER_SUPPORTS_WSHADOW)
if(COMPILER_SUPPORTS_WALL)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()
if(COMPILER_SUPPORTS_WEXTRA)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
endif()
if(COMPILER_SUPPORTS_WPEDANTIC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
endif()
if(COMPILER_SUPPORTS_WERROR)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
if(COMPILER_SUPPORTS_WSHADOW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
endif()
if(COMPILER_SUPPORTS_WSIGN_CONVERSION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
endif()
if(COMPILER_SUPPORTS_WCONVERSION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion")
endif()
if(COMPILER_SUPPORTS_WDUPLICATED_COND)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wduplicated-cond")
endif()
if(COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wduplicated-branches")
endif()
if(COMPILER_SUPPORTS_WLOGICAL_OP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wlogical-op")
endif()
if(COMPILER_SUPPORTS_WUSELESS_CAST)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wuseless-cast")
endif()
if(COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
endif()
if(COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wrange-loop-analysis")
endif()
if(COMPILER_SUPPORTS_WUNDEF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wundef")
endif()
option(TOML11_USE_UNRELEASED_TOML_FEATURES
"use features in toml-lang/toml master while testing" OFF)
if(TOML11_USE_UNRELEASED_TOML_FEATURES)
message(STATUS "adding TOML11_USE_UNRELEASED_TOML_FEATURES flag")
add_definitions("-DTOML11_USE_UNRELEASED_TOML_FEATURES")
endif()
# Disable some MSVC warnings
if(MSVC)
@@ -79,17 +149,72 @@ if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4820")
# pragma warning(pop): likely mismatch, popping warning state pushed in different file
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd5031")
# pragma warning(pop): spectre warnings in tests
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd5045")
# pragma warning(pop): spectre warnings in tests
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4265")
endif()
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
add_definitions(-DBOOST_TEST_DYN_LINK)
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
# check which standard library implementation is used. If libstdc++ is used,
# it will fail to compile. It compiles if libc++ is used.
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include <cstddef>
#ifdef __GLIBCXX__
static_assert(false);
#endif
int main() {
return 0;
}" TOML11_WITH_LIBCXX_LIBRARY)
# LLVM 8 requires -lc++fs if compiled with libc++ to use <filesystem>.
# LLVM 9+ does not require any special library.
# GCC 8 requires -lstdc++fs. GCC 9+ does not require it.
#
# Yes, we can check the version of the compiler used in the current build
# directly in CMake. But, in most cases, clang build uses libstdc++ as the
# standard library implementation and it makes the condition complicated.
# In many environment, the default installed C++ compiler is GCC and libstdc++
# is installed along with it. In most build on such an environment, even if we
# chose clang as the C++ compiler, still libstdc++ is used. Checking default
# gcc version makes the condition complicated.
# The purpose of this file is to compile tests. We know the environment on which
# the tests run. We can set this option and, I think, it is easier and better.
option(TOML11_REQUIRE_FILESYSTEM_LIBRARY "need to link -lstdc++fs or -lc++fs" OFF)
foreach(TEST_NAME ${TEST_NAMES})
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
target_include_directories(${TEST_NAME} SYSTEM PRIVATE ${Boost_INCLUDE_DIRS})
# to compile tests with <filesystem>...
if(TOML11_REQUIRE_FILESYSTEM_LIBRARY)
if(TOML11_WITH_LIBCXX_LIBRARY)
target_link_libraries(${TEST_NAME} "c++fs")
else()
target_link_libraries(${TEST_NAME} "stdc++fs")
endif()
endif()
target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if(toml11_TEST_WITH_ASAN)
set_target_properties(${TEST_NAME} PROPERTIES
COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer"
LINK_FLAGS "-fsanitize=address -fno-omit-frame-pointer")
elseif(toml11_TEST_WITH_UBSAN)
set_target_properties(${TEST_NAME} PROPERTIES
COMPILE_FLAGS "-fsanitize=undefined"
LINK_FLAGS "-fsanitize=undefined")
endif()
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Set the PATH to be able to find Boost DLL
if(WIN32)
@@ -100,7 +225,15 @@ foreach(TEST_NAME ${TEST_NAMES})
endif()
endforeach(TEST_NAME)
# this test is to check it compiles. it will not run
add_executable(test_multiple_translation_unit
test_multiple_translation_unit_1.cpp
test_multiple_translation_unit_2.cpp)
target_link_libraries(test_multiple_translation_unit toml11::toml11)
if(WIN32)
add_executable(test_windows test_windows.cpp)
target_link_libraries(test_windows toml11::toml11)
endif()

View File

@@ -0,0 +1,113 @@
#include "toml.hpp"
#include <iostream>
#include <iomanip>
int main(int argc, char **argv)
{
if(argc != 2)
{
std::cerr << "usage: ./check [filename]" << std::endl;
return 1;
}
const std::string filename(argv[1]);
{
const auto data = toml::parse(filename);
{
std::ofstream ofs("tmp.toml");
ofs << std::setprecision(16) << std::setw(80) << data;
}
const auto serialized = toml::parse("tmp.toml");
if(data != serialized)
{
// this is really a ditry hack, but is the easiest way...
// TODO: cleanup by adding comparison function to check if a value is NaN or not
if(filename.substr(filename.size() - 22, 22) == "float-inf-and-nan.toml" &&
std::isnan (toml::find<double>(serialized, "nan")) &&
!std::signbit (toml::find<double>(serialized, "nan")) &&
std::isnan (toml::find<double>(serialized, "nan_plus")) &&
!std::signbit (toml::find<double>(serialized, "nan_plus")) &&
std::isnan (toml::find<double>(serialized, "nan_neg")) &&
std::signbit (toml::find<double>(serialized, "nan_neg")) &&
!std::isnan (toml::find<double>(serialized, "infinity")) &&
!std::isfinite(toml::find<double>(serialized, "infinity")) &&
!std::signbit (toml::find<double>(serialized, "infinity")) &&
!std::isnan (toml::find<double>(serialized, "infinity_plus")) &&
!std::isfinite(toml::find<double>(serialized, "infinity_plus")) &&
!std::signbit (toml::find<double>(serialized, "infinity_plus")) &&
!std::isnan (toml::find<double>(serialized, "infinity_neg")) &&
!std::isfinite(toml::find<double>(serialized, "infinity_neg")) &&
std::signbit (toml::find<double>(serialized, "infinity_neg")))
{
// then it is correctly serialized.
// Note that, the result of (nan == nan) is false. so `data == serialized` is false.
}
else
{
std::cerr << "============================================================\n";
std::cerr << "result (w/o comment) different: " << filename << std::endl;
std::cerr << "------------------------------------------------------------\n";
std::cerr << "# serialized\n";
std::cerr << serialized;
std::cerr << "------------------------------------------------------------\n";
std::cerr << "# data\n";
std::cerr << data;
return 1;
}
}
}
{
const auto data = toml::parse<toml::preserve_comments>(filename);
{
std::ofstream ofs("tmp.toml");
ofs << std::setprecision(16) << std::setw(80) << data;
}
const auto serialized = toml::parse<toml::preserve_comments>("tmp.toml");
if(data != serialized)
{
// this is really a ditry hack, but is the easiest way...
// TODO: cleanup by adding comparison function to check if a value is NaN or not
if(filename.substr(filename.size() - 22, 22) == "float-inf-and-nan.toml" &&
std::isnan (toml::find<double>(serialized, "nan")) &&
!std::signbit (toml::find<double>(serialized, "nan")) &&
std::isnan (toml::find<double>(serialized, "nan_plus")) &&
!std::signbit (toml::find<double>(serialized, "nan_plus")) &&
std::isnan (toml::find<double>(serialized, "nan_neg")) &&
std::signbit (toml::find<double>(serialized, "nan_neg")) &&
!std::isnan (toml::find<double>(serialized, "infinity")) &&
!std::isfinite(toml::find<double>(serialized, "infinity")) &&
!std::signbit (toml::find<double>(serialized, "infinity")) &&
!std::isnan (toml::find<double>(serialized, "infinity_plus")) &&
!std::isfinite(toml::find<double>(serialized, "infinity_plus")) &&
!std::signbit (toml::find<double>(serialized, "infinity_plus")) &&
!std::isnan (toml::find<double>(serialized, "infinity_neg")) &&
!std::isfinite(toml::find<double>(serialized, "infinity_neg")) &&
std::signbit (toml::find<double>(serialized, "infinity_neg")) &&
toml::find(data, "nan").comments() == toml::find(serialized, "nan").comments() &&
toml::find(data, "nan_plus").comments() == toml::find(serialized, "nan_plus").comments() &&
toml::find(data, "nan_neg").comments() == toml::find(serialized, "nan_neg").comments() &&
toml::find(data, "infinity").comments() == toml::find(serialized, "infinity").comments() &&
toml::find(data, "infinity_plus").comments() == toml::find(serialized, "infinity_plus").comments() &&
toml::find(data, "infinity_neg").comments() == toml::find(serialized, "infinity_neg").comments() )
{
// then it is correctly serialized.
// Note that, the result of (nan == nan) is false. so `data == serialized` is false.
}
else
{
std::cerr << "============================================================\n";
std::cerr << "result (w/ comment) different: " << filename << std::endl;
std::cerr << "------------------------------------------------------------\n";
std::cerr << "# serialized\n";
std::cerr << serialized;
std::cerr << "------------------------------------------------------------\n";
std::cerr << "# data\n";
std::cerr << data;
return 1;
}
}
}
return 0;
}

View File

@@ -16,6 +16,14 @@ struct json_serializer
}
void operator()(toml::floating v)
{
if(std::isnan(v) && std::signbit(v))
{
// toml-test does not allow negative NaN represented in "-nan" because
// there are languages that does not distinguish nan and -nan.
// But toml11 keeps sign from input. To resolve this difference,
// we convert -nan to nan here.
v = std::numeric_limits<toml::floating>::quiet_NaN();
}
std::cout << "{\"type\":\"float\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
@@ -24,23 +32,24 @@ struct json_serializer
// since toml11 automatically convert string to multiline string that is
// valid only in TOML, we need to format the string to make it valid in
// JSON.
std::cout << "{\"type\":\"string\",\"value\":\""
<< this->escape_string(v.str) << "\"}";
toml::serializer<toml::value> ser(std::numeric_limits<std::size_t>::max());
std::cout << "{\"type\":\"string\",\"value\":"
<< ser(v.str) << "}";
return ;
}
void operator()(const toml::local_time& v)
{
std::cout << "{\"type\":\"local_time\",\"value\":\"" << toml::value(v) << "\"}";
std::cout << "{\"type\":\"time-local\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::local_date& v)
{
std::cout << "{\"type\":\"local_date\",\"value\":\"" << toml::value(v) << "\"}";
std::cout << "{\"type\":\"date-local\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::local_datetime& v)
{
std::cout << "{\"type\":\"local_datetime\",\"value\":\"" << toml::value(v) << "\"}";
std::cout << "{\"type\":\"datetime-local\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::offset_datetime& v)
@@ -64,7 +73,8 @@ struct json_serializer
}
else
{
std::cout << "{\"type\":\"array\",\"value\":[";
// std::cout << "{\"type\":\"array\",\"value\":[";
std::cout << "[";
bool is_first = true;
for(const auto& elem : v)
{
@@ -72,7 +82,7 @@ struct json_serializer
is_first = false;
toml::visit(*this, elem);
}
std::cout << "]}";
std::cout << "]";
}
return ;
}
@@ -84,34 +94,20 @@ struct json_serializer
{
if(!is_first) {std::cout << ", ";}
is_first = false;
std::cout << toml::format(toml::string(elem.first),
std::numeric_limits<std::size_t>::max());
std::cout << ':';
const auto k = toml::format_key(elem.first);
if(k.at(0) == '"')
{
std::cout << k << ":";
}
else // bare key
{
std::cout << '\"' << k << "\":";
}
toml::visit(*this, elem.second);
}
std::cout << '}';
return ;
}
std::string escape_string(const std::string& s) const
{
std::string retval;
for(const char c : s)
{
switch(c)
{
case '\\': {retval += "\\\\"; break;}
case '\"': {retval += "\\\""; break;}
case '\b': {retval += "\\b"; break;}
case '\t': {retval += "\\t"; break;}
case '\f': {retval += "\\f"; break;}
case '\n': {retval += "\\n"; break;}
case '\r': {retval += "\\r"; break;}
default : {retval += c; break;}
}
}
return retval;
}
};
int main()

551
tests/test_comments.cpp Normal file
View File

@@ -0,0 +1,551 @@
#define BOOST_TEST_MODULE "test_comments"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
BOOST_AUTO_TEST_CASE(test_comment_before)
{
{
const std::string file = R"(
# comment for a.
a = 42
# comment for b.
b = "baz"
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto& a = toml::find(v, "a");
const auto& b = toml::find(v, "b");
BOOST_TEST(a.comments().size() == 1u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(b.comments().size() == 1u);
BOOST_TEST(b.comments().front() == " comment for b.");
}
{
const std::string file = R"(
# comment for a.
# another comment for a.
a = 42
# comment for b.
# also comment for b.
b = "baz"
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto& a = toml::find(v, "a");
const auto& b = toml::find(v, "b");
BOOST_TEST(a.comments().size() == 2u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(a.comments().back() == " another comment for a.");
BOOST_TEST(b.comments().size() == 2u);
BOOST_TEST(b.comments().front() == " comment for b.");
BOOST_TEST(b.comments().back() == " also comment for b.");
}
}
BOOST_AUTO_TEST_CASE(test_comment_inline)
{
{
const std::string file = R"(
a = 42 # comment for a.
b = "baz" # comment for b.
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto& a = toml::find(v, "a");
const auto& b = toml::find(v, "b");
BOOST_TEST(a.comments().size() == 1u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(b.comments().size() == 1u);
BOOST_TEST(b.comments().front() == " comment for b.");
}
{
const std::string file = R"(
a = [
42,
] # comment for a.
b = [
"bar", # this is not a comment for b, but "bar"
] # this is a comment for b.
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto& a = toml::find(v, "a");
const auto& b = toml::find(v, "b");
const auto& b0 = b.as_array().at(0);
BOOST_TEST(a.comments().size() == 1u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(b.comments().size() == 1u);
BOOST_TEST(b.comments().front() == " this is a comment for b.");
BOOST_TEST(b0.comments().size() == 1u);
BOOST_TEST(b0.comments().front() == " this is not a comment for b, but \"bar\"");
}
}
BOOST_AUTO_TEST_CASE(test_comment_both)
{
{
const std::string file = R"(
# comment for a.
a = 42 # inline comment for a.
# comment for b.
b = "baz" # inline comment for b.
# comment for c.
c = [ # this comment will be ignored
# comment for the first element.
10 # this also.
] # another comment for c.
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto& a = toml::find(v, "a");
const auto& b = toml::find(v, "b");
const auto& c = toml::find(v, "c");
const auto& c0 = c.as_array().at(0);
BOOST_TEST(a.comments().size() == 2u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(a.comments().back() == " inline comment for a.");
BOOST_TEST(b.comments().size() == 2u);
BOOST_TEST(b.comments().front() == " comment for b.");
BOOST_TEST(b.comments().back() == " inline comment for b.");
BOOST_TEST(c.comments().size() == 2u);
BOOST_TEST(c.comments().front() == " comment for c.");
BOOST_TEST(c.comments().back() == " another comment for c.");
BOOST_TEST(c0.comments().size() == 2u);
BOOST_TEST(c0.comments().front() == " comment for the first element.");
BOOST_TEST(c0.comments().back() == " this also.");
}
}
BOOST_AUTO_TEST_CASE(test_comments_on_implicit_values)
{
{
const std::string file = R"(
# comment for the first element of array-of-tables.
[[array-of-tables]]
foo = "bar"
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto aot = toml::find(v, "array-of-tables");
const auto elm = aot.at(0);
BOOST_TEST(aot.comments().empty());
BOOST_TEST(elm.comments().size() == 1);
BOOST_TEST(elm.comments().front() == " comment for the first element of array-of-tables.");
}
{
const std::string file = R"(
# comment for the array itself
array-of-tables = [
# comment for the first element of array-of-tables.
{foo = "bar"}
]
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto aot = toml::find(v, "array-of-tables");
const auto elm = aot.at(0);
BOOST_TEST(aot.comments().size() == 1);
BOOST_TEST(aot.comments().front() == " comment for the array itself");
BOOST_TEST(elm.comments().size() == 1);
BOOST_TEST(elm.comments().front() == " comment for the first element of array-of-tables.");
}
}
BOOST_AUTO_TEST_CASE(test_discard_comment)
{
const std::string file = R"(
# comment for a.
a = 42 # inline comment for a.
# comment for b.
b = "baz" # inline comment for b.
# comment for c.
c = [ # this comment will be ignored
# comment for the first element.
10 # this also.
] # another comment for c.
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::discard_comments>(iss);
const auto& a = toml::find(v, "a");
const auto& b = toml::find(v, "b");
const auto& c = toml::find(v, "c");
const auto& c0 = c.as_array().at(0);
BOOST_TEST(a.comments().empty());
BOOST_TEST(b.comments().empty());
BOOST_TEST(c.comments().empty());
BOOST_TEST(c0.comments().empty());
}
BOOST_AUTO_TEST_CASE(test_construct_value_with_comments)
{
using value_type = toml::basic_value<toml::preserve_comments>;
{
const value_type v(true, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_boolean());
BOOST_TEST(v.as_boolean() == true);
}
{
const value_type v(42, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_integer());
BOOST_TEST(v.as_integer() == 42);
}
{
const value_type v(3.14, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_floating());
BOOST_TEST(v.as_floating() == 3.14);
}
{
const value_type v(toml::string("str"), {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_string());
BOOST_TEST(v.as_string() == "str");
}
{
const value_type v(std::string("str"), {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_string());
BOOST_TEST(v.as_string() == "str");
}
{
const value_type v(std::string("str"), toml::string_t::literal,
{"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_string());
BOOST_TEST(v.as_string() == "str");
}
{
const value_type v("str", {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_string());
BOOST_TEST(v.as_string() == "str");
}
{
const value_type v("str", toml::string_t::literal,
{"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_string());
BOOST_TEST(v.as_string() == "str");
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
{
using namespace std::literals::string_view_literals;
const value_type v("str"sv, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_string());
BOOST_TEST(v.as_string() == "str");
}
{
using namespace std::literals::string_view_literals;
const value_type v("str"sv, toml::string_t::literal,
{"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_string());
BOOST_TEST(v.as_string() == "str");
}
#endif
const toml::local_date ld{2019, toml::month_t::Apr, 1};
const toml::local_time lt{12, 30, 45};
const toml::local_datetime ldt{ld, lt};
const toml::offset_datetime odt{ld, lt, toml::time_offset{9, 0}};
{
const value_type v(ld, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_local_date());
BOOST_TEST(v.as_local_date() == ld);
}
{
const value_type v(lt, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_local_time());
BOOST_TEST(v.as_local_time() == lt);
}
{
const toml::local_time three_hours{3,0,0};
const value_type v(std::chrono::hours(3), {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_local_time());
BOOST_TEST(v.as_local_time() == three_hours);
}
{
const value_type v(ldt, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_local_datetime());
BOOST_TEST(v.as_local_datetime() == ldt);
}
{
const value_type v(odt, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_offset_datetime());
BOOST_TEST(v.as_offset_datetime() == odt);
}
{
const auto systp = static_cast<std::chrono::system_clock::time_point>(odt);
const value_type v(systp, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_offset_datetime());
// While the conversion, the information about time offset may change.
const auto systp2 = static_cast<std::chrono::system_clock::time_point>(
v.as_offset_datetime());
const bool result = systp == systp2; // because there is no operator<<
BOOST_TEST(result);
}
{
const typename value_type::array_type a{1,2,3,4,5};
const value_type v(a, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_array());
BOOST_TEST(v.as_array().at(0).is_integer());
BOOST_TEST(v.as_array().at(1).is_integer());
BOOST_TEST(v.as_array().at(2).is_integer());
BOOST_TEST(v.as_array().at(3).is_integer());
BOOST_TEST(v.as_array().at(4).is_integer());
BOOST_TEST(v.as_array().at(0).as_integer() == 1);
BOOST_TEST(v.as_array().at(1).as_integer() == 2);
BOOST_TEST(v.as_array().at(2).as_integer() == 3);
BOOST_TEST(v.as_array().at(3).as_integer() == 4);
BOOST_TEST(v.as_array().at(4).as_integer() == 5);
}
{
const std::initializer_list<int> a = {1,2,3,4,5};
const value_type v(a, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_array());
BOOST_TEST(v.as_array().at(0).is_integer());
BOOST_TEST(v.as_array().at(1).is_integer());
BOOST_TEST(v.as_array().at(2).is_integer());
BOOST_TEST(v.as_array().at(3).is_integer());
BOOST_TEST(v.as_array().at(4).is_integer());
BOOST_TEST(v.as_array().at(0).as_integer() == 1);
BOOST_TEST(v.as_array().at(1).as_integer() == 2);
BOOST_TEST(v.as_array().at(2).as_integer() == 3);
BOOST_TEST(v.as_array().at(3).as_integer() == 4);
BOOST_TEST(v.as_array().at(4).as_integer() == 5);
}
{
const std::vector<int> a = {1,2,3,4,5};
const value_type v(a, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_array());
BOOST_TEST(v.as_array().at(0).is_integer());
BOOST_TEST(v.as_array().at(1).is_integer());
BOOST_TEST(v.as_array().at(2).is_integer());
BOOST_TEST(v.as_array().at(3).is_integer());
BOOST_TEST(v.as_array().at(4).is_integer());
BOOST_TEST(v.as_array().at(0).as_integer() == 1);
BOOST_TEST(v.as_array().at(1).as_integer() == 2);
BOOST_TEST(v.as_array().at(2).as_integer() == 3);
BOOST_TEST(v.as_array().at(3).as_integer() == 4);
BOOST_TEST(v.as_array().at(4).as_integer() == 5);
}
{
const typename value_type::table_type t{
{"key1", 42}, {"key2", "foobar"}
};
const value_type v(t, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_table());
BOOST_TEST(v.as_table().at("key1").is_integer());
BOOST_TEST(v.as_table().at("key1").as_integer() == 42);
BOOST_TEST(v.as_table().at("key2").is_string());
BOOST_TEST(v.as_table().at("key2").as_string() == "foobar");
}
{
const std::initializer_list<std::pair<std::string, value_type>> t{
{"key1", 42}, {"key2", "foobar"}
};
const value_type v(t, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_table());
BOOST_TEST(v.as_table().at("key1").is_integer());
BOOST_TEST(v.as_table().at("key1").as_integer() == 42);
BOOST_TEST(v.as_table().at("key2").is_string());
BOOST_TEST(v.as_table().at("key2").as_string() == "foobar");
}
{
const std::map<std::string, value_type> t{
{"key1", 42}, {"key2", "foobar"}
};
const value_type v(t, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_table());
BOOST_TEST(v.as_table().at("key1").is_integer());
BOOST_TEST(v.as_table().at("key1").as_integer() == 42);
BOOST_TEST(v.as_table().at("key2").is_string());
BOOST_TEST(v.as_table().at("key2").as_string() == "foobar");
}
}
BOOST_AUTO_TEST_CASE(test_overwrite_comments)
{
using value_type = toml::basic_value<toml::preserve_comments>;
{
const value_type v(42, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_integer());
BOOST_TEST(v.as_integer() == 42);
const value_type u(v, {"comment3", "comment4"});
BOOST_TEST(u.comments().size() == 2u);
BOOST_TEST(u.comments().at(0) == "comment3");
BOOST_TEST(u.comments().at(1) == "comment4");
BOOST_TEST(u.is_integer());
BOOST_TEST(u.as_integer() == 42);
}
{
const value_type v(42, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_integer());
BOOST_TEST(v.as_integer() == 42);
const value_type u(v);
BOOST_TEST(u.comments().size() == 2u);
BOOST_TEST(u.comments().at(0) == "comment1");
BOOST_TEST(u.comments().at(1) == "comment2");
BOOST_TEST(u.is_integer());
BOOST_TEST(u.as_integer() == 42);
}
{
const value_type v(42, {"comment1", "comment2"});
BOOST_TEST(v.comments().size() == 2u);
BOOST_TEST(v.comments().at(0) == "comment1");
BOOST_TEST(v.comments().at(1) == "comment2");
BOOST_TEST(v.is_integer());
BOOST_TEST(v.as_integer() == 42);
const value_type u(v, {});
BOOST_TEST(u.comments().size() == 0u);
BOOST_TEST(u.is_integer());
BOOST_TEST(u.as_integer() == 42);
}
}
BOOST_AUTO_TEST_CASE(test_output_comments)
{
using value_type = toml::basic_value<toml::preserve_comments>;
{
const value_type v(42, {"comment1", "comment2"});
std::ostringstream oss;
oss << v.comments();
std::ostringstream ref;
ref << "#comment1\n";
ref << "#comment2\n";
BOOST_TEST(oss.str() == ref.str());
}
{
const value_type v(42, {"comment1", "comment2"});
std::ostringstream oss;
// If v is not a table, toml11 assumes that user is writing something
// like the following.
oss << "answer = " << v;
BOOST_TEST(oss.str() == "answer = 42 #comment1comment2");
}
{
const value_type v(42, {"comment1", "comment2"});
std::ostringstream oss;
// If v is not a table, toml11 assumes that user is writing something
// like the following.
oss << toml::nocomment << "answer = " << v;
BOOST_TEST(oss.str() == "answer = 42");
}
{
const value_type v(42, {"comment1", "comment2"});
std::ostringstream oss;
// If v is not a table, toml11 assumes that user is writing something
// like the following.
oss << toml::nocomment << toml::showcomment << "answer = " << v;
BOOST_TEST(oss.str() == "answer = 42 #comment1comment2");
}
}

View File

@@ -11,47 +11,47 @@ BOOST_AUTO_TEST_CASE(test_local_date)
{
const toml::local_date date(2018, toml::month_t::Jan, 1);
const toml::local_date date1(date);
BOOST_CHECK_EQUAL(date, date1);
BOOST_TEST(date == date1);
const std::chrono::system_clock::time_point tp(date);
const toml::local_date date2(tp);
BOOST_CHECK_EQUAL(date, date2);
BOOST_TEST(date == date2);
const toml::local_date date3(2017, toml::month_t::Dec, 31);
BOOST_CHECK(date > date3);
BOOST_TEST(date > date3);
std::ostringstream oss;
oss << date;
BOOST_CHECK_EQUAL(oss.str(), std::string("2018-01-01"));
BOOST_TEST(oss.str() == std::string("2018-01-01"));
}
BOOST_AUTO_TEST_CASE(test_local_time)
{
const toml::local_time time(12, 30, 45);
const toml::local_time time1(time);
BOOST_CHECK_EQUAL(time, time1);
BOOST_TEST(time == time1);
const std::chrono::nanoseconds dur(time);
std::chrono::nanoseconds ns(0);
ns += std::chrono::hours (12);
ns += std::chrono::minutes(30);
ns += std::chrono::seconds(45);
BOOST_CHECK_EQUAL(dur.count(), ns.count());
BOOST_TEST(dur.count() == ns.count());
const toml::local_time time3(12, 15, 45);
BOOST_CHECK(time > time3);
BOOST_TEST(time > time3);
{
std::ostringstream oss;
oss << time;
BOOST_CHECK_EQUAL(oss.str(), std::string("12:30:45"));
BOOST_TEST(oss.str() == std::string("12:30:45"));
}
{
const toml::local_time time4(12, 30, 45, 123, 456);
std::ostringstream oss;
oss << time4;
BOOST_CHECK_EQUAL(oss.str(), std::string("12:30:45.123456"));
BOOST_TEST(oss.str() == std::string("12:30:45.123456"));
}
}
@@ -59,20 +59,20 @@ BOOST_AUTO_TEST_CASE(test_time_offset)
{
const toml::time_offset time(9, 30);
const toml::time_offset time1(time);
BOOST_CHECK_EQUAL(time, time1);
BOOST_TEST(time == time1);
const std::chrono::minutes dur(time);
std::chrono::minutes m(0);
m += std::chrono::hours (9);
m += std::chrono::minutes(30);
BOOST_CHECK_EQUAL(dur.count(), m.count());
BOOST_TEST(dur.count() == m.count());
const toml::time_offset time2(9, 0);
BOOST_CHECK(time2 < time);
BOOST_TEST(time2 < time);
std::ostringstream oss;
oss << time;
BOOST_CHECK_EQUAL(oss.str(), std::string("+09:30"));
BOOST_TEST(oss.str() == std::string("+09:30"));
}
BOOST_AUTO_TEST_CASE(test_local_datetime)
@@ -80,15 +80,15 @@ BOOST_AUTO_TEST_CASE(test_local_datetime)
const toml::local_datetime dt(toml::local_date(2018, toml::month_t::Jan, 1),
toml::local_time(12, 30, 45));
const toml::local_datetime dt1(dt);
BOOST_CHECK_EQUAL(dt, dt1);
BOOST_TEST(dt == dt1);
const std::chrono::system_clock::time_point tp(dt);
const toml::local_datetime dt2(tp);
BOOST_CHECK_EQUAL(dt, dt2);
BOOST_TEST(dt == dt2);
std::ostringstream oss;
oss << dt;
BOOST_CHECK_EQUAL(oss.str(), std::string("2018-01-01T12:30:45"));
BOOST_TEST(oss.str() == std::string("2018-01-01T12:30:45"));
}
BOOST_AUTO_TEST_CASE(test_offset_datetime)
@@ -97,17 +97,18 @@ BOOST_AUTO_TEST_CASE(test_offset_datetime)
toml::local_time(12, 30, 45),
toml::time_offset(9, 30));
const toml::offset_datetime dt1(dt);
BOOST_CHECK_EQUAL(dt, dt1);
BOOST_TEST(dt == dt1);
const std::chrono::system_clock::time_point tp1(dt);
const toml::offset_datetime dt2(tp1);
const std::chrono::system_clock::time_point tp2(dt2);
BOOST_CHECK(tp1 == tp2);
const bool tp_same = (tp1 == tp2);
BOOST_TEST(tp_same);
{
std::ostringstream oss;
oss << dt;
BOOST_CHECK_EQUAL(oss.str(), std::string("2018-01-01T12:30:45+09:30"));
BOOST_TEST(oss.str() == std::string("2018-01-01T12:30:45+09:30"));
}
{
const toml::offset_datetime dt3(
@@ -116,6 +117,6 @@ BOOST_AUTO_TEST_CASE(test_offset_datetime)
toml::time_offset(0, 0));
std::ostringstream oss;
oss << dt3;
BOOST_CHECK_EQUAL(oss.str(), std::string("2018-01-01T12:30:45Z"));
BOOST_TEST(oss.str() == std::string("2018-01-01T12:30:45Z"));
}
}

View File

@@ -12,50 +12,19 @@
BOOST_AUTO_TEST_CASE(test_detect_empty_key)
{
std::istringstream stream(std::string("= \"value\""));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_empty_key");
}
catch(const toml::syntax_error& syn)
{
// to see the error message
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_detect_missing_value)
{
std::istringstream stream(std::string("a ="));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_missing_value");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_detect_too_many_value)
{
std::istringstream stream(std::string("a = 1 = \"value\""));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_too_many_value");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_detect_duplicate_table)
@@ -66,17 +35,7 @@ BOOST_AUTO_TEST_CASE(test_detect_duplicate_table)
"[table]\n"
"b = 42\n"
));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_duplicate_table");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_detect_conflict_array_table)
@@ -87,17 +46,7 @@ BOOST_AUTO_TEST_CASE(test_detect_conflict_array_table)
"[table]\n"
"b = 42\n"
));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_conflict_array_table");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_detect_conflict_table_array)
@@ -108,17 +57,7 @@ BOOST_AUTO_TEST_CASE(test_detect_conflict_table_array)
"[[table]]\n"
"b = 42\n"
));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_conflict_table_array");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_detect_duplicate_value)
@@ -127,17 +66,7 @@ BOOST_AUTO_TEST_CASE(test_detect_duplicate_value)
"a = 1\n"
"a = 2\n"
));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_duplicate_value");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_detect_conflicting_value)
@@ -146,35 +75,19 @@ BOOST_AUTO_TEST_CASE(test_detect_conflicting_value)
"a.b = 1\n"
"a.b.c = 2\n"
));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_conflicting_value");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_detect_inhomogeneous_array)
{
#ifdef TOML11_DISALLOW_HETEROGENEOUS_ARRAYS
std::istringstream stream(std::string(
"a = [1, 1.0]\n"
));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_inhomogeneous_array");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
#else
BOOST_TEST_MESSAGE("After v1.0.0-rc.1, heterogeneous arrays are allowed");
#endif
}
BOOST_AUTO_TEST_CASE(test_detect_appending_array_of_table)
@@ -184,16 +97,5 @@ BOOST_AUTO_TEST_CASE(test_detect_appending_array_of_table)
"[[a]]\n"
"b = 2\n"
));
bool exception_thrown = false;
try
{
toml::parse(stream, "test_detect_appending_array_of_table");
}
catch(const toml::syntax_error& syn)
{
std::cerr << syn.what() << std::endl;
exception_thrown = true;
}
BOOST_CHECK(exception_thrown);
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}

30
tests/test_expect.cpp Normal file
View File

@@ -0,0 +1,30 @@
#define BOOST_TEST_MODULE "test_expect"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
BOOST_AUTO_TEST_CASE(test_expect)
{
{
toml::value v1(42);
toml::value v2(3.14);
const auto v1_or_0 = toml::expect<int>(v1).unwrap_or(0);
const auto v2_or_0 = toml::expect<int>(v2).unwrap_or(0);
BOOST_TEST(42 == v1_or_0);
BOOST_TEST( 0 == v2_or_0);
const auto v1_or_none = toml::expect<int>(v1).map([](int i){return std::to_string(i);}).unwrap_or(std::string("none"));
const auto v2_or_none = toml::expect<int>(v2).map([](int i){return std::to_string(i);}).unwrap_or(std::string("none"));
BOOST_TEST("42" == v1_or_none);
BOOST_TEST("none" == v2_or_none);
}
}

View File

@@ -6,6 +6,8 @@
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <deque>
#include <map>
namespace extlib
{
@@ -31,6 +33,27 @@ struct bar
return toml::table{{"a", this->a}, {"b", this->b}};
}
};
struct baz
{
int a;
std::string b;
};
struct qux
{
int a;
std::string b;
};
struct foobar
{
// via constructor
explicit foobar(const toml::value& v)
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
{}
int a;
std::string b;
};
} // extlib
namespace toml
@@ -47,70 +70,562 @@ struct from<extlib::foo>
template<>
struct into<extlib::foo>
{
static toml::table into_toml(const extlib::foo& f)
static toml::value into_toml(const extlib::foo& f)
{
return toml::value{{"a", f.a}, {"b", f.b}};
}
};
template<>
struct from<extlib::baz>
{
static extlib::baz from_toml(const toml::value& v)
{
return extlib::baz{toml::find<int>(v, "a"), toml::find<std::string>(v, "b")};
}
};
template<>
struct into<extlib::qux>
{
static toml::table into_toml(const extlib::qux& f)
{
return toml::table{{"a", f.a}, {"b", f.b}};
}
};
} // toml
// ---------------------------------------------------------------------------
namespace extlib2
{
struct foo
{
int a;
std::string b;
};
struct bar
{
int a;
std::string b;
template<typename C, template<typename ...> class M, template<typename ...> class A>
void from_toml(const toml::basic_value<C, M, A>& v)
{
this->a = toml::find<int>(v, "a");
this->b = toml::find<std::string>(v, "b");
return ;
}
toml::table into_toml() const
{
return toml::table{{"a", this->a}, {"b", this->b}};
}
};
struct baz
{
int a;
std::string b;
};
struct qux
{
int a;
std::string b;
};
struct foobar
{
template<typename C, template<typename ...> class M, template<typename ...> class A>
explicit foobar(const toml::basic_value<C, M, A>& v)
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
{}
int a;
std::string b;
};
} // extlib2
namespace toml
{
template<>
struct from<extlib2::foo>
{
template<typename C, template<typename ...> class M, template<typename ...> class A>
static extlib2::foo from_toml(const toml::basic_value<C, M, A>& v)
{
return extlib2::foo{toml::find<int>(v, "a"), toml::find<std::string>(v, "b")};
}
};
template<>
struct into<extlib2::foo>
{
static toml::table into_toml(const extlib2::foo& f)
{
return toml::table{{"a", f.a}, {"b", f.b}};
}
};
template<>
struct from<extlib2::baz>
{
template<typename C, template<typename ...> class M, template<typename ...> class A>
static extlib2::baz from_toml(const toml::basic_value<C, M, A>& v)
{
return extlib2::baz{toml::find<int>(v, "a"), toml::find<std::string>(v, "b")};
}
};
template<>
struct into<extlib2::qux>
{
static toml::basic_value<toml::preserve_comments, std::map>
into_toml(const extlib2::qux& f)
{
return toml::basic_value<toml::preserve_comments, std::map>{
{"a", f.a}, {"b", f.b}
};
}
};
} // toml
// ---------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(test_conversion_by_member_methods)
{
const toml::value v{{"a", 42}, {"b", "baz"}};
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto foo = toml::get<extlib::foo>(v);
BOOST_CHECK_EQUAL(foo.a, 42);
BOOST_CHECK_EQUAL(foo.b, "baz");
const auto foo = toml::get<extlib::foo>(v);
BOOST_TEST(foo.a == 42);
BOOST_TEST(foo.b == "baz");
const toml::value v2(foo);
const toml::value v2(foo);
BOOST_CHECK_EQUAL(v, v2);
BOOST_TEST(v == v2);
}
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto foo = toml::get<extlib2::foo>(v);
BOOST_TEST(foo.a == 42);
BOOST_TEST(foo.b == "baz");
const toml::value v2(foo);
BOOST_TEST(v == v2);
}
{
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_TEST(foo.a == 42);
BOOST_TEST(foo.b == "baz");
const toml::basic_value<toml::discard_comments, std::map, std::deque>
v2(foo);
BOOST_TEST(v == v2);
}
}
BOOST_AUTO_TEST_CASE(test_conversion_by_specialization)
{
const toml::value v{{"a", 42}, {"b", "baz"}};
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto bar = toml::get<extlib::bar>(v);
BOOST_CHECK_EQUAL(bar.a, 42);
BOOST_CHECK_EQUAL(bar.b, "baz");
const auto bar = toml::get<extlib::bar>(v);
BOOST_TEST(bar.a == 42);
BOOST_TEST(bar.b == "baz");
const toml::value v2(bar);
const toml::value v2(bar);
BOOST_CHECK_EQUAL(v, v2);
BOOST_TEST(v == v2);
}
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto bar = toml::get<extlib2::bar>(v);
BOOST_TEST(bar.a == 42);
BOOST_TEST(bar.b == "baz");
const toml::value v2(bar);
BOOST_TEST(v == v2);
}
{
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_TEST(bar.a == 42);
BOOST_TEST(bar.b == "baz");
const toml::basic_value<toml::discard_comments, std::map, std::deque>
v2(bar);
BOOST_TEST(v == v2);
}
}
BOOST_AUTO_TEST_CASE(test_conversion_one_way)
{
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto baz = toml::get<extlib::baz>(v);
BOOST_TEST(baz.a == 42);
BOOST_TEST(baz.b == "baz");
}
{
const extlib::qux q{42, "qux"};
const toml::value v(q);
BOOST_TEST(toml::find<int>(v, "a") == 42);
BOOST_TEST(toml::find<std::string>(v, "b") == "qux");
}
{
const toml::basic_value<toml::discard_comments, std::map> v{
{"a", 42}, {"b", "baz"}
};
const auto baz = toml::get<extlib2::baz>(v);
BOOST_TEST(baz.a == 42);
BOOST_TEST(baz.b == "baz");
}
{
const extlib::qux q{42, "qux"};
const toml::basic_value<toml::preserve_comments, std::map> v(q);
BOOST_TEST(toml::find<int>(v, "a") == 42);
BOOST_TEST(toml::find<std::string>(v, "b") == "qux");
}
}
BOOST_AUTO_TEST_CASE(test_conversion_via_constructor)
{
{
const toml::value v{{"a", 42}, {"b", "foobar"}};
const auto foobar = toml::get<extlib::foobar>(v);
BOOST_TEST(foobar.a == 42);
BOOST_TEST(foobar.b == "foobar");
}
{
const toml::basic_value<toml::discard_comments, std::map> v{
{"a", 42}, {"b", "foobar"}
};
const auto foobar = toml::get<extlib2::foobar>(v);
BOOST_TEST(foobar.a == 42);
BOOST_TEST(foobar.b == "foobar");
}
}
BOOST_AUTO_TEST_CASE(test_recursive_conversion)
{
const toml::value 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"}},
};
{
const toml::value 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"}},
};
const auto foos = toml::get<std::vector<extlib::foo>>(v);
BOOST_CHECK_EQUAL(foos.size() , 4ul);
BOOST_CHECK_EQUAL(foos.at(0).a , 42);
BOOST_CHECK_EQUAL(foos.at(1).a , 43);
BOOST_CHECK_EQUAL(foos.at(2).a , 44);
BOOST_CHECK_EQUAL(foos.at(3).a , 45);
const auto foos = toml::get<std::vector<extlib::foo>>(v);
BOOST_TEST(foos.size() == 4ul);
BOOST_TEST(foos.at(0).a == 42);
BOOST_TEST(foos.at(1).a == 43);
BOOST_TEST(foos.at(2).a == 44);
BOOST_TEST(foos.at(3).a == 45);
BOOST_CHECK_EQUAL(foos.at(0).b , "baz");
BOOST_CHECK_EQUAL(foos.at(1).b , "qux");
BOOST_CHECK_EQUAL(foos.at(2).b , "quux");
BOOST_CHECK_EQUAL(foos.at(3).b , "foobar");
BOOST_TEST(foos.at(0).b == "baz");
BOOST_TEST(foos.at(1).b == "qux");
BOOST_TEST(foos.at(2).b == "quux");
BOOST_TEST(foos.at(3).b == "foobar");
const auto bars = toml::get<std::vector<extlib::bar>>(v);
BOOST_CHECK_EQUAL(bars.size() , 4ul);
BOOST_CHECK_EQUAL(bars.at(0).a , 42);
BOOST_CHECK_EQUAL(bars.at(1).a , 43);
BOOST_CHECK_EQUAL(bars.at(2).a , 44);
BOOST_CHECK_EQUAL(bars.at(3).a , 45);
const auto bars = toml::get<std::vector<extlib::bar>>(v);
BOOST_TEST(bars.size() == 4ul);
BOOST_TEST(bars.at(0).a == 42);
BOOST_TEST(bars.at(1).a == 43);
BOOST_TEST(bars.at(2).a == 44);
BOOST_TEST(bars.at(3).a == 45);
BOOST_TEST(bars.at(0).b == "baz");
BOOST_TEST(bars.at(1).b == "qux");
BOOST_TEST(bars.at(2).b == "quux");
BOOST_TEST(bars.at(3).b == "foobar");
}
{
const toml::value 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"}},
};
const auto foos = toml::get<std::vector<extlib2::foo>>(v);
BOOST_TEST(foos.size() == 4ul);
BOOST_TEST(foos.at(0).a == 42);
BOOST_TEST(foos.at(1).a == 43);
BOOST_TEST(foos.at(2).a == 44);
BOOST_TEST(foos.at(3).a == 45);
BOOST_TEST(foos.at(0).b == "baz");
BOOST_TEST(foos.at(1).b == "qux");
BOOST_TEST(foos.at(2).b == "quux");
BOOST_TEST(foos.at(3).b == "foobar");
const auto bars = toml::get<std::vector<extlib2::bar>>(v);
BOOST_TEST(bars.size() == 4ul);
BOOST_TEST(bars.at(0).a == 42);
BOOST_TEST(bars.at(1).a == 43);
BOOST_TEST(bars.at(2).a == 44);
BOOST_TEST(bars.at(3).a == 45);
BOOST_TEST(bars.at(0).b == "baz");
BOOST_TEST(bars.at(1).b == "qux");
BOOST_TEST(bars.at(2).b == "quux");
BOOST_TEST(bars.at(3).b == "foobar");
}
{
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"}}
};
const auto foos = toml::get<std::vector<extlib2::foo>>(v);
BOOST_TEST(foos.size() == 4ul);
BOOST_TEST(foos.at(0).a == 42);
BOOST_TEST(foos.at(1).a == 43);
BOOST_TEST(foos.at(2).a == 44);
BOOST_TEST(foos.at(3).a == 45);
BOOST_TEST(foos.at(0).b == "baz");
BOOST_TEST(foos.at(1).b == "qux");
BOOST_TEST(foos.at(2).b == "quux");
BOOST_TEST(foos.at(3).b == "foobar");
const auto bars = toml::get<std::vector<extlib2::bar>>(v);
BOOST_TEST(bars.size() == 4ul);
BOOST_TEST(bars.at(0).a == 42);
BOOST_TEST(bars.at(1).a == 43);
BOOST_TEST(bars.at(2).a == 44);
BOOST_TEST(bars.at(3).a == 45);
BOOST_TEST(bars.at(0).b == "baz");
BOOST_TEST(bars.at(1).b == "qux");
BOOST_TEST(bars.at(2).b == "quux");
BOOST_TEST(bars.at(3).b == "foobar");
}
// via constructor
{
const toml::value 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"}}
};
{
const auto foobars = toml::get<std::vector<extlib::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
{
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
}
{
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"}}
};
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
// via constructor
{
const toml::value v{
{"0", toml::table{{"a", 42}, {"b", "baz"}}},
{"1", toml::table{{"a", 43}, {"b", "qux"}}},
{"2", toml::table{{"a", 44}, {"b", "quux"}}},
{"3", toml::table{{"a", 45}, {"b", "foobar"}}}
};
{
const auto foobars = toml::get<std::map<std::string, extlib::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at("0").a == 42);
BOOST_TEST(foobars.at("1").a == 43);
BOOST_TEST(foobars.at("2").a == 44);
BOOST_TEST(foobars.at("3").a == 45);
BOOST_TEST(foobars.at("0").b == "baz");
BOOST_TEST(foobars.at("1").b == "qux");
BOOST_TEST(foobars.at("2").b == "quux");
BOOST_TEST(foobars.at("3").b == "foobar");
}
{
const auto foobars = toml::get<std::map<std::string, extlib2::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at("0").a == 42);
BOOST_TEST(foobars.at("1").a == 43);
BOOST_TEST(foobars.at("2").a == 44);
BOOST_TEST(foobars.at("3").a == 45);
BOOST_TEST(foobars.at("0").b == "baz");
BOOST_TEST(foobars.at("1").b == "qux");
BOOST_TEST(foobars.at("2").b == "quux");
BOOST_TEST(foobars.at("3").b == "foobar");
}
}
{
const toml::basic_value<toml::discard_comments, std::map, std::deque>
v{
{"0", toml::table{{"a", 42}, {"b", "baz"}}},
{"1", toml::table{{"a", 43}, {"b", "qux"}}},
{"2", toml::table{{"a", 44}, {"b", "quux"}}},
{"3", toml::table{{"a", 45}, {"b", "foobar"}}}
};
const auto foobars = toml::get<std::map<std::string, extlib::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at("0").a == 42);
BOOST_TEST(foobars.at("1").a == 43);
BOOST_TEST(foobars.at("2").a == 44);
BOOST_TEST(foobars.at("3").a == 45);
BOOST_TEST(foobars.at("0").b == "baz");
BOOST_TEST(foobars.at("1").b == "qux");
BOOST_TEST(foobars.at("2").b == "quux");
BOOST_TEST(foobars.at("3").b == "foobar");
}
BOOST_CHECK_EQUAL(bars.at(0).b , "baz");
BOOST_CHECK_EQUAL(bars.at(1).b , "qux");
BOOST_CHECK_EQUAL(bars.at(2).b , "quux");
BOOST_CHECK_EQUAL(bars.at(3).b , "foobar");
}
// ===========================================================================
#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
namespace extlib3
{
struct foo
{
int a;
std::string b;
};
struct bar
{
int a;
std::string b;
foo f;
};
} // extlib3
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib3::foo, a, b)
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib3::bar, a, b, f)
BOOST_AUTO_TEST_CASE(test_conversion_via_macro)
{
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto foo = toml::get<extlib3::foo>(v);
BOOST_TEST(foo.a == 42);
BOOST_TEST(foo.b == "baz");
const toml::value v2(foo);
BOOST_TEST(v2 == v);
}
{
const toml::basic_value<toml::discard_comments, std::map, std::deque> v{
{"a", 42}, {"b", "baz"}
};
const auto foo = toml::get<extlib3::foo>(v);
BOOST_TEST(foo.a == 42);
BOOST_TEST(foo.b == "baz");
const toml::basic_value<toml::discard_comments, std::map, std::deque> v2(foo);
BOOST_TEST(v2 == v);
}
// -----------------------------------------------------------------------
{
const toml::value v{
{"a", 42},
{"b", "bar.b"},
{"f", toml::table{{"a", 42}, {"b", "foo.b"}}}
};
const auto bar = toml::get<extlib3::bar>(v);
BOOST_TEST(bar.a == 42);
BOOST_TEST(bar.b == "bar.b");
BOOST_TEST(bar.f.a == 42);
BOOST_TEST(bar.f.b == "foo.b");
const toml::value v2(bar);
BOOST_TEST(v2 == v);
}
{
const toml::basic_value<toml::discard_comments, std::map, std::deque> v{
{"a", 42},
{"b", "bar.b"},
{"f", toml::table{{"a", 42}, {"b", "foo.b"}}}
};
const auto bar = toml::get<extlib3::bar>(v);
BOOST_TEST(bar.a == 42);
BOOST_TEST(bar.b == "bar.b");
BOOST_TEST(bar.f.a == 42);
BOOST_TEST(bar.f.b == "foo.b");
const toml::basic_value<toml::discard_comments, std::map, std::deque> v2(bar);
BOOST_TEST(v2 == v);
}
}
#endif // TOML11_WITHOUT_DEFINE_NON_INTRUSIVE

833
tests/test_find.cpp Normal file
View File

@@ -0,0 +1,833 @@
#define BOOST_TEST_MODULE "test_find"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <string_view>
#endif
#include <tuple>
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
>;
BOOST_AUTO_TEST_CASE(test_find_throws)
{
// -----------------------------------------------------------------------
// const-reference version
{
// value is not a table
const toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, "key"), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
const toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, "key"), toml::type_error);
}
{
// the value corresponding to the key is not found
const toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, "different_key"),
std::out_of_range);
}
{
// the positive control.
const toml::value v{{"key", 42}};
BOOST_TEST(42 == toml::find<int>(v, "key"));
}
// -----------------------------------------------------------------------
// reference version
{
// value is not a table
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, "key"), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, "key"), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, "different_key"),
std::out_of_range);
}
{
// the positive control.
toml::value v{{"key", 42}};
BOOST_TEST(42 == toml::find<int>(v, "key"));
}
// -----------------------------------------------------------------------
// move version
{
// value is not a table
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), "key"), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), "key"), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::integer>(std::move(v), "different_key"),
std::out_of_range);
}
{
// the positive control.
toml::value v{{"key", 42}};
BOOST_TEST(42 == toml::find<int>(std::move(v), "key"));
}
}
BOOST_AUTO_TEST_CASE(test_find_array_throws)
{
// -----------------------------------------------------------------------
// const-reference version
{
// value is not an array
const toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
const toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not found
const toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
}
{
// the positive control.
const toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(v, 2));
}
// -----------------------------------------------------------------------
// non-const reference version
{
// value is not an array
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
}
{
// the positive control.
toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(v, 2));
}
// -----------------------------------------------------------------------
// move version
{
// value is not an array
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(std::move(v), 6), std::out_of_range);
}
{
// the positive control.
toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(std::move(v), 2));
}
}
BOOST_AUTO_TEST_CASE(test_find_recursive)
{
// recursively search tables
{
toml::value v{
{"a", {
{"b", {
{"c", {
{"d", 42}
}}
}}
}}
};
BOOST_TEST(42 == toml::find<int>(v, "a", "b", "c", "d"));
// reference that can be used to modify the content
auto& num = toml::find<toml::integer>(v, "a", "b", "c", "d");
num = 54;
BOOST_TEST(54 == toml::find<int>(v, "a", "b", "c", "d"));
const std::string a("a"), b("b"), c("c"), d("d");
auto& num2 = toml::find<toml::integer>(v, a, b, c, d);
num2 = 42;
BOOST_TEST(42 == toml::find<int>(v, a, b, c, d));
auto num3 = toml::find<toml::integer>(v, a, "b", c, "d");
BOOST_TEST(42 == num3);
auto num4 = toml::find<toml::integer>(std::move(v), a, b, c, d);
BOOST_TEST(42 == num4);
}
// recursively search arrays
{
toml::value v{
toml::array{"array", "of", "string"},
toml::array{toml::array{1, 2, 3}, toml::array{3.14, 2.71}}
};
BOOST_TEST("array" == toml::find<std::string>(v, 0, 0));
BOOST_TEST("of" == toml::find<std::string>(v, 0, 1));
BOOST_TEST("string" == toml::find<std::string>(v, 0, 2));
BOOST_TEST(1 == toml::find<int>(v, 1, 0, 0));
BOOST_TEST(2 == toml::find<int>(v, 1, 0, 1));
BOOST_TEST(3 == toml::find<int>(v, 1, 0, 2));
BOOST_TEST(3.14 == toml::find<double>(v, 1, 1, 0));
BOOST_TEST(2.71 == toml::find<double>(v, 1, 1, 1));
// reference that can be used to modify the content
auto& num = toml::find<toml::integer>(v, 1, 0, 2);
num = 42;
BOOST_TEST( 1 == toml::find<int>(v, 1, 0, 0));
BOOST_TEST( 2 == toml::find<int>(v, 1, 0, 1));
BOOST_TEST(42 == toml::find<int>(v, 1, 0, 2));
// move value
auto num2 = toml::find<toml::integer>(std::move(v), 1, 0, 2);
BOOST_TEST(42 == num2);
}
// recursively search mixtures
{
toml::value v = toml::table{{"array", toml::array{
toml::array{1, 2, 3},
toml::array{
toml::table{{"foo", "bar"}, {"baz", "qux"}},
toml::table{{"pi", 3.14}, {"e", 2.71}}
}}
}};
BOOST_TEST(1 == toml::find<int>(v, "array", 0, 0));
BOOST_TEST(2 == toml::find<int>(v, "array", 0, 1));
BOOST_TEST(3 == toml::find<int>(v, "array", 0, 2));
BOOST_TEST("bar" == toml::find<std::string>(v, "array", 1, 0, "foo"));
BOOST_TEST("qux" == toml::find<std::string>(v, "array", 1, 0, "baz"));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, "pi"));
BOOST_TEST(2.71 == toml::find<double>(v, "array", 1, 1, "e"));
const std::string ar("array");
const auto ar_c = "array";
const std::string pi("pi");
const auto pi_c = "pi";
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, "pi"));
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi_c));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, "pi"));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi_c));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi_c));
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
{
{
value_type v{{"key", true}};
BOOST_TEST(true == toml::find<toml::boolean>(v, "key"));
toml::find<toml::boolean>(v, "key") = false;
BOOST_TEST(false == toml::find<toml::boolean>(v, "key"));
const auto moved = toml::find<toml::boolean>(std::move(v), "key");
BOOST_TEST(false == moved);
}
{
value_type v{{"key", 42}};
BOOST_TEST(toml::integer(42) == toml::find<toml::integer>(v, "key"));
toml::find<toml::integer>(v, "key") = 54;
BOOST_TEST(toml::integer(54) == toml::find<toml::integer>(v, "key"));
const auto moved = toml::find<toml::integer>(std::move(v), "key");
BOOST_TEST(toml::integer(54) == moved);
}
{
value_type v{{"key", 3.14}};
BOOST_TEST(toml::floating(3.14) == toml::find<toml::floating>(v, "key"));
toml::find<toml::floating>(v, "key") = 2.71;
BOOST_TEST(toml::floating(2.71) == toml::find<toml::floating>(v, "key"));
const auto moved = toml::find<toml::floating>(std::move(v), "key");
BOOST_TEST(toml::floating(2.71) == moved);
}
{
value_type v{{"key", "foo"}};
BOOST_TEST(toml::string("foo", toml::string_t::basic) ==
toml::find<toml::string>(v, "key"));
toml::find<toml::string>(v, "key").str += "bar";
BOOST_TEST(toml::string("foobar", toml::string_t::basic) ==
toml::find<toml::string>(v, "key"));
const auto moved = toml::find<toml::string>(std::move(v), "key");
BOOST_TEST(toml::string("foobar", toml::string_t::basic) == moved);
}
{
value_type v{{"key", value_type("foo", toml::string_t::literal)}};
BOOST_TEST(toml::string("foo", toml::string_t::literal) ==
toml::find<toml::string>(v, "key"));
toml::find<toml::string>(v, "key").str += "bar";
BOOST_TEST(toml::string("foobar", toml::string_t::literal) ==
toml::find<toml::string>(v, "key"));
const auto moved = toml::find<toml::string>(std::move(v), "key");
BOOST_TEST(toml::string("foobar", toml::string_t::literal) == moved);
}
{
toml::local_date d(2018, toml::month_t::Apr, 22);
value_type v{{"key", d}};
BOOST_CHECK(d == toml::find<toml::local_date>(v, "key"));
toml::find<toml::local_date>(v, "key").year = 2017;
d.year = 2017;
BOOST_CHECK(d == toml::find<toml::local_date>(v, "key"));
const auto moved = toml::find<toml::local_date>(std::move(v), "key");
BOOST_CHECK(d == moved);
}
{
toml::local_time t(12, 30, 45);
value_type v{{"key", t}};
BOOST_CHECK(t == toml::find<toml::local_time>(v, "key"));
toml::find<toml::local_time>(v, "key").hour = 9;
t.hour = 9;
BOOST_CHECK(t == toml::find<toml::local_time>(v, "key"));
const auto moved = toml::find<toml::local_time>(std::move(v), "key");
BOOST_CHECK(t == moved);
}
{
toml::local_datetime dt(toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 30, 45));
value_type v{{"key", dt}};
BOOST_CHECK(dt == toml::find<toml::local_datetime>(v, "key"));
toml::find<toml::local_datetime>(v, "key").date.year = 2017;
dt.date.year = 2017;
BOOST_CHECK(dt == toml::find<toml::local_datetime>(v, "key"));
const auto moved = toml::find<toml::local_datetime>(std::move(v), "key");
BOOST_CHECK(dt == moved);
}
{
toml::offset_datetime dt(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 30, 45)), toml::time_offset(9, 0));
value_type v{{"key", dt}};
BOOST_CHECK(dt == toml::find<toml::offset_datetime>(v, "key"));
toml::find<toml::offset_datetime>(v, "key").date.year = 2017;
dt.date.year = 2017;
BOOST_CHECK(dt == toml::find<toml::offset_datetime>(v, "key"));
const auto moved = toml::find<toml::offset_datetime>(std::move(v), "key");
BOOST_CHECK(dt == moved);
}
{
typename value_type::array_type vec;
vec.push_back(value_type(42));
vec.push_back(value_type(54));
value_type v{{"key", vec}};
const bool result1 = (vec == toml::find<typename value_type::array_type>(v, "key"));
BOOST_CHECK(result1);
toml::find<typename value_type::array_type>(v, "key").push_back(value_type(123));
vec.push_back(value_type(123));
const bool result2 = (vec == toml::find<typename value_type::array_type>(v, "key"));
BOOST_CHECK(result2);
const auto moved = toml::find<typename value_type::array_type>(std::move(v), "key");
const bool result3 = (vec == moved);
BOOST_CHECK(result3);
}
{
typename value_type::table_type tab;
tab["key1"] = value_type(42);
tab["key2"] = value_type(3.14);
value_type v{{"key", tab}};
const bool result1 = (tab == toml::find<typename value_type::table_type>(v, "key"));
BOOST_CHECK(result1);
toml::find<typename value_type::table_type>(v, "key")["key3"] = value_type(123);
tab["key3"] = value_type(123);
const bool result2 = (tab == toml::find<typename value_type::table_type>(v, "key"));
BOOST_CHECK(result2);
const auto moved = toml::find<typename value_type::table_type>(std::move(v), "key");
const bool result3 = (tab == moved);
BOOST_CHECK(result3);
}
{
value_type v1(42);
value_type v{{"key", v1}};
BOOST_CHECK(v1 == toml::find(v, "key"));
value_type v2(54);
toml::find(v, "key") = v2;
BOOST_CHECK(v2 == toml::find(v, "key"));
const auto moved = toml::find(std::move(v), "key");
BOOST_CHECK(v2 == moved);
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_integer_type, value_type, test_value_types)
{
{
value_type v{{"key", 42}};
BOOST_TEST(int(42) == toml::find<int >(v, "key"));
BOOST_TEST(short(42) == toml::find<short >(v, "key"));
BOOST_TEST(char(42) == toml::find<char >(v, "key"));
BOOST_TEST(unsigned(42) == toml::find<unsigned >(v, "key"));
BOOST_TEST(long(42) == toml::find<long >(v, "key"));
BOOST_TEST(std::int64_t(42) == toml::find<std::int64_t >(v, "key"));
BOOST_TEST(std::uint64_t(42) == toml::find<std::uint64_t>(v, "key"));
BOOST_TEST(std::int16_t(42) == toml::find<std::int16_t >(v, "key"));
BOOST_TEST(std::uint16_t(42) == toml::find<std::uint16_t>(v, "key"));
BOOST_TEST(std::uint16_t(42) == toml::find<std::uint16_t>(std::move(v), "key"));
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_floating_type, value_type, test_value_types)
{
{
value_type v{{"key", 3.14}};
const double ref(3.14);
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(v, "key"));
BOOST_TEST( ref == toml::find<double >(v, "key"));
BOOST_TEST(static_cast<long double>(ref) == toml::find<long double>(v, "key"));
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(std::move(v), "key"));
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_string_type, value_type, test_value_types)
{
{
value_type v{{"key", toml::string("foo", toml::string_t::basic)}};
BOOST_TEST("foo" == toml::find<std::string>(v, "key"));
toml::find<std::string>(v, "key") += "bar";
BOOST_TEST("foobar" == toml::find<std::string>(v, "key"));
}
{
value_type v{{"key", toml::string("foo", toml::string_t::literal)}};
BOOST_TEST("foo" == toml::find<std::string>(v, "key"));
toml::find<std::string>(v, "key") += "bar";
BOOST_TEST("foobar" == toml::find<std::string>(v, "key"));
}
{
value_type v{{"key", toml::string("foo", toml::string_t::literal)}};
const auto moved = toml::find<std::string>(std::move(v), "key");
BOOST_TEST("foo" == moved);
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
{
value_type v{{"key", toml::string("foo", toml::string_t::basic)}};
BOOST_TEST("foo" == toml::find<std::string_view>(v, "key"));
}
{
value_type v{{"key", toml::string("foo", toml::string_t::literal)}};
BOOST_TEST("foo" == toml::find<std::string_view>(v, "key"));
}
#endif
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array, value_type, test_value_types)
{
value_type v{{"key", {42, 54, 69, 72}}};
const std::vector<int> vec = toml::find<std::vector<int>>(v, "key");
const std::list<short> lst = toml::find<std::list<short>>(v, "key");
const std::deque<std::int64_t> deq = toml::find<std::deque<std::int64_t>>(v, "key");
BOOST_TEST(42 == vec.at(0));
BOOST_TEST(54 == vec.at(1));
BOOST_TEST(69 == vec.at(2));
BOOST_TEST(72 == vec.at(3));
std::list<short>::const_iterator iter = lst.begin();
BOOST_TEST(static_cast<short>(42) == *(iter++));
BOOST_TEST(static_cast<short>(54) == *(iter++));
BOOST_TEST(static_cast<short>(69) == *(iter++));
BOOST_TEST(static_cast<short>(72) == *(iter++));
BOOST_TEST(static_cast<std::int64_t>(42) == deq.at(0));
BOOST_TEST(static_cast<std::int64_t>(54) == deq.at(1));
BOOST_TEST(static_cast<std::int64_t>(69) == deq.at(2));
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::find<std::array<int, 4>>(v, "key");
BOOST_TEST(42 == ary.at(0));
BOOST_TEST(54 == ary.at(1));
BOOST_TEST(69 == ary.at(2));
BOOST_TEST(72 == ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::find<std::tuple<int, short, unsigned, long>>(v, "key");
BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
value_type p{{"key", {3.14, 2.71}}};
std::pair<double, double> pr = toml::find<std::pair<double, double> >(p, "key");
BOOST_TEST(3.14 == pr.first);
BOOST_TEST(2.71 == pr.second);
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_move_toml_array, value_type, test_value_types)
{
value_type v1{{"key", {42, 54, 69, 72}}};
value_type v2{{"key", {42, 54, 69, 72}}};
value_type v3{{"key", {42, 54, 69, 72}}};
value_type v4{{"key", {42, 54, 69, 72}}};
value_type v5{{"key", {42, 54, 69, 72}}};
const std::vector<int> vec = toml::find<std::vector<int>>(std::move(v1), "key");
const std::list<short> lst = toml::find<std::list<short>>(std::move(v2), "key");
const std::deque<std::int64_t> deq = toml::find<std::deque<std::int64_t>>(std::move(v3), "key");
BOOST_TEST(42 == vec.at(0));
BOOST_TEST(54 == vec.at(1));
BOOST_TEST(69 == vec.at(2));
BOOST_TEST(72 == vec.at(3));
std::list<short>::const_iterator iter = lst.begin();
BOOST_TEST(static_cast<short>(42) == *(iter++));
BOOST_TEST(static_cast<short>(54) == *(iter++));
BOOST_TEST(static_cast<short>(69) == *(iter++));
BOOST_TEST(static_cast<short>(72) == *(iter++));
BOOST_TEST(static_cast<std::int64_t>(42) == deq.at(0));
BOOST_TEST(static_cast<std::int64_t>(54) == deq.at(1));
BOOST_TEST(static_cast<std::int64_t>(69) == deq.at(2));
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::find<std::array<int, 4>>(std::move(v4), "key");
BOOST_TEST(42 == ary.at(0));
BOOST_TEST(54 == ary.at(1));
BOOST_TEST(69 == ary.at(2));
BOOST_TEST(72 == ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::find<std::tuple<int, short, unsigned, long>>(std::move(v5), "key");
BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
value_type p{{"key", {3.14, 2.71}}};
std::pair<double, double> pr = toml::find<std::pair<double, double> >(std::move(p), "key");
BOOST_TEST(3.14 == pr.first);
BOOST_TEST(2.71 == pr.second);
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array_of_array, value_type, test_value_types)
{
value_type v1{42, 54, 69, 72};
value_type v2{"foo", "bar", "baz"};
value_type v{{"key", {v1, v2}}};
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::find<std::pair<std::vector<int>, std::vector<std::string>>>(v, "key");
BOOST_TEST(p.first.at(0) == 42);
BOOST_TEST(p.first.at(1) == 54);
BOOST_TEST(p.first.at(2) == 69);
BOOST_TEST(p.first.at(3) == 72);
BOOST_TEST(p.second.at(0) == "foo");
BOOST_TEST(p.second.at(1) == "bar");
BOOST_TEST(p.second.at(2) == "baz");
std::tuple<std::vector<int>, std::vector<std::string>> t =
toml::find<std::tuple<std::vector<int>, std::vector<std::string>>>(v, "key");
BOOST_TEST(std::get<0>(t).at(0) == 42);
BOOST_TEST(std::get<0>(t).at(1) == 54);
BOOST_TEST(std::get<0>(t).at(2) == 69);
BOOST_TEST(std::get<0>(t).at(3) == 72);
BOOST_TEST(std::get<1>(t).at(0) == "foo");
BOOST_TEST(std::get<1>(t).at(1) == "bar");
BOOST_TEST(std::get<1>(t).at(2) == "baz");
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_move_toml_array_of_array, value_type, test_value_types)
{
value_type a1{42, 54, 69, 72};
value_type a2{"foo", "bar", "baz"};
value_type v1{{"key", {a1, a2}}};
value_type v2{{"key", {a1, a2}}};
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::find<std::pair<std::vector<int>, std::vector<std::string>>>(std::move(v1), "key");
BOOST_TEST(p.first.at(0) == 42);
BOOST_TEST(p.first.at(1) == 54);
BOOST_TEST(p.first.at(2) == 69);
BOOST_TEST(p.first.at(3) == 72);
BOOST_TEST(p.second.at(0) == "foo");
BOOST_TEST(p.second.at(1) == "bar");
BOOST_TEST(p.second.at(2) == "baz");
std::tuple<std::vector<int>, std::vector<std::string>> t =
toml::find<std::tuple<std::vector<int>, std::vector<std::string>>>(std::move(v2), "key");
BOOST_TEST(std::get<0>(t).at(0) == 42);
BOOST_TEST(std::get<0>(t).at(1) == 54);
BOOST_TEST(std::get<0>(t).at(2) == 69);
BOOST_TEST(std::get<0>(t).at(3) == 72);
BOOST_TEST(std::get<1>(t).at(0) == "foo");
BOOST_TEST(std::get<1>(t).at(1) == "bar");
BOOST_TEST(std::get<1>(t).at(2) == "baz");
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_table, value_type, test_value_types)
{
{
value_type v1{{"key", {
{"key1", 1}, {"key2", 2}, {"key3", 3}, {"key4", 4}
}}};
const auto v = toml::find<std::map<std::string, int>>(v1, "key");
BOOST_TEST(v.at("key1") == 1);
BOOST_TEST(v.at("key2") == 2);
BOOST_TEST(v.at("key3") == 3);
BOOST_TEST(v.at("key4") == 4);
}
{
value_type v1{{"key", {
{"key1", 1}, {"key2", 2}, {"key3", 3}, {"key4", 4}
}}};
const auto v = toml::find<std::map<std::string, int>>(std::move(v1), "key");
BOOST_TEST(v.at("key1") == 1);
BOOST_TEST(v.at("key2") == 2);
BOOST_TEST(v.at("key3") == 3);
BOOST_TEST(v.at("key4") == 4);
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_local_date, value_type, test_value_types)
{
{
value_type v1{{"key", toml::local_date{2018, toml::month_t::Apr, 1}}};
const auto date = std::chrono::system_clock::to_time_t(
toml::find<std::chrono::system_clock::time_point>(v1, "key"));
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 0;
t.tm_min = 0;
t.tm_sec = 0;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_TEST(c == date);
}
{
value_type v1{{"key", toml::local_date{2018, toml::month_t::Apr, 1}}};
const auto date = std::chrono::system_clock::to_time_t(
toml::find<std::chrono::system_clock::time_point>(std::move(v1), "key"));
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 0;
t.tm_min = 0;
t.tm_sec = 0;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_TEST(c == date);
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_local_time, value_type, test_value_types)
{
{
value_type v1{{"key", toml::local_time{12, 30, 45}}};
const auto time = toml::find<std::chrono::seconds>(v1, "key");
BOOST_CHECK(time == std::chrono::hours(12) +
std::chrono::minutes(30) + std::chrono::seconds(45));
}
{
value_type v1{{"key", toml::local_time{12, 30, 45}}};
const auto time = toml::find<std::chrono::seconds>(std::move(v1), "key");
BOOST_CHECK(time == std::chrono::hours(12) +
std::chrono::minutes(30) + std::chrono::seconds(45));
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_local_datetime, value_type, test_value_types)
{
{
value_type v1{{"key", toml::local_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 45})}};
const auto date = std::chrono::system_clock::to_time_t(
toml::find<std::chrono::system_clock::time_point>(v1, "key"));
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 12;
t.tm_min = 30;
t.tm_sec = 45;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_TEST(c == date);
}
{
value_type v1{{"key", toml::local_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 45})}};
const auto date = std::chrono::system_clock::to_time_t(
toml::find<std::chrono::system_clock::time_point>(std::move(v1), "key"));
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 12;
t.tm_min = 30;
t.tm_sec = 45;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_TEST(c == date);
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_offset_datetime, value_type, test_value_types)
{
{
value_type v1{{"key", toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{9, 0})}};
// 2018-04-01T12:30:00+09:00
// == 2018-04-01T03:30:00Z
const auto date = toml::find<std::chrono::system_clock::time_point>(v1, "key");
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tmp = std::gmtime(std::addressof(timet)); // XXX not threadsafe!
BOOST_CHECK(tmp);
const auto tm = *tmp;
BOOST_TEST(tm.tm_year + 1900 == 2018);
BOOST_TEST(tm.tm_mon + 1 == 4);
BOOST_TEST(tm.tm_mday == 1);
BOOST_TEST(tm.tm_hour == 3);
BOOST_TEST(tm.tm_min == 30);
BOOST_TEST(tm.tm_sec == 0);
}
{
value_type v1{{"key", toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{-8, 0})}};
// 2018-04-01T12:30:00-08:00
// == 2018-04-01T20:30:00Z
const auto date = toml::find<std::chrono::system_clock::time_point>(v1, "key");
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tmp = std::gmtime(std::addressof(timet)); // XXX not threadsafe!
BOOST_CHECK(tmp);
const auto tm = *tmp;
BOOST_TEST(tm.tm_year + 1900 == 2018);
BOOST_TEST(tm.tm_mon + 1 == 4);
BOOST_TEST(tm.tm_mday == 1);
BOOST_TEST(tm.tm_hour == 20);
BOOST_TEST(tm.tm_min == 30);
BOOST_TEST(tm.tm_sec == 0);
}
{
value_type v1{{"key", toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{-8, 0})}};
// 2018-04-01T12:30:00-08:00
// == 2018-04-01T20:30:00Z
const auto date = toml::find<std::chrono::system_clock::time_point>(std::move(v1), "key");
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tmp = std::gmtime(std::addressof(timet)); // XXX not threadsafe!
BOOST_CHECK(tmp);
const auto tm = *tmp;
BOOST_TEST(tm.tm_year + 1900 == 2018);
BOOST_TEST(tm.tm_mon + 1 == 4);
BOOST_TEST(tm.tm_mday == 1);
BOOST_TEST(tm.tm_hour == 20);
BOOST_TEST(tm.tm_min == 30);
BOOST_TEST(tm.tm_sec == 0);
}
}

541
tests/test_find_or.cpp Normal file
View File

@@ -0,0 +1,541 @@
#define BOOST_TEST_MODULE "test_find_or"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
#include <tuple>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <string_view>
#endif
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
>;
namespace test
{
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::vector<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::deque<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::list<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits,
typename Key, typename Value, typename Comp, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const std::map<Key, Value, Comp, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
os << ']';
return os;
}
template<typename charT, typename traits,
typename Key, typename Value, typename Hash, typename Eq, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const std::unordered_map<Key, Value, Hash, Eq, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
os << ']';
return os;
}
} // test
#define TOML11_TEST_FIND_OR_EXACT(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
const toml::toml_type opt opt_expr ; \
const value_type v{{"key", init}}; \
BOOST_TEST(init != opt); \
BOOST_TEST(init == toml::find_or(v, "key", opt)); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_exact, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_EXACT(boolean, ( true), (false))
TOML11_TEST_FIND_OR_EXACT(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_EXACT(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_EXACT(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_EXACT(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_EXACT(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_EXACT(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_EXACT(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
const typename value_type::array_type init{1,2,3,4,5};
const typename value_type::array_type opt {6,7,8,9,10};
const value_type v{{"key", init}};
BOOST_TEST(init != opt);
BOOST_TEST(init == toml::find_or(v, "key", opt));
}
{
const typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
const typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
const value_type v{{"key", init}};
BOOST_TEST(init != opt);
BOOST_TEST(init == toml::find_or(v, "key", opt));
}
}
#undef TOML11_TEST_FIND_OR_EXACT
#define TOML11_TEST_FIND_OR_MOVE(toml_type, init_expr, opt_expr) \
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt opt_expr ; \
value_type v{{"key", init}}; \
BOOST_TEST(init != opt); \
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));\
BOOST_TEST(init == moved); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_move, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_MOVE(boolean, ( true), (false))
TOML11_TEST_FIND_OR_MOVE(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_MOVE(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_MOVE(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_MOVE(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_MOVE(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_MOVE(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_MOVE(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt {6,7,8,9,10};
value_type v{{"key", init}};
BOOST_TEST(init != opt);
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
BOOST_TEST(init == moved);
}
{
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
value_type v{{"key", init}};
BOOST_TEST(init != opt);
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
BOOST_TEST(init == moved);
}
}
#undef TOML11_TEST_FIND_OR_MOVE
#define TOML11_TEST_FIND_OR_MODIFY(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt1 opt_expr ; \
toml::toml_type opt2 opt_expr ; \
value_type v{{"key", init}}; \
BOOST_TEST(init != opt1); \
toml::find_or(v, "key", opt2) = opt1; \
BOOST_TEST(opt1 == toml::find<toml::toml_type>(v, "key"));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_modify, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_MODIFY(boolean, ( true), (false))
TOML11_TEST_FIND_OR_MODIFY(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_MODIFY(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_MODIFY(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_MODIFY(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_MODIFY(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_MODIFY(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_MODIFY(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt1{6,7,8,9,10};
typename value_type::array_type opt2{6,7,8,9,10};
BOOST_TEST(init != opt1);
value_type v{{"key", init}};
toml::find_or(v, "key", opt2) = opt1;
BOOST_TEST(opt1 == toml::find<typename value_type::array_type>(v, "key"));
}
{
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt1{{"key1", 54}, {"key2", "bar"}};
typename value_type::table_type opt2{{"key1", 54}, {"key2", "bar"}};
value_type v{{"key", init}};
BOOST_TEST(init != opt1);
toml::find_or(v, "key", opt2) = opt1;
BOOST_TEST(opt1 == toml::find<typename value_type::table_type>(v, "key"));
}
}
#undef TOML11_TEST_FIND_OR_MODIFY
#define TOML11_TEST_FIND_OR_FALLBACK(init_type, opt_type) \
{ \
using namespace test; \
value_type v(init_type); \
BOOST_TEST(opt_type == toml::find_or(v, "key", opt_type));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_fallback, value_type, test_value_types)
{
const toml::boolean boolean (true);
const toml::integer integer (42);
const toml::floating floating (3.14);
const toml::string string ("foo");
const toml::local_time local_time (12, 30, 45);
const toml::local_date local_date (2019, toml::month_t::Apr, 1);
const toml::local_datetime local_datetime (
toml::local_date(2019, toml::month_t::Apr, 1),
toml::local_time(12, 30, 45));
const toml::offset_datetime offset_datetime(
toml::local_date(2019, toml::month_t::Apr, 1),
toml::local_time(12, 30, 45), toml::time_offset( 9, 0));
using array_type = typename value_type::array_type;
using table_type = typename value_type::table_type;
const array_type array{1, 2, 3, 4, 5};
const table_type table{{"key1", 42}, {"key2", "foo"}};
TOML11_TEST_FIND_OR_FALLBACK(boolean, integer );
TOML11_TEST_FIND_OR_FALLBACK(boolean, floating );
TOML11_TEST_FIND_OR_FALLBACK(boolean, string );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_time );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_date );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(boolean, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(boolean, array );
TOML11_TEST_FIND_OR_FALLBACK(boolean, table );
TOML11_TEST_FIND_OR_FALLBACK(integer, boolean );
TOML11_TEST_FIND_OR_FALLBACK(integer, floating );
TOML11_TEST_FIND_OR_FALLBACK(integer, string );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_time );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_date );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(integer, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(integer, array );
TOML11_TEST_FIND_OR_FALLBACK(integer, table );
TOML11_TEST_FIND_OR_FALLBACK(floating, boolean );
TOML11_TEST_FIND_OR_FALLBACK(floating, integer );
TOML11_TEST_FIND_OR_FALLBACK(floating, string );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_time );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_date );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(floating, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(floating, array );
TOML11_TEST_FIND_OR_FALLBACK(floating, table );
TOML11_TEST_FIND_OR_FALLBACK(string, boolean );
TOML11_TEST_FIND_OR_FALLBACK(string, integer );
TOML11_TEST_FIND_OR_FALLBACK(string, floating );
TOML11_TEST_FIND_OR_FALLBACK(string, local_time );
TOML11_TEST_FIND_OR_FALLBACK(string, local_date );
TOML11_TEST_FIND_OR_FALLBACK(string, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(string, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(string, array );
TOML11_TEST_FIND_OR_FALLBACK(string, table );
TOML11_TEST_FIND_OR_FALLBACK(local_time, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_time, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_time, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_time, string );
TOML11_TEST_FIND_OR_FALLBACK(local_time, local_date );
TOML11_TEST_FIND_OR_FALLBACK(local_time, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(local_time, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_time, array );
TOML11_TEST_FIND_OR_FALLBACK(local_time, table );
TOML11_TEST_FIND_OR_FALLBACK(local_date, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_date, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_date, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_date, string );
TOML11_TEST_FIND_OR_FALLBACK(local_date, local_time );
TOML11_TEST_FIND_OR_FALLBACK(local_date, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(local_date, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_date, array );
TOML11_TEST_FIND_OR_FALLBACK(local_date, table );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, string );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, local_time );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, local_date );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, array );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, table );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, boolean );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, integer );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, floating );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, string );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_time );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_date );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, array );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, table );
TOML11_TEST_FIND_OR_FALLBACK(array, boolean );
TOML11_TEST_FIND_OR_FALLBACK(array, integer );
TOML11_TEST_FIND_OR_FALLBACK(array, floating );
TOML11_TEST_FIND_OR_FALLBACK(array, string );
TOML11_TEST_FIND_OR_FALLBACK(array, local_time );
TOML11_TEST_FIND_OR_FALLBACK(array, local_date );
TOML11_TEST_FIND_OR_FALLBACK(array, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(array, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(array, table );
TOML11_TEST_FIND_OR_FALLBACK(table, boolean );
TOML11_TEST_FIND_OR_FALLBACK(table, integer );
TOML11_TEST_FIND_OR_FALLBACK(table, floating );
TOML11_TEST_FIND_OR_FALLBACK(table, string );
TOML11_TEST_FIND_OR_FALLBACK(table, local_time );
TOML11_TEST_FIND_OR_FALLBACK(table, local_date );
TOML11_TEST_FIND_OR_FALLBACK(table, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(table, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(table, array );
}
#undef TOML11_TEST_FIND_OR_FALLBACK
BOOST_AUTO_TEST_CASE(test_find_or_integer)
{
{
toml::value v{{"num", 42}};
BOOST_TEST(42u == toml::find_or(v, "num", 0u));
BOOST_TEST(0u == toml::find_or(v, "foo", 0u));
}
{
toml::value v{{"num", 42}};
const auto moved = toml::find_or(std::move(v), "num", 0u);
BOOST_TEST(42u == moved);
}
{
toml::value v{{"num", 42}};
const auto moved = toml::find_or(std::move(v), "foo", 0u);
BOOST_TEST(0u == moved);
}
}
BOOST_AUTO_TEST_CASE(test_find_or_floating)
{
{
toml::value v1{{"key", 42}};
toml::value v2{{"key", 3.14}};
BOOST_TEST(2.71f == toml::find_or(v1, "key", 2.71f));
const double ref(3.14);
BOOST_TEST(static_cast<float>(ref) == toml::find_or(v2, "key", 2.71f));
}
{
toml::value v1{{"key", 42}};
toml::value v2{{"key", 3.14}};
const auto moved1 = toml::find_or(std::move(v1), "key", 2.71f);
const auto moved2 = toml::find_or(std::move(v2), "key", 2.71f);
BOOST_TEST(2.71f == moved1);
const double ref(3.14);
BOOST_TEST(static_cast<float>(ref) == moved2);
}
}
BOOST_AUTO_TEST_CASE(test_find_or_string)
{
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key", 42}};
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_TEST("foobar" == toml::find_or(v1, "key", s1));
BOOST_TEST("bazqux" == toml::find_or(v2, "key", s1));
std::string& v1r = toml::find_or(v1, "key", s1);
std::string& s1r = toml::find_or(v2, "key", s1);
BOOST_TEST("foobar" == v1r);
BOOST_TEST("bazqux" == s1r);
BOOST_TEST("foobar" == toml::find_or(v1, "key", s2));
BOOST_TEST("bazqux" == toml::find_or(v2, "key", s2));
BOOST_TEST("foobar" == toml::find_or(std::move(v1), "key", std::move(s1)));
s1 = "bazqux"; // restoring moved value
BOOST_TEST("bazqux" == toml::find_or(std::move(v2), "key", std::move(s1)));
}
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key", 42}};
std::string s1("bazqux");
const auto moved1 = toml::find_or(std::move(v1), "key", s1);
const auto moved2 = toml::find_or(std::move(v2), "key", s1);
BOOST_TEST("foobar" == moved1);
BOOST_TEST("bazqux" == moved2);
}
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key", 42}};
std::string s1("bazqux");
std::string s2("bazqux");
const auto moved1 = toml::find_or(std::move(v1), "key", std::move(s1));
const auto moved2 = toml::find_or(std::move(v2), "key", std::move(s2));
BOOST_TEST("foobar" == moved1);
BOOST_TEST("bazqux" == moved2);
}
// string literal
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key",42}};
BOOST_TEST("foobar" == toml::find_or(v1, "key", "bazqux"));
BOOST_TEST("bazqux" == toml::find_or(v2, "key", "bazqux"));
const char* lit = "bazqux";
BOOST_TEST("foobar" == toml::find_or(v1, "key", lit));
BOOST_TEST("bazqux" == toml::find_or(v2, "key", lit));
}
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key",42}};
const auto moved1 = toml::find_or(std::move(v1), "key", "bazqux");
const auto moved2 = toml::find_or(std::move(v2), "key", "bazqux");
BOOST_TEST("foobar" == moved1);
BOOST_TEST("bazqux" == moved2);
}
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key",42}};
const char* lit = "bazqux";
const auto moved1 = toml::find_or(std::move(v1), "key", lit);
const auto moved2 = toml::find_or(std::move(v2), "key", lit);
BOOST_TEST("foobar" == moved1);
BOOST_TEST("bazqux" == moved2);
}
}
BOOST_AUTO_TEST_CASE(test_find_or_map)
{
using map_type = std::map<std::string, std::string>;
{
const toml::value v1{
{"key", {{"key", "value"}}}
};
const auto key = toml::find_or(v1, "key", map_type{});
const auto key2 = toml::find_or(v1, "key2", map_type{});
BOOST_TEST(!key.empty());
BOOST_TEST(key2.empty());
BOOST_TEST(key.size() == 1u);
BOOST_TEST(key.at("key") == "value");
}
{
toml::value v1{
{"key", {{"key", "value"}}}
};
const auto key = toml::find_or<map_type>(v1, "key", map_type{});
const auto key2 = toml::find_or<map_type>(v1, "key2", map_type{});
BOOST_TEST(!key.empty());
BOOST_TEST(key2.empty());
BOOST_TEST(key.size() == 1u);
BOOST_TEST(key.at("key") == "value");
}
{
toml::value v1{
{"key", {{"key", "value"}}}
};
toml::value v2(v1);
const auto key = toml::find_or(std::move(v1), "key", map_type{});
const auto key2 = toml::find_or(std::move(v2), "key2", map_type{});
BOOST_TEST(!key.empty());
BOOST_TEST(key2.empty());
BOOST_TEST(key.size() == 1u);
BOOST_TEST(key.at("key") == "value");
}
{
toml::value v1{
{"key", {{"key", "value"}}}
};
toml::value v2(v1);
const auto key = toml::find_or<map_type>(std::move(v1), "key", map_type{});
const auto key2 = toml::find_or<map_type>(std::move(v2), "key2", map_type{});
BOOST_TEST(!key.empty());
BOOST_TEST(key2.empty());
BOOST_TEST(key.size() == 1u);
BOOST_TEST(key.at("key") == "value");
}
}

View File

@@ -0,0 +1,401 @@
#define BOOST_TEST_MODULE "test_find_or_recursive"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
#include <tuple>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <string_view>
#endif
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
>;
namespace test
{
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::vector<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::deque<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::list<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits,
typename Key, typename Value, typename Comp, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const std::map<Key, Value, Comp, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
os << ']';
return os;
}
template<typename charT, typename traits,
typename Key, typename Value, typename Hash, typename Eq, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const std::unordered_map<Key, Value, Hash, Eq, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
os << ']';
return os;
}
} // test
#define TOML11_TEST_FIND_OR_EXACT(toml_type, init_expr, opt_expr) \
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
const toml::toml_type opt opt_expr ; \
const value_type v{{"key1", value_type{{"key2", init}} }};\
BOOST_TEST(init != opt); \
BOOST_TEST(init == toml::find_or(v, "key1", "key2", opt));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_exact, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_EXACT(boolean, ( true), (false))
TOML11_TEST_FIND_OR_EXACT(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_EXACT(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_EXACT(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_EXACT(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_EXACT(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_EXACT(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_EXACT(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
const typename value_type::array_type init{1,2,3,4,5};
const typename value_type::array_type opt {6,7,8,9,10};
const value_type v{{"key", init}};
BOOST_TEST(init != opt);
BOOST_TEST(init == toml::find_or(v, "key", opt));
}
{
const typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
const typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
const value_type v{{"key", init}};
BOOST_TEST(init != opt);
BOOST_TEST(init == toml::find_or(v, "key", opt));
}
}
#undef TOML11_TEST_FIND_OR_EXACT
#define TOML11_TEST_FIND_OR_MOVE(toml_type, init_expr, opt_expr) \
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt opt_expr ; \
value_type v{{"key1", value_type{{"key2", init}} }}; \
BOOST_TEST(init != opt); \
const auto moved = toml::find_or(std::move(v), "key1", "key2", std::move(opt));\
BOOST_TEST(init == moved); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_move, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_MOVE(boolean, ( true), (false))
TOML11_TEST_FIND_OR_MOVE(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_MOVE(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_MOVE(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_MOVE(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_MOVE(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_MOVE(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_MOVE(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt {6,7,8,9,10};
value_type v{{"key", init}};
BOOST_TEST(init != opt);
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
BOOST_TEST(init == moved);
}
{
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
value_type v{{"key", init}};
BOOST_TEST(init != opt);
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
BOOST_TEST(init == moved);
}
}
#undef TOML11_TEST_FIND_OR_MOVE
#define TOML11_TEST_FIND_OR_MODIFY(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt1 opt_expr ; \
toml::toml_type opt2 opt_expr ; \
value_type v{{"key1", value_type{{"key2", init}} }}; \
BOOST_TEST(init != opt1); \
toml::find_or(v, "key1", "key2", opt2) = opt1; \
BOOST_TEST(opt1 == toml::find<toml::toml_type>(v, "key1", "key2"));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_modify, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_MODIFY(boolean, ( true), (false))
TOML11_TEST_FIND_OR_MODIFY(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_MODIFY(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_MODIFY(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_MODIFY(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_MODIFY(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_MODIFY(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_MODIFY(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt1{6,7,8,9,10};
typename value_type::array_type opt2{6,7,8,9,10};
BOOST_TEST(init != opt1);
value_type v{{"key", init}};
toml::find_or(v, "key", opt2) = opt1;
BOOST_TEST(opt1 == toml::find<typename value_type::array_type>(v, "key"));
}
{
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt1{{"key1", 54}, {"key2", "bar"}};
typename value_type::table_type opt2{{"key1", 54}, {"key2", "bar"}};
value_type v{{"key", init}};
BOOST_TEST(init != opt1);
toml::find_or(v, "key", opt2) = opt1;
BOOST_TEST(opt1 == toml::find<typename value_type::table_type>(v, "key"));
}
}
#undef TOML11_TEST_FIND_OR_MODIFY
#define TOML11_TEST_FIND_OR_FALLBACK(init_type, opt_type) \
{ \
using namespace test; \
value_type v1{{"key1", value_type{{"key3", "foo"}}}}; \
BOOST_TEST(opt_type == toml::find_or(v1, "key1", "key2", opt_type));\
value_type v2{{"key1", "foo"}}; \
BOOST_TEST(opt_type == toml::find_or(v2, "key1", "key3", opt_type));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_fallback, value_type, test_value_types)
{
const toml::boolean boolean (true);
const toml::integer integer (42);
const toml::floating floating (3.14);
const toml::string string ("foo");
const toml::local_time local_time (12, 30, 45);
const toml::local_date local_date (2019, toml::month_t::Apr, 1);
const toml::local_datetime local_datetime (
toml::local_date(2019, toml::month_t::Apr, 1),
toml::local_time(12, 30, 45));
const toml::offset_datetime offset_datetime(
toml::local_date(2019, toml::month_t::Apr, 1),
toml::local_time(12, 30, 45), toml::time_offset( 9, 0));
using array_type = typename value_type::array_type;
using table_type = typename value_type::table_type;
const array_type array{1, 2, 3, 4, 5};
const table_type table{{"key1", 42}, {"key2", "foo"}};
TOML11_TEST_FIND_OR_FALLBACK(boolean, integer );
TOML11_TEST_FIND_OR_FALLBACK(boolean, floating );
TOML11_TEST_FIND_OR_FALLBACK(boolean, string );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_time );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_date );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(boolean, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(boolean, array );
TOML11_TEST_FIND_OR_FALLBACK(boolean, table );
TOML11_TEST_FIND_OR_FALLBACK(integer, boolean );
TOML11_TEST_FIND_OR_FALLBACK(integer, floating );
TOML11_TEST_FIND_OR_FALLBACK(integer, string );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_time );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_date );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(integer, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(integer, array );
TOML11_TEST_FIND_OR_FALLBACK(integer, table );
TOML11_TEST_FIND_OR_FALLBACK(floating, boolean );
TOML11_TEST_FIND_OR_FALLBACK(floating, integer );
TOML11_TEST_FIND_OR_FALLBACK(floating, string );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_time );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_date );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(floating, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(floating, array );
TOML11_TEST_FIND_OR_FALLBACK(floating, table );
TOML11_TEST_FIND_OR_FALLBACK(string, boolean );
TOML11_TEST_FIND_OR_FALLBACK(string, integer );
TOML11_TEST_FIND_OR_FALLBACK(string, floating );
TOML11_TEST_FIND_OR_FALLBACK(string, local_time );
TOML11_TEST_FIND_OR_FALLBACK(string, local_date );
TOML11_TEST_FIND_OR_FALLBACK(string, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(string, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(string, array );
TOML11_TEST_FIND_OR_FALLBACK(string, table );
TOML11_TEST_FIND_OR_FALLBACK(local_time, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_time, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_time, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_time, string );
TOML11_TEST_FIND_OR_FALLBACK(local_time, local_date );
TOML11_TEST_FIND_OR_FALLBACK(local_time, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(local_time, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_time, array );
TOML11_TEST_FIND_OR_FALLBACK(local_time, table );
TOML11_TEST_FIND_OR_FALLBACK(local_date, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_date, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_date, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_date, string );
TOML11_TEST_FIND_OR_FALLBACK(local_date, local_time );
TOML11_TEST_FIND_OR_FALLBACK(local_date, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(local_date, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_date, array );
TOML11_TEST_FIND_OR_FALLBACK(local_date, table );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, string );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, local_time );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, local_date );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, array );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, table );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, boolean );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, integer );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, floating );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, string );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_time );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_date );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, array );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, table );
TOML11_TEST_FIND_OR_FALLBACK(array, boolean );
TOML11_TEST_FIND_OR_FALLBACK(array, integer );
TOML11_TEST_FIND_OR_FALLBACK(array, floating );
TOML11_TEST_FIND_OR_FALLBACK(array, string );
TOML11_TEST_FIND_OR_FALLBACK(array, local_time );
TOML11_TEST_FIND_OR_FALLBACK(array, local_date );
TOML11_TEST_FIND_OR_FALLBACK(array, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(array, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(array, table );
TOML11_TEST_FIND_OR_FALLBACK(table, boolean );
TOML11_TEST_FIND_OR_FALLBACK(table, integer );
TOML11_TEST_FIND_OR_FALLBACK(table, floating );
TOML11_TEST_FIND_OR_FALLBACK(table, string );
TOML11_TEST_FIND_OR_FALLBACK(table, local_time );
TOML11_TEST_FIND_OR_FALLBACK(table, local_date );
TOML11_TEST_FIND_OR_FALLBACK(table, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(table, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(table, array );
}
#undef TOML11_TEST_FIND_OR_FALLBACK
struct move_only_type
{
explicit move_only_type(const std::string& n): name_(n) {}
void from_toml(const toml::value& v)
{
this->name_ = toml::find<std::string>(v, "name");
return;
}
move_only_type(): name_("default"){}
~move_only_type() = default;
move_only_type(move_only_type&&) = default;
move_only_type& operator=(move_only_type&&) = default;
move_only_type(const move_only_type&) = delete;
move_only_type& operator=(const move_only_type&) = delete;
bool operator==(const move_only_type& other) const noexcept {return this->name_ == other.name_;}
bool operator!=(const move_only_type& other) const noexcept {return this->name_ != other.name_;}
bool operator< (const move_only_type& other) const noexcept {return this->name_ < other.name_;}
bool operator<=(const move_only_type& other) const noexcept {return this->name_ <= other.name_;}
bool operator> (const move_only_type& other) const noexcept {return this->name_ > other.name_;}
bool operator>=(const move_only_type& other) const noexcept {return this->name_ >= other.name_;}
std::string name_;
};
std::ostream& operator<<(std::ostream& os, const move_only_type& mot)
{
os << mot.name_;
return os;
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_move_only, value_type, test_value_types)
{
const move_only_type ref("reference");
move_only_type opt("optional");
{
const value_type v{{"key1", value_type{{"key2", value_type{{"name", "reference"}} }} }};
BOOST_TEST(ref == toml::find_or(v, "key1", "key2", std::move(opt)));
}
}

View File

@@ -1,4 +1,4 @@
#define BOOST_TEST_MODULE "test_value"
#define BOOST_TEST_MODULE "test_format_error"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
@@ -6,6 +6,7 @@
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <iostream>
// to check it successfully compiles. it does not check the formatted string.

View File

@@ -1,63 +0,0 @@
#define BOOST_TEST_MODULE "test_from_toml"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
BOOST_AUTO_TEST_CASE(test_from_toml)
{
toml::boolean b = false;
toml::integer i = 0;
toml::floating f = 0.;
toml::string s;
toml::local_date dt;
toml::array a;
toml::table t;
{
toml::value v(true);
toml::from_toml(std::tie(b, i, f, s, dt, a, t), v);
BOOST_CHECK_EQUAL(b, true);
}
{
toml::value v(42);
toml::from_toml(std::tie(b, i, f, s, dt, a, t), v);
BOOST_CHECK_EQUAL(i, 42);
}
{
toml::value v(3.14);
toml::from_toml(std::tie(b, i, f, s, dt, a, t), v);
BOOST_CHECK_EQUAL(f, 3.14);
}
{
toml::value v("foo");
toml::from_toml(std::tie(b, i, f, s, dt, a, t), v);
BOOST_CHECK_EQUAL(s, "foo");
}
{
toml::value v(toml::local_date(2018, toml::month_t::Apr, 22));
toml::from_toml(std::tie(b, i, f, s, dt, a, t), v);
BOOST_CHECK(dt == toml::local_date(2018, toml::month_t::Apr, 22));
}
{
toml::array ref{toml::value(42), toml::value(54)};
toml::value v(ref);
toml::from_toml(std::tie(b, i, f, s, dt, a, t), v);
BOOST_CHECK(ref == a);
}
{
toml::table ref{{"key1", 42}, {"key2", 3.14}};
toml::value v(ref);
toml::from_toml(std::tie(b, i, f, s, dt, a, t), v);
BOOST_CHECK(ref == t);
}
}

View File

@@ -5,280 +5,414 @@
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/value.hpp>
#include <toml/get.hpp>
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
#include <tuple>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <string_view>
#endif
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
>;
BOOST_AUTO_TEST_CASE(test_get_exact)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
{
{
toml::value v(true);
BOOST_CHECK_EQUAL(true, toml::get<toml::boolean>(v));
value_type v(true);
BOOST_TEST(true == toml::get<toml::boolean>(v));
toml::get<toml::boolean>(v) = false;
BOOST_CHECK_EQUAL(false, toml::get<toml::boolean>(v));
BOOST_TEST(false == toml::get<toml::boolean>(v));
toml::boolean x = toml::get<toml::boolean>(std::move(v));
BOOST_TEST(false == x);
}
{
toml::value v(42);
BOOST_CHECK_EQUAL(toml::integer(42), toml::get<toml::integer>(v));
value_type v(42);
BOOST_TEST(toml::integer(42) == toml::get<toml::integer>(v));
toml::get<toml::integer>(v) = 54;
BOOST_CHECK_EQUAL(toml::integer(54), toml::get<toml::integer>(v));
BOOST_TEST(toml::integer(54) == toml::get<toml::integer>(v));
toml::integer x = toml::get<toml::integer>(std::move(v));
BOOST_TEST(toml::integer(54) == x);
}
{
toml::value v(3.14);
BOOST_CHECK_EQUAL(toml::floating(3.14), toml::get<toml::floating>(v));
value_type v(3.14);
BOOST_TEST(toml::floating(3.14) == toml::get<toml::floating>(v));
toml::get<toml::floating>(v) = 2.71;
BOOST_CHECK_EQUAL(toml::floating(2.71), toml::get<toml::floating>(v));
BOOST_TEST(toml::floating(2.71) == toml::get<toml::floating>(v));
toml::floating x = toml::get<toml::floating>(std::move(v));
BOOST_TEST(toml::floating(2.71) == x);
}
{
toml::value v("foo");
BOOST_CHECK_EQUAL(toml::string("foo", toml::string_t::basic),
value_type v("foo");
BOOST_TEST(toml::string("foo", toml::string_t::basic) ==
toml::get<toml::string>(v));
toml::get<toml::string>(v).str += "bar";
BOOST_CHECK_EQUAL(toml::string("foobar", toml::string_t::basic),
BOOST_TEST(toml::string("foobar", toml::string_t::basic) ==
toml::get<toml::string>(v));
toml::string x = toml::get<toml::string>(std::move(v));
BOOST_TEST(toml::string("foobar") == x);
}
{
toml::value v("foo", toml::string_t::literal);
BOOST_CHECK_EQUAL(toml::string("foo", toml::string_t::literal),
value_type v("foo", toml::string_t::literal);
BOOST_TEST(toml::string("foo", toml::string_t::literal) ==
toml::get<toml::string>(v));
toml::get<toml::string>(v).str += "bar";
BOOST_CHECK_EQUAL(toml::string("foobar", toml::string_t::literal),
BOOST_TEST(toml::string("foobar", toml::string_t::literal) ==
toml::get<toml::string>(v));
toml::string x = toml::get<toml::string>(std::move(v));
BOOST_TEST(toml::string("foobar", toml::string_t::literal) == x);
}
{
toml::local_date d(2018, toml::month_t::Apr, 22);
toml::value v(d);
BOOST_CHECK(d == toml::get<toml::local_date>(v));
value_type v(d);
BOOST_TEST(d == toml::get<toml::local_date>(v));
toml::get<toml::local_date>(v).year = 2017;
d.year = 2017;
BOOST_CHECK(d == toml::get<toml::local_date>(v));
BOOST_TEST(d == toml::get<toml::local_date>(v));
toml::local_date x = toml::get<toml::local_date>(std::move(v));
BOOST_TEST(d == x);
}
{
toml::local_time t(12, 30, 45);
toml::value v(t);
BOOST_CHECK(t == toml::get<toml::local_time>(v));
value_type v(t);
BOOST_TEST(t == toml::get<toml::local_time>(v));
toml::get<toml::local_time>(v).hour = 9;
t.hour = 9;
BOOST_CHECK(t == toml::get<toml::local_time>(v));
BOOST_TEST(t == toml::get<toml::local_time>(v));
toml::local_time x = toml::get<toml::local_time>(std::move(v));
BOOST_TEST(t == x);
}
{
toml::local_datetime dt(toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 30, 45));
toml::value v(dt);
BOOST_CHECK(dt == toml::get<toml::local_datetime>(v));
value_type v(dt);
BOOST_TEST(dt == toml::get<toml::local_datetime>(v));
toml::get<toml::local_datetime>(v).date.year = 2017;
dt.date.year = 2017;
BOOST_CHECK(dt == toml::get<toml::local_datetime>(v));
BOOST_TEST(dt == toml::get<toml::local_datetime>(v));
toml::local_datetime x = toml::get<toml::local_datetime>(std::move(v));
BOOST_TEST(dt == x);
}
{
toml::offset_datetime dt(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 30, 45)), toml::time_offset(9, 0));
toml::value v(dt);
BOOST_CHECK(dt == toml::get<toml::offset_datetime>(v));
value_type v(dt);
BOOST_TEST(dt == toml::get<toml::offset_datetime>(v));
toml::get<toml::offset_datetime>(v).date.year = 2017;
dt.date.year = 2017;
BOOST_CHECK(dt == toml::get<toml::offset_datetime>(v));
BOOST_TEST(dt == toml::get<toml::offset_datetime>(v));
toml::offset_datetime x = toml::get<toml::offset_datetime>(std::move(v));
BOOST_TEST(dt == x);
}
{
toml::array vec;
vec.push_back(toml::value(42));
vec.push_back(toml::value(54));
toml::value v(vec);
BOOST_CHECK(vec == toml::get<toml::array>(v));
using array_type = typename value_type::array_type;
array_type vec;
vec.push_back(value_type(42));
vec.push_back(value_type(54));
value_type v(vec);
BOOST_TEST(vec == toml::get<array_type>(v));
toml::get<toml::array>(v).push_back(toml::value(123));
vec.push_back(toml::value(123));
BOOST_CHECK(vec == toml::get<toml::array>(v));
toml::get<array_type>(v).push_back(value_type(123));
vec.push_back(value_type(123));
BOOST_TEST(vec == toml::get<array_type>(v));
array_type x = toml::get<array_type>(std::move(v));
BOOST_TEST(vec == x);
}
{
toml::table tab;
tab["key1"] = toml::value(42);
tab["key2"] = toml::value(3.14);
toml::value v(tab);
BOOST_CHECK(tab == toml::get<toml::table>(v));
using table_type = typename value_type::table_type;
table_type tab;
tab["key1"] = value_type(42);
tab["key2"] = value_type(3.14);
value_type v(tab);
BOOST_TEST(tab == toml::get<table_type>(v));
toml::get<toml::table>(v)["key3"] = toml::value(123);
tab["key3"] = toml::value(123);
BOOST_CHECK(tab == toml::get<toml::table>(v));
toml::get<table_type>(v)["key3"] = value_type(123);
tab["key3"] = value_type(123);
BOOST_TEST(tab == toml::get<table_type>(v));
table_type x = toml::get<table_type>(std::move(v));
BOOST_TEST(tab == x);
}
{
toml::value v1(42);
BOOST_CHECK(v1 == toml::get<toml::value>(v1));
value_type v1(42);
BOOST_TEST(v1 == toml::get<value_type>(v1));
toml::value v2(54);
toml::get<toml::value>(v1) = v2;
BOOST_CHECK(v2 == toml::get<toml::value>(v1));
value_type v2(54);
toml::get<value_type>(v1) = v2;
BOOST_TEST(v2 == toml::get<value_type>(v1));
value_type x = toml::get<value_type>(std::move(v1));
BOOST_TEST(v2 == x);
}
}
BOOST_AUTO_TEST_CASE(test_get_integer_type)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_integer_type, value_type, test_value_types)
{
{
toml::value v(42);
BOOST_CHECK_EQUAL(int(42), toml::get<int >(v));
BOOST_CHECK_EQUAL(short(42), toml::get<short >(v));
BOOST_CHECK_EQUAL(char(42), toml::get<char >(v));
BOOST_CHECK_EQUAL(unsigned(42), toml::get<unsigned >(v));
BOOST_CHECK_EQUAL(long(42), toml::get<long >(v));
BOOST_CHECK_EQUAL(std::int64_t(42), toml::get<std::int64_t >(v));
BOOST_CHECK_EQUAL(std::uint64_t(42), toml::get<std::uint64_t>(v));
BOOST_CHECK_EQUAL(std::int16_t(42), toml::get<std::int16_t >(v));
BOOST_CHECK_EQUAL(std::uint16_t(42), toml::get<std::uint16_t>(v));
value_type v(42);
BOOST_TEST(int(42) == toml::get<int >(v));
BOOST_TEST(short(42) == toml::get<short >(v));
BOOST_TEST(char(42) == toml::get<char >(v));
BOOST_TEST(unsigned(42) == toml::get<unsigned >(v));
BOOST_TEST(long(42) == toml::get<long >(v));
BOOST_TEST(std::int64_t(42) == toml::get<std::int64_t >(v));
BOOST_TEST(std::uint64_t(42) == toml::get<std::uint64_t>(v));
BOOST_TEST(std::int16_t(42) == toml::get<std::int16_t >(v));
BOOST_TEST(std::uint16_t(42) == toml::get<std::uint16_t>(v));
BOOST_TEST(std::uint16_t(42) == toml::get<std::uint16_t>(std::move(v)));
}
}
BOOST_AUTO_TEST_CASE(test_get_floating_type)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_floating_type, value_type, test_value_types)
{
{
toml::value v(3.14);
BOOST_CHECK_EQUAL(static_cast<float >(3.14), toml::get<float >(v));
BOOST_CHECK_EQUAL(static_cast<double >(3.14), toml::get<double >(v));
BOOST_CHECK_EQUAL(static_cast<long double>(3.14), toml::get<long double>(v));
value_type v(3.14);
const double ref(3.14);
BOOST_TEST(static_cast<float >(ref) == toml::get<float >(v));
BOOST_TEST( ref == toml::get<double >(v));
BOOST_TEST(static_cast<long double>(ref) == toml::get<long double>(v));
BOOST_TEST(static_cast<float >(ref) == toml::get<float>(std::move(v)));
}
}
BOOST_AUTO_TEST_CASE(test_get_string_type)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_string_type, value_type, test_value_types)
{
{
toml::value v("foo", toml::string_t::basic);
BOOST_CHECK_EQUAL("foo", toml::get<std::string>(v));
value_type v("foo", toml::string_t::basic);
BOOST_TEST("foo" == toml::get<std::string>(v));
toml::get<std::string>(v) += "bar";
BOOST_CHECK_EQUAL("foobar", toml::get<std::string>(v));
BOOST_TEST("foobar" == toml::get<std::string>(v));
const auto x = toml::get<std::string>(std::move(v));
BOOST_TEST("foobar" == x);
}
{
toml::value v("foo", toml::string_t::literal);
BOOST_CHECK_EQUAL("foo", toml::get<std::string>(v));
value_type v("foo", toml::string_t::literal);
BOOST_TEST("foo" == toml::get<std::string>(v));
toml::get<std::string>(v) += "bar";
BOOST_CHECK_EQUAL("foobar", toml::get<std::string>(v));
BOOST_TEST("foobar" == toml::get<std::string>(v));
const auto x = toml::get<std::string>(std::move(v));
BOOST_TEST("foobar" == x);
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
{
value_type v("foo", toml::string_t::basic);
BOOST_TEST("foo" == toml::get<std::string_view>(v));
}
{
value_type v("foo", toml::string_t::literal);
BOOST_TEST("foo" == toml::get<std::string_view>(v));
}
#endif
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
{
{
const value_type v{42, 54, 69, 72};
const std::vector<int> vec = toml::get<std::vector<int>>(v);
const std::list<short> lst = toml::get<std::list<short>>(v);
const std::deque<std::int64_t> deq = toml::get<std::deque<std::int64_t>>(v);
BOOST_TEST(42 == vec.at(0));
BOOST_TEST(54 == vec.at(1));
BOOST_TEST(69 == vec.at(2));
BOOST_TEST(72 == vec.at(3));
std::list<short>::const_iterator iter = lst.begin();
BOOST_TEST(static_cast<short>(42) == *(iter++));
BOOST_TEST(static_cast<short>(54) == *(iter++));
BOOST_TEST(static_cast<short>(69) == *(iter++));
BOOST_TEST(static_cast<short>(72) == *(iter++));
BOOST_TEST(static_cast<std::int64_t>(42) == deq.at(0));
BOOST_TEST(static_cast<std::int64_t>(54) == deq.at(1));
BOOST_TEST(static_cast<std::int64_t>(69) == deq.at(2));
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::get<std::array<int, 4>>(v);
BOOST_TEST(42 == ary.at(0));
BOOST_TEST(54 == ary.at(1));
BOOST_TEST(69 == ary.at(2));
BOOST_TEST(72 == ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::get<std::tuple<int, short, unsigned, long>>(v);
BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
const value_type p{3.14, 2.71};
std::pair<double, double> pr = toml::get<std::pair<double, double> >(p);
BOOST_TEST(3.14 == pr.first);
BOOST_TEST(2.71 == pr.second);
}
{
value_type v{42, 54, 69, 72};
const std::vector<int> vec = toml::get<std::vector<int>>(std::move(v));
BOOST_TEST(42 == vec.at(0));
BOOST_TEST(54 == vec.at(1));
BOOST_TEST(69 == vec.at(2));
BOOST_TEST(72 == vec.at(3));
}
{
value_type v{42, 54, 69, 72};
const std::deque<int> deq = toml::get<std::deque<int>>(std::move(v));
BOOST_TEST(42 == deq.at(0));
BOOST_TEST(54 == deq.at(1));
BOOST_TEST(69 == deq.at(2));
BOOST_TEST(72 == deq.at(3));
}
{
value_type v{42, 54, 69, 72};
const std::list<int> lst = toml::get<std::list<int>>(std::move(v));
std::list<int>::const_iterator iter = lst.begin();
BOOST_TEST(42 == *(iter++));
BOOST_TEST(54 == *(iter++));
BOOST_TEST(69 == *(iter++));
BOOST_TEST(72 == *(iter++));
}
{
value_type v{42, 54, 69, 72};
std::array<int, 4> ary = toml::get<std::array<int, 4>>(std::move(v));
BOOST_TEST(42 == ary.at(0));
BOOST_TEST(54 == ary.at(1));
BOOST_TEST(69 == ary.at(2));
BOOST_TEST(72 == ary.at(3));
}
{
value_type v{42, 54, 69, 72};
std::tuple<int, short, unsigned, long> tpl =
toml::get<std::tuple<int, short, unsigned, long>>(std::move(v));
BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
}
}
BOOST_AUTO_TEST_CASE(test_get_toml_array)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array_of_array, value_type, test_value_types)
{
toml::value v(toml::array(0));
toml::get<toml::array>(v).push_back(toml::value(42));
toml::get<toml::array>(v).push_back(toml::value(54));
toml::get<toml::array>(v).push_back(toml::value(69));
toml::get<toml::array>(v).push_back(toml::value(72));
{
const value_type v1{42, 54, 69, 72};
const value_type v2{"foo", "bar", "baz"};
const value_type v{v1, v2};
const std::vector<int> vec = toml::get<std::vector<int>>(v);
const std::list<short> lst = toml::get<std::list<short>>(v);
const std::deque<std::int64_t> deq = toml::get<std::deque<std::int64_t>>(v);
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::get<std::pair<std::vector<int>, std::vector<std::string>>>(v);
BOOST_CHECK_EQUAL(42, vec.at(0));
BOOST_CHECK_EQUAL(54, vec.at(1));
BOOST_CHECK_EQUAL(69, vec.at(2));
BOOST_CHECK_EQUAL(72, vec.at(3));
BOOST_TEST(p.first.size() == 4u);
BOOST_TEST(p.first.at(0) == 42);
BOOST_TEST(p.first.at(1) == 54);
BOOST_TEST(p.first.at(2) == 69);
BOOST_TEST(p.first.at(3) == 72);
std::list<short>::const_iterator iter = lst.begin();
BOOST_CHECK_EQUAL(static_cast<short>(42), *(iter++));
BOOST_CHECK_EQUAL(static_cast<short>(54), *(iter++));
BOOST_CHECK_EQUAL(static_cast<short>(69), *(iter++));
BOOST_CHECK_EQUAL(static_cast<short>(72), *(iter++));
BOOST_TEST(p.second.size() == 3u);
BOOST_TEST(p.second.at(0) == "foo");
BOOST_TEST(p.second.at(1) == "bar");
BOOST_TEST(p.second.at(2) == "baz");
BOOST_CHECK_EQUAL(static_cast<std::int64_t>(42), deq.at(0));
BOOST_CHECK_EQUAL(static_cast<std::int64_t>(54), deq.at(1));
BOOST_CHECK_EQUAL(static_cast<std::int64_t>(69), deq.at(2));
BOOST_CHECK_EQUAL(static_cast<std::int64_t>(72), deq.at(3));
std::tuple<std::vector<int>, std::vector<std::string>> t =
toml::get<std::tuple<std::vector<int>, std::vector<std::string>>>(v);
std::array<int, 4> ary = toml::get<std::array<int, 4>>(v);
BOOST_CHECK_EQUAL(static_cast<int>(42), ary.at(0));
BOOST_CHECK_EQUAL(static_cast<int>(54), ary.at(1));
BOOST_CHECK_EQUAL(static_cast<int>(69), ary.at(2));
BOOST_CHECK_EQUAL(static_cast<int>(72), ary.at(3));
BOOST_TEST(std::get<0>(t).at(0) == 42);
BOOST_TEST(std::get<0>(t).at(1) == 54);
BOOST_TEST(std::get<0>(t).at(2) == 69);
BOOST_TEST(std::get<0>(t).at(3) == 72);
std::tuple<int, short, unsigned, long> tpl =
toml::get<std::tuple<int, short, unsigned, long>>(v);
BOOST_CHECK_EQUAL(static_cast<int >(42), std::get<0>(tpl));
BOOST_CHECK_EQUAL(static_cast<short >(54), std::get<1>(tpl));
BOOST_CHECK_EQUAL(static_cast<unsigned>(69), std::get<2>(tpl));
BOOST_CHECK_EQUAL(static_cast<long >(72), std::get<3>(tpl));
BOOST_TEST(std::get<1>(t).at(0) == "foo");
BOOST_TEST(std::get<1>(t).at(1) == "bar");
BOOST_TEST(std::get<1>(t).at(2) == "baz");
}
{
const value_type v1{42, 54, 69, 72};
const value_type v2{"foo", "bar", "baz"};
value_type v{v1, v2};
toml::value p(toml::array{});
toml::get<toml::array>(p).push_back(toml::value(3.14));
toml::get<toml::array>(p).push_back(toml::value(2.71));
std::pair<double, double> pr = toml::get<std::pair<double, double> >(p);
BOOST_CHECK_EQUAL(3.14, pr.first);
BOOST_CHECK_EQUAL(2.71, pr.second);
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::get<std::pair<std::vector<int>, std::vector<std::string>>>(std::move(v));
BOOST_TEST(p.first.size() == 4u);
BOOST_TEST(p.first.at(0) == 42);
BOOST_TEST(p.first.at(1) == 54);
BOOST_TEST(p.first.at(2) == 69);
BOOST_TEST(p.first.at(3) == 72);
BOOST_TEST(p.second.size() == 3u);
BOOST_TEST(p.second.at(0) == "foo");
BOOST_TEST(p.second.at(1) == "bar");
BOOST_TEST(p.second.at(2) == "baz");
}
}
BOOST_AUTO_TEST_CASE(test_get_toml_array_of_array)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_table, value_type, test_value_types)
{
toml::value v1(toml::array{});
toml::get<toml::array>(v1).push_back(toml::value(42));
toml::get<toml::array>(v1).push_back(toml::value(54));
toml::get<toml::array>(v1).push_back(toml::value(69));
toml::get<toml::array>(v1).push_back(toml::value(72));
{
const value_type v1{
{"key1", 1},
{"key2", 2},
{"key3", 3},
{"key4", 4}
};
toml::value v2(toml::array{});
toml::get<toml::array>(v2).push_back(toml::value("foo"));
toml::get<toml::array>(v2).push_back(toml::value("bar"));
toml::get<toml::array>(v2).push_back(toml::value("baz"));
const auto v = toml::get<std::map<std::string, int>>(v1);
BOOST_TEST(v.at("key1") == 1);
BOOST_TEST(v.at("key2") == 2);
BOOST_TEST(v.at("key3") == 3);
BOOST_TEST(v.at("key4") == 4);
}
{
value_type v1{
{"key1", 1},
{"key2", 2},
{"key3", 3},
{"key4", 4}
};
const auto v = toml::get<std::map<std::string, int>>(std::move(v1));
BOOST_TEST(v.at("key1") == 1);
BOOST_TEST(v.at("key2") == 2);
BOOST_TEST(v.at("key3") == 3);
BOOST_TEST(v.at("key4") == 4);
}
toml::value v(toml::array(2));
toml::get<toml::array>(v).at(0) = v1;
toml::get<toml::array>(v).at(1) = v2;
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::get<std::pair<std::vector<int>, std::vector<std::string>>>(v);
BOOST_CHECK_EQUAL(p.first.at(0), 42);
BOOST_CHECK_EQUAL(p.first.at(1), 54);
BOOST_CHECK_EQUAL(p.first.at(2), 69);
BOOST_CHECK_EQUAL(p.first.at(3), 72);
BOOST_CHECK_EQUAL(p.second.at(0), "foo");
BOOST_CHECK_EQUAL(p.second.at(1), "bar");
BOOST_CHECK_EQUAL(p.second.at(2), "baz");
std::tuple<std::vector<int>, std::vector<std::string>> t =
toml::get<std::tuple<std::vector<int>, std::vector<std::string>>>(v);
BOOST_CHECK_EQUAL(std::get<0>(t).at(0), 42);
BOOST_CHECK_EQUAL(std::get<0>(t).at(1), 54);
BOOST_CHECK_EQUAL(std::get<0>(t).at(2), 69);
BOOST_CHECK_EQUAL(std::get<0>(t).at(3), 72);
BOOST_CHECK_EQUAL(std::get<1>(t).at(0), "foo");
BOOST_CHECK_EQUAL(std::get<1>(t).at(1), "bar");
BOOST_CHECK_EQUAL(std::get<1>(t).at(2), "baz");
}
BOOST_AUTO_TEST_CASE(test_get_toml_table)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_local_date, value_type, test_value_types)
{
toml::value v1(toml::table{
{"key1", 1},
{"key2", 2},
{"key3", 3},
{"key4", 4}
});
const auto v = toml::get<std::map<std::string, int>>(v1);
BOOST_CHECK_EQUAL(v.at("key1"), 1);
BOOST_CHECK_EQUAL(v.at("key2"), 2);
BOOST_CHECK_EQUAL(v.at("key3"), 3);
BOOST_CHECK_EQUAL(v.at("key4"), 4);
}
BOOST_AUTO_TEST_CASE(test_get_toml_local_date)
{
toml::value v1(toml::local_date{2018, toml::month_t::Apr, 1});
value_type v1(toml::local_date{2018, toml::month_t::Apr, 1});
const auto date = std::chrono::system_clock::to_time_t(
toml::get<std::chrono::system_clock::time_point>(v1));
@@ -291,20 +425,22 @@ BOOST_AUTO_TEST_CASE(test_get_toml_local_date)
t.tm_sec = 0;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_CHECK_EQUAL(c, date);
BOOST_TEST(c == date);
}
BOOST_AUTO_TEST_CASE(test_get_toml_local_time)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_local_time, value_type, test_value_types)
{
toml::value v1(toml::local_time{12, 30, 45});
value_type v1(toml::local_time{12, 30, 45});
const auto time = toml::get<std::chrono::seconds>(v1);
BOOST_CHECK(time == std::chrono::hours(12) +
std::chrono::minutes(30) + std::chrono::seconds(45));
const bool result = time == std::chrono::hours(12) +
std::chrono::minutes(30) +
std::chrono::seconds(45);
BOOST_TEST(result);
}
BOOST_AUTO_TEST_CASE(test_get_toml_local_datetime)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_local_datetime, value_type, test_value_types)
{
toml::value v1(toml::local_datetime(
value_type v1(toml::local_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 45}));
@@ -319,13 +455,13 @@ BOOST_AUTO_TEST_CASE(test_get_toml_local_datetime)
t.tm_sec = 45;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_CHECK_EQUAL(c, date);
BOOST_TEST(c == date);
}
BOOST_AUTO_TEST_CASE(test_get_toml_offset_datetime)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_offset_datetime, value_type, test_value_types)
{
{
toml::value v1(toml::offset_datetime(
value_type v1(toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{9, 0}));
@@ -337,18 +473,18 @@ BOOST_AUTO_TEST_CASE(test_get_toml_offset_datetime)
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tmp = std::gmtime(std::addressof(timet)); // XXX not threadsafe!
BOOST_CHECK(tmp);
BOOST_TEST(tmp);
const auto tm = *tmp;
BOOST_CHECK_EQUAL(tm.tm_year + 1900, 2018);
BOOST_CHECK_EQUAL(tm.tm_mon + 1, 4);
BOOST_CHECK_EQUAL(tm.tm_mday, 1);
BOOST_CHECK_EQUAL(tm.tm_hour, 3);
BOOST_CHECK_EQUAL(tm.tm_min, 30);
BOOST_CHECK_EQUAL(tm.tm_sec, 0);
BOOST_TEST(tm.tm_year + 1900 == 2018);
BOOST_TEST(tm.tm_mon + 1 == 4);
BOOST_TEST(tm.tm_mday == 1);
BOOST_TEST(tm.tm_hour == 3);
BOOST_TEST(tm.tm_min == 30);
BOOST_TEST(tm.tm_sec == 0);
}
{
toml::value v1(toml::offset_datetime(
value_type v1(toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{-8, 0}));
@@ -360,14 +496,14 @@ BOOST_AUTO_TEST_CASE(test_get_toml_offset_datetime)
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tmp = std::gmtime(std::addressof(timet)); // XXX not threadsafe!
BOOST_CHECK(tmp);
BOOST_TEST(tmp);
const auto tm = *tmp;
BOOST_CHECK_EQUAL(tm.tm_year + 1900, 2018);
BOOST_CHECK_EQUAL(tm.tm_mon + 1, 4);
BOOST_CHECK_EQUAL(tm.tm_mday, 1);
BOOST_CHECK_EQUAL(tm.tm_hour, 20);
BOOST_CHECK_EQUAL(tm.tm_min, 30);
BOOST_CHECK_EQUAL(tm.tm_sec, 0);
BOOST_TEST(tm.tm_year + 1900 == 2018);
BOOST_TEST(tm.tm_mon + 1 == 4);
BOOST_TEST(tm.tm_mday == 1);
BOOST_TEST(tm.tm_hour == 20);
BOOST_TEST(tm.tm_min == 30);
BOOST_TEST(tm.tm_sec == 0);
}
}

452
tests/test_get_or.cpp Normal file
View File

@@ -0,0 +1,452 @@
#define BOOST_TEST_MODULE "test_get_or"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
#include <tuple>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <string_view>
#endif
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
>;
namespace test
{
// to compare result values in BOOST_TEST().
//
// BOOST_TEST outputs the expected and actual values. Thus it includes the
// output stream operator inside. To compile it, we need operator<<s for
// containers to compare.
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::vector<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::deque<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::list<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits,
typename Key, typename Value, typename Comp, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const std::map<Key, Value, Comp, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
os << ']';
return os;
}
template<typename charT, typename traits,
typename Key, typename Value, typename Hash, typename Eq, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const std::unordered_map<Key, Value, Hash, Eq, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
os << ']';
return os;
}
} // test
#define TOML11_TEST_GET_OR_EXACT(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
const toml::toml_type opt opt_expr ; \
const value_type v(init); \
BOOST_TEST(init != opt); \
BOOST_TEST(init == toml::get_or(v, opt)); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_or_exact, value_type, test_value_types)
{
TOML11_TEST_GET_OR_EXACT(boolean, ( true), (false))
TOML11_TEST_GET_OR_EXACT(integer, ( 42), ( 54))
TOML11_TEST_GET_OR_EXACT(floating, ( 3.14), ( 2.71))
TOML11_TEST_GET_OR_EXACT(string, ("foo"), ("bar"))
TOML11_TEST_GET_OR_EXACT(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_GET_OR_EXACT(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_GET_OR_EXACT(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_GET_OR_EXACT(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
const typename value_type::array_type init{1,2,3,4,5};
const typename value_type::array_type opt {6,7,8,9,10};
const value_type v(init);
BOOST_TEST(init != opt);
BOOST_TEST(init == toml::get_or(v, opt));
}
{
const typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
const typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
const value_type v(init);
BOOST_TEST(init != opt);
BOOST_TEST(init == toml::get_or(v, opt));
}
}
#undef TOML11_TEST_GET_OR_EXACT
#define TOML11_TEST_GET_OR_MOVE_EXACT(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt opt_expr ; \
value_type v(init); \
BOOST_TEST(init != opt); \
const auto opt_ = toml::get_or(std::move(v), std::move(opt));\
BOOST_TEST(init == opt_); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_or_move, value_type, test_value_types)
{
TOML11_TEST_GET_OR_MOVE_EXACT(boolean, ( true), (false))
TOML11_TEST_GET_OR_MOVE_EXACT(integer, ( 42), ( 54))
TOML11_TEST_GET_OR_MOVE_EXACT(floating, ( 3.14), ( 2.71))
TOML11_TEST_GET_OR_MOVE_EXACT(string, ("foo"), ("bar"))
TOML11_TEST_GET_OR_MOVE_EXACT(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_GET_OR_MOVE_EXACT(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_GET_OR_MOVE_EXACT(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_GET_OR_MOVE_EXACT(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
const typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt {6,7,8,9,10};
value_type v(init);
BOOST_TEST(init != opt);
const auto opt_ = toml::get_or(std::move(v), std::move(opt));
BOOST_TEST(init == opt_);
}
{
const typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
value_type v(init);
BOOST_TEST(init != opt);
const auto opt_ = toml::get_or(std::move(v), std::move(opt));
BOOST_TEST(init == opt_);
}
}
#undef TOML11_TEST_GET_OR_MOVE_EXACT
#define TOML11_TEST_GET_OR_MODIFY(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt1 opt_expr ; \
toml::toml_type opt2 opt_expr ; \
value_type v(init); \
BOOST_TEST(init != opt1); \
toml::get_or(v, opt2) = opt1; \
BOOST_TEST(opt1 == toml::get<toml::toml_type>(v)); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_or_modify, value_type, test_value_types)
{
TOML11_TEST_GET_OR_MODIFY(boolean, ( true), (false))
TOML11_TEST_GET_OR_MODIFY(integer, ( 42), ( 54))
TOML11_TEST_GET_OR_MODIFY(floating, ( 3.14), ( 2.71))
TOML11_TEST_GET_OR_MODIFY(string, ("foo"), ("bar"))
TOML11_TEST_GET_OR_MODIFY(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_GET_OR_MODIFY(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_GET_OR_MODIFY(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_GET_OR_MODIFY(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt1{6,7,8,9,10};
typename value_type::array_type opt2{6,7,8,9,10};
BOOST_TEST(init != opt1);
value_type v(init);
toml::get_or(v, opt2) = opt1;
BOOST_TEST(opt1 == toml::get<typename value_type::array_type>(v));
}
{
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt1{{"key1", 54}, {"key2", "bar"}};
typename value_type::table_type opt2{{"key1", 54}, {"key2", "bar"}};
value_type v(init);
BOOST_TEST(init != opt1);
toml::get_or(v, opt2) = opt1;
BOOST_TEST(opt1 == toml::get<typename value_type::table_type>(v));
}
}
#undef TOML11_TEST_GET_OR_MODIFY
#define TOML11_TEST_GET_OR_FALLBACK(init_type, opt_type) \
{ \
using namespace test; \
value_type v(init_type); \
BOOST_TEST(opt_type == toml::get_or(v, opt_type));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_or_fallback, value_type, test_value_types)
{
const toml::boolean boolean (true);
const toml::integer integer (42);
const toml::floating floating (3.14);
const toml::string string ("foo");
const toml::local_time local_time (12, 30, 45);
const toml::local_date local_date (2019, toml::month_t::Apr, 1);
const toml::local_datetime local_datetime (
toml::local_date(2019, toml::month_t::Apr, 1),
toml::local_time(12, 30, 45));
const toml::offset_datetime offset_datetime(
toml::local_date(2019, toml::month_t::Apr, 1),
toml::local_time(12, 30, 45), toml::time_offset( 9, 0));
using array_type = typename value_type::array_type;
using table_type = typename value_type::table_type;
const array_type array{1, 2, 3, 4, 5};
const table_type table{{"key1", 42}, {"key2", "foo"}};
TOML11_TEST_GET_OR_FALLBACK(boolean, integer );
TOML11_TEST_GET_OR_FALLBACK(boolean, floating );
TOML11_TEST_GET_OR_FALLBACK(boolean, string );
TOML11_TEST_GET_OR_FALLBACK(boolean, local_time );
TOML11_TEST_GET_OR_FALLBACK(boolean, local_date );
TOML11_TEST_GET_OR_FALLBACK(boolean, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(boolean, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(boolean, array );
TOML11_TEST_GET_OR_FALLBACK(boolean, table );
TOML11_TEST_GET_OR_FALLBACK(integer, boolean );
TOML11_TEST_GET_OR_FALLBACK(integer, floating );
TOML11_TEST_GET_OR_FALLBACK(integer, string );
TOML11_TEST_GET_OR_FALLBACK(integer, local_time );
TOML11_TEST_GET_OR_FALLBACK(integer, local_date );
TOML11_TEST_GET_OR_FALLBACK(integer, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(integer, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(integer, array );
TOML11_TEST_GET_OR_FALLBACK(integer, table );
TOML11_TEST_GET_OR_FALLBACK(floating, boolean );
TOML11_TEST_GET_OR_FALLBACK(floating, integer );
TOML11_TEST_GET_OR_FALLBACK(floating, string );
TOML11_TEST_GET_OR_FALLBACK(floating, local_time );
TOML11_TEST_GET_OR_FALLBACK(floating, local_date );
TOML11_TEST_GET_OR_FALLBACK(floating, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(floating, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(floating, array );
TOML11_TEST_GET_OR_FALLBACK(floating, table );
TOML11_TEST_GET_OR_FALLBACK(string, boolean );
TOML11_TEST_GET_OR_FALLBACK(string, integer );
TOML11_TEST_GET_OR_FALLBACK(string, floating );
TOML11_TEST_GET_OR_FALLBACK(string, local_time );
TOML11_TEST_GET_OR_FALLBACK(string, local_date );
TOML11_TEST_GET_OR_FALLBACK(string, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(string, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(string, array );
TOML11_TEST_GET_OR_FALLBACK(string, table );
TOML11_TEST_GET_OR_FALLBACK(local_time, boolean );
TOML11_TEST_GET_OR_FALLBACK(local_time, integer );
TOML11_TEST_GET_OR_FALLBACK(local_time, floating );
TOML11_TEST_GET_OR_FALLBACK(local_time, string );
TOML11_TEST_GET_OR_FALLBACK(local_time, local_date );
TOML11_TEST_GET_OR_FALLBACK(local_time, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(local_time, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(local_time, array );
TOML11_TEST_GET_OR_FALLBACK(local_time, table );
TOML11_TEST_GET_OR_FALLBACK(local_date, boolean );
TOML11_TEST_GET_OR_FALLBACK(local_date, integer );
TOML11_TEST_GET_OR_FALLBACK(local_date, floating );
TOML11_TEST_GET_OR_FALLBACK(local_date, string );
TOML11_TEST_GET_OR_FALLBACK(local_date, local_time );
TOML11_TEST_GET_OR_FALLBACK(local_date, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(local_date, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(local_date, array );
TOML11_TEST_GET_OR_FALLBACK(local_date, table );
TOML11_TEST_GET_OR_FALLBACK(local_datetime, boolean );
TOML11_TEST_GET_OR_FALLBACK(local_datetime, integer );
TOML11_TEST_GET_OR_FALLBACK(local_datetime, floating );
TOML11_TEST_GET_OR_FALLBACK(local_datetime, string );
TOML11_TEST_GET_OR_FALLBACK(local_datetime, local_time );
TOML11_TEST_GET_OR_FALLBACK(local_datetime, local_date );
TOML11_TEST_GET_OR_FALLBACK(local_datetime, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(local_datetime, array );
TOML11_TEST_GET_OR_FALLBACK(local_datetime, table );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, boolean );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, integer );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, floating );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, string );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, local_time );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, local_date );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, array );
TOML11_TEST_GET_OR_FALLBACK(offset_datetime, table );
TOML11_TEST_GET_OR_FALLBACK(array, boolean );
TOML11_TEST_GET_OR_FALLBACK(array, integer );
TOML11_TEST_GET_OR_FALLBACK(array, floating );
TOML11_TEST_GET_OR_FALLBACK(array, string );
TOML11_TEST_GET_OR_FALLBACK(array, local_time );
TOML11_TEST_GET_OR_FALLBACK(array, local_date );
TOML11_TEST_GET_OR_FALLBACK(array, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(array, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(array, table );
TOML11_TEST_GET_OR_FALLBACK(table, boolean );
TOML11_TEST_GET_OR_FALLBACK(table, integer );
TOML11_TEST_GET_OR_FALLBACK(table, floating );
TOML11_TEST_GET_OR_FALLBACK(table, string );
TOML11_TEST_GET_OR_FALLBACK(table, local_time );
TOML11_TEST_GET_OR_FALLBACK(table, local_date );
TOML11_TEST_GET_OR_FALLBACK(table, local_datetime );
TOML11_TEST_GET_OR_FALLBACK(table, offset_datetime);
TOML11_TEST_GET_OR_FALLBACK(table, array );
}
#undef TOML11_TEST_GET_OR_FALLBACK
BOOST_AUTO_TEST_CASE(test_get_or_integer)
{
{
toml::value v1(42);
toml::value v2(3.14);
BOOST_TEST(42u == toml::get_or(v1, 0u));
BOOST_TEST(0u == toml::get_or(v2, 0u));
}
{
toml::value v1(42);
toml::value v2(3.14);
BOOST_TEST(42u == toml::get_or(std::move(v1), 0u));
BOOST_TEST(0u == toml::get_or(std::move(v2), 0u));
}
}
BOOST_AUTO_TEST_CASE(test_get_or_floating)
{
{
toml::value v1(42);
toml::value v2(3.14);
BOOST_TEST(2.71f == toml::get_or(v1, 2.71f));
BOOST_TEST(static_cast<float>(v2.as_floating()) == toml::get_or(v2, 2.71f));
}
{
toml::value v1(42);
toml::value v2(3.14);
BOOST_TEST(2.71f == toml::get_or(std::move(v1), 2.71f));
BOOST_TEST(static_cast<float>(3.14) == toml::get_or(std::move(v2), 2.71f));
}
}
BOOST_AUTO_TEST_CASE(test_get_or_string)
{
{
toml::value v1("foobar");
toml::value v2(42);
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_TEST("foobar" == toml::get_or(v1, s1));
BOOST_TEST("bazqux" == toml::get_or(v2, s1));
std::string& v1r = toml::get_or(v1, s1);
std::string& s1r = toml::get_or(v2, s1);
BOOST_TEST("foobar" == v1r);
BOOST_TEST("bazqux" == s1r);
BOOST_TEST("foobar" == toml::get_or(v1, s2));
BOOST_TEST("bazqux" == toml::get_or(v2, s2));
BOOST_TEST("foobar" == toml::get_or(v1, std::move(s1)));
BOOST_TEST("bazqux" == toml::get_or(v2, std::move(s1)));
}
{
toml::value v1("foobar");
toml::value v2(42);
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_TEST("foobar" == toml::get_or(std::move(v1), s1));
BOOST_TEST("bazqux" == toml::get_or(std::move(v2), s1));
}
{
toml::value v1("foobar");
toml::value v2(42);
BOOST_TEST("foobar" == toml::get_or(v1, "bazqux"));
BOOST_TEST("bazqux" == toml::get_or(v2, "bazqux"));
const char* lit = "bazqux";
BOOST_TEST("foobar" == toml::get_or(v1, lit));
BOOST_TEST("bazqux" == toml::get_or(v2, lit));
}
{
toml::value v1("foobar");
toml::value v2(42);
BOOST_TEST("foobar" == toml::get_or(std::move(v1), "bazqux"));
BOOST_TEST("bazqux" == toml::get_or(std::move(v2), "bazqux"));
}
{
toml::value v1("foobar");
toml::value v2(42);
const char* lit = "bazqux";
BOOST_TEST("foobar" == toml::get_or(v1, lit));
BOOST_TEST("bazqux" == toml::get_or(v2, lit));
}
}

View File

@@ -1,254 +0,0 @@
#define BOOST_TEST_MODULE "test_get_or"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
BOOST_AUTO_TEST_CASE(test_find)
{
{
toml::value v(true);
bool thrown = false;
try
{
toml::find<toml::boolean>(v, "key");
}
catch(toml::type_error const& te)
{
thrown = true;
}
BOOST_CHECK(thrown);
}
{
toml::table v{{"num", 42}};
BOOST_CHECK_EQUAL(42, toml::find<int>(v, "num"));
toml::find<toml::integer>(v, "num") = 54;
BOOST_CHECK_EQUAL(54, toml::find<int>(v, "num"));
}
{
toml::value v = toml::table{{"num", 42}};
BOOST_CHECK_EQUAL(42, toml::find<int>(v, "num"));
toml::find<toml::integer>(v, "num") = 54;
BOOST_CHECK_EQUAL(54, toml::find<int>(v, "num"));
}
}
BOOST_AUTO_TEST_CASE(test_get_or)
{
// requires conversion int -> uint
{
toml::value v1(42);
toml::value v2(3.14);
BOOST_CHECK_EQUAL(42u, toml::get_or(v1, 0u));
BOOST_CHECK_EQUAL(0u, toml::get_or(v2, 0u));
}
// exact toml type
{
toml::value v1(42);
toml::value v2(3.14);
toml::integer opt(0);
BOOST_CHECK_EQUAL(42, toml::get_or(v1, opt));
BOOST_CHECK_EQUAL(0, toml::get_or(v2, opt));
toml::value v3("foobar");
toml::string s("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::get_or(v3, s));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v1, s));
}
// std::string
{
toml::value v1("foobar");
toml::value v2(42);
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, s1));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, s1));
std::string& v1r = toml::get_or(v1, s1);
std::string& s1r = toml::get_or(v2, s1);
BOOST_CHECK_EQUAL("foobar", v1r);
BOOST_CHECK_EQUAL("bazqux", s1r);
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, s2));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, s2));
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, std::move(s1)));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, std::move(s1)));
}
// string literal
{
toml::value v1("foobar");
toml::value v2(42);
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, "bazqux"));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, "bazqux"));
const char* lit = "bazqux";
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, lit));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, lit));
}
}
BOOST_AUTO_TEST_CASE(test_find_or)
{
// ========================================================================
// pass toml::value
//
// requires conversion int -> uint
{
toml::table v{{"num", 42}};
BOOST_CHECK_EQUAL(42u, toml::find_or(v, "num", 0u));
BOOST_CHECK_EQUAL(0u, toml::find_or(v, "foo", 0u));
}
// exact toml type
{
toml::table v1{{"key", 42 }};
toml::table v2{{"key", 3.14}};
toml::table v3{{"not", "key"}};
toml::integer opt(0);
BOOST_CHECK_EQUAL(42, toml::find_or(v1, "key", opt));
BOOST_CHECK_EQUAL(0, toml::find_or(v2, "key", opt));
BOOST_CHECK_EQUAL(0, toml::find_or(v3, "key", opt));
toml::table v4{{"str", "foobar"}};
toml::string s("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::find_or(v4, "str", s));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v1, "str", s));
}
// std::string
{
toml::table v1{{"key", "foobar"}};
toml::table v2{{"key", 42}};
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s1));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s1));
std::string& v1r = toml::find_or(v1, "key", s1);
std::string& s1r = toml::find_or(v2, "key", s1);
BOOST_CHECK_EQUAL("foobar", v1r);
BOOST_CHECK_EQUAL("bazqux", s1r);
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s2));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s2));
BOOST_CHECK_EQUAL("foobar", toml::find_or(std::move(v1), "key", std::move(s1)));
s1 = "bazqux"; // restoring moved value
BOOST_CHECK_EQUAL("bazqux", toml::find_or(std::move(v2), "key", std::move(s1)));
}
// string literal
{
toml::table v1{{"key", "foobar"}};
toml::table v2{{"key",42}};
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", "bazqux"));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", "bazqux"));
const char* lit = "bazqux";
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", lit));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", lit));
}
// ========================================================================
// pass toml::value
//
// requires conversion int -> uint
{
toml::table v = toml::table{{"num", 42}};
BOOST_CHECK_EQUAL(42u, toml::find_or(v, "num", 0u));
BOOST_CHECK_EQUAL(0u, toml::find_or(v, "foo", 0u));
}
// exact toml type
{
toml::value v1 = toml::table{{"key", 42 }};
toml::value v2 = toml::table{{"key", 3.14}};
toml::value v3 = toml::table{{"not", "key"}};
BOOST_CHECK_EQUAL(42, toml::find_or(v1, "key", toml::integer(0)));
BOOST_CHECK_EQUAL( 0, toml::find_or(v2, "key", toml::integer(0)));
BOOST_CHECK_EQUAL( 0, toml::find_or(v3, "key", toml::integer(0)));
toml::value v4 = toml::table{{"str", "foobar"}};
toml::string s("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::find_or(v4, "str", s));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v1, "str", s));
}
// std::string
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key", 42}};
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s1));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s1));
std::string& v1r = toml::find_or(v1, "key", s1);
std::string& s1r = toml::find_or(v2, "key", s1);
BOOST_CHECK_EQUAL("foobar", v1r);
BOOST_CHECK_EQUAL("bazqux", s1r);
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s2));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s2));
BOOST_CHECK_EQUAL("foobar", toml::find_or(std::move(v1), "key", std::move(s1)));
s1 = "bazqux"; // restoring moved value
BOOST_CHECK_EQUAL("bazqux", toml::find_or(std::move(v2), "key", std::move(s1)));
}
// string literal
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key",42}};
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", "bazqux"));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", "bazqux"));
const char* lit = "bazqux";
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", lit));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", lit));
}
}
BOOST_AUTO_TEST_CASE(test_expect)
{
{
toml::value v1(42);
toml::value v2(3.14);
const auto v1_or_0 = toml::expect<int>(v1).unwrap_or(0);
const auto v2_or_0 = toml::expect<int>(v2).unwrap_or(0);
BOOST_CHECK_EQUAL(42, v1_or_0);
BOOST_CHECK_EQUAL( 0, v2_or_0);
const auto v1_or_none = toml::expect<int>(v1).map([](int i){return std::to_string(i);}).unwrap_or(std::string("none"));
const auto v2_or_none = toml::expect<int>(v2).map([](int i){return std::to_string(i);}).unwrap_or(std::string("none"));
BOOST_CHECK_EQUAL("42", v1_or_none);
BOOST_CHECK_EQUAL("none", v2_or_none);
}
}

View File

@@ -8,19 +8,19 @@
do { \
const std::string token (tkn); \
const std::string expected(expct); \
toml::detail::location<std::string> loc("test", token); \
toml::detail::location loc("test", token); \
const auto result = lxr::invoke(loc); \
BOOST_CHECK(result.is_ok()); \
BOOST_TEST(result.is_ok()); \
if(result.is_ok()){ \
const auto region = result.unwrap(); \
BOOST_CHECK_EQUAL(region.str(), expected); \
BOOST_CHECK_EQUAL(region.str().size(), expected.size()); \
BOOST_CHECK_EQUAL(static_cast<std::size_t>(std::distance( \
loc.begin(), loc.iter())), region.size()); \
const auto region = result.unwrap(); \
BOOST_TEST(region.str() == expected); \
BOOST_TEST(region.str().size() == expected.size()); \
BOOST_TEST(static_cast<std::size_t>(std::distance( \
loc.begin(), loc.iter())) == region.size()); \
} else { \
std::cerr << "lexer " << lxr::pattern() << " failed with input `"; \
std::cerr << token << "`. expected `" << expected << "`\n"; \
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
std::cerr << "lexer failed with input `"; \
std::cerr << token << "`. expected `" << expected << "`\n"; \
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
} \
} while(false); \
/**/
@@ -28,8 +28,9 @@ do { \
#define TOML11_TEST_LEX_REJECT(lxr, tkn) \
do { \
const std::string token (tkn); \
toml::detail::location<std::string> loc("test", token); \
toml::detail::location loc("test", token); \
const auto result = lxr::invoke(loc); \
BOOST_CHECK(result.is_err()); \
BOOST_CHECK(loc.begin() == loc.iter()); \
BOOST_TEST(result.is_err()); \
const bool loc_same = (loc.begin() == loc.iter()); \
BOOST_TEST(loc_same); \
} while(false); /**/

View File

@@ -35,27 +35,35 @@ BOOST_AUTO_TEST_CASE(test_fractional_invalid)
BOOST_AUTO_TEST_CASE(test_exponential_valid)
{
TOML11_TEST_LEX_ACCEPT(lex_float, "1e10", "1e10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1e+10", "1e+10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1e-10", "1e-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "+1e10", "+1e10");
TOML11_TEST_LEX_ACCEPT(lex_float, "+1e+10", "+1e+10");
TOML11_TEST_LEX_ACCEPT(lex_float, "+1e-10", "+1e-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "-1e10", "-1e10");
TOML11_TEST_LEX_ACCEPT(lex_float, "-1e+10", "-1e+10");
TOML11_TEST_LEX_ACCEPT(lex_float, "-1e-10", "-1e-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "123e-10", "123e-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1E10", "1E10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1E+10", "1E+10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1E-10", "1E-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "123E-10", "123E-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-10", "1_2_3E-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1e10", "1e10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1e+10", "1e+10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1e-10", "1e-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "+1e10", "+1e10");
TOML11_TEST_LEX_ACCEPT(lex_float, "+1e+10", "+1e+10");
TOML11_TEST_LEX_ACCEPT(lex_float, "+1e-10", "+1e-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "-1e10", "-1e10");
TOML11_TEST_LEX_ACCEPT(lex_float, "-1e+10", "-1e+10");
TOML11_TEST_LEX_ACCEPT(lex_float, "-1e-10", "-1e-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "123e-10", "123e-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1E10", "1E10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1E+10", "1E+10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1E-10", "1E-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "123E-10", "123E-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-10", "1_2_3E-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-1_0", "1_2_3E-1_0");
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-01", "1_2_3E-01");
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-0_1", "1_2_3E-0_1");
#endif
}
BOOST_AUTO_TEST_CASE(test_exponential_invalid)
{
TOML11_TEST_LEX_ACCEPT(lex_float, "1e1E0", "1e1");
// accept partially
TOML11_TEST_LEX_ACCEPT(lex_float, "1e1E0", "1e1");
TOML11_TEST_LEX_ACCEPT(lex_float, "1E1e0", "1E1");
}
@@ -64,12 +72,26 @@ BOOST_AUTO_TEST_CASE(test_both_valid)
TOML11_TEST_LEX_ACCEPT(lex_float, "6.02e23", "6.02e23");
TOML11_TEST_LEX_ACCEPT(lex_float, "6.02e+23", "6.02e+23");
TOML11_TEST_LEX_ACCEPT(lex_float, "1.112_650_06e-17", "1.112_650_06e-17");
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_LEX_ACCEPT(lex_float, "1.0e-07", "1.0e-07");
#endif
}
BOOST_AUTO_TEST_CASE(test_both_invalid)
{
TOML11_TEST_LEX_ACCEPT(lex_float, "1e1.0", "1e1");
TOML11_TEST_LEX_REJECT(lex_float, "01e1.0");
// accept partially
TOML11_TEST_LEX_ACCEPT(lex_float, "1e1.0", "1e1");
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_LEX_ACCEPT(lex_float, "1.0e_01", "1.0");
TOML11_TEST_LEX_ACCEPT(lex_float, "1.0e0__1", "1.0e0");
#endif
}
BOOST_AUTO_TEST_CASE(test_special_floating_point)

View File

@@ -18,12 +18,11 @@ BOOST_AUTO_TEST_CASE(test_quoted_key)
{
TOML11_TEST_LEX_ACCEPT(lex_key, "\"127.0.0.1\"", "\"127.0.0.1\"");
TOML11_TEST_LEX_ACCEPT(lex_key, "\"character encoding\"", "\"character encoding\"");
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
// UTF-8 codepoint of characters that looks like "key" written upside down
TOML11_TEST_LEX_ACCEPT(lex_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"",
"\"\xCA\x8E\xC7\x9D\xCA\x9E\"");
#else
TOML11_TEST_LEX_ACCEPT(lex_key, u8"\"ʎǝʞ\"", u8"\"ʎǝʞ\"");
#endif
TOML11_TEST_LEX_ACCEPT(lex_key, "'key2'", "'key2'");
TOML11_TEST_LEX_ACCEPT(lex_key, "'quoted \"value\"'", "'quoted \"value\"'");
}

View File

@@ -31,15 +31,9 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
"\"192.168.1.1\"",
"\"192.168.1.1\"");
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"",
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"");
#else
TOML11_TEST_LEX_ACCEPT(lex_string,
u8"\"中国\"",
u8"\"中国\"");
#endif
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"", // UTF-8 string (means "China" in
"\"\xE4\xB8\xAD\xE5\x9B\xBD\""); // Chinese characters)
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"You'll hate me after this - #\"",
@@ -57,6 +51,22 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"");
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"");
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"");
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"");
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"");
}
BOOST_AUTO_TEST_CASE(test_literal_string)
@@ -83,4 +93,16 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
TOML11_TEST_LEX_ACCEPT(lex_string,
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''");
TOML11_TEST_LEX_ACCEPT(lex_string,
"''''That's still pointless', she said.'''",
"''''That's still pointless', she said.'''");
TOML11_TEST_LEX_ACCEPT(lex_string,
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''");
TOML11_TEST_LEX_ACCEPT(lex_string,
"''''This,' she said, 'is just a pointless statement.''''",
"''''This,' she said, 'is just a pointless statement.''''");
}

View File

@@ -12,6 +12,170 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
{
using namespace toml::literals::toml_literals;
{
const toml::value r{{"a", 42}, {"b", "baz"}};
const toml::value v = R"(
a = 42
b = "baz"
)"_toml;
BOOST_TEST(r == v);
}
{
const toml::value r{
{"c", 3.14},
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = R"(
c = 3.14
[table]
a = 42
b = "baz"
)"_toml;
BOOST_TEST(r == v);
}
{
const toml::value r{
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = R"(
[table]
a = 42
b = "baz"
)"_toml;
BOOST_TEST(r == v);
}
{
const toml::value r{
{"array_of_tables", toml::array{toml::table{}}}
};
const toml::value v = R"(
[[array_of_tables]]
)"_toml;
BOOST_TEST(r == v);
}
}
BOOST_AUTO_TEST_CASE(test_value_as_literal)
{
using namespace toml::literals::toml_literals;
{
const toml::value v1 = "true"_toml;
const toml::value v2 = "false"_toml;
BOOST_TEST(v1.is_boolean());
BOOST_TEST(v2.is_boolean());
BOOST_TEST(toml::get<bool>(v1));
BOOST_TEST(!toml::get<bool>(v2));
}
{
const toml::value v1 = "123_456"_toml;
const toml::value v2 = "0b0010"_toml;
const toml::value v3 = "0xDEADBEEF"_toml;
BOOST_TEST(v1.is_integer());
BOOST_TEST(v2.is_integer());
BOOST_TEST(v3.is_integer());
BOOST_TEST(toml::get<toml::integer>(v1) == 123456);
BOOST_TEST(toml::get<toml::integer>(v2) == 2);
BOOST_TEST(toml::get<toml::integer>(v3) == 0xDEADBEEF);
}
{
const toml::value v1 = "3.1415"_toml;
const toml::value v2 = "6.02e+23"_toml;
BOOST_TEST(v1.is_floating());
BOOST_TEST(v2.is_floating());
BOOST_TEST(toml::get<double>(v1) == 3.1415, boost::test_tools::tolerance(0.00001));
BOOST_TEST(toml::get<double>(v2) == 6.02e23, boost::test_tools::tolerance(0.0001));
}
{
const toml::value v1 = R"("foo")"_toml;
const toml::value v2 = R"('foo')"_toml;
const toml::value v3 = R"("""foo""")"_toml;
const toml::value v4 = R"('''foo''')"_toml;
BOOST_TEST(v1.is_string());
BOOST_TEST(v2.is_string());
BOOST_TEST(v3.is_string());
BOOST_TEST(v4.is_string());
BOOST_TEST(toml::get<std::string>(v1) == "foo");
BOOST_TEST(toml::get<std::string>(v2) == "foo");
BOOST_TEST(toml::get<std::string>(v3) == "foo");
BOOST_TEST(toml::get<std::string>(v4) == "foo");
}
{
{
const toml::value v1 = R"([1,2,3])"_toml;
BOOST_TEST(v1.is_array());
const bool result = (toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3});
BOOST_TEST(result);
}
{
const toml::value v2 = R"([1,])"_toml;
BOOST_TEST(v2.is_array());
const bool result = (toml::get<std::vector<int>>(v2) == std::vector<int>{1});
BOOST_TEST(result);
}
{
const toml::value v3 = R"([[1,]])"_toml;
BOOST_TEST(v3.is_array());
const bool result = (toml::get<std::vector<int>>(toml::get<toml::array>(v3).front()) == std::vector<int>{1});
BOOST_TEST(result);
}
{
const toml::value v4 = R"([[1],])"_toml;
BOOST_TEST(v4.is_array());
const bool result = (toml::get<std::vector<int>>(toml::get<toml::array>(v4).front()) == std::vector<int>{1});
BOOST_TEST(result);
}
}
{
const toml::value v1 = R"({a = 42})"_toml;
BOOST_TEST(v1.is_table());
const bool result = toml::get<std::map<std::string,int>>(v1) ==
std::map<std::string,int>{{"a", 42}};
BOOST_TEST(result);
}
{
const toml::value v1 = "1979-05-27"_toml;
BOOST_TEST(v1.is_local_date());
BOOST_TEST(toml::get<toml::local_date>(v1) ==
toml::local_date(1979, toml::month_t::May, 27));
}
{
const toml::value v1 = "12:00:00"_toml;
BOOST_TEST(v1.is_local_time());
const bool result = toml::get<std::chrono::hours>(v1) == std::chrono::hours(12);
BOOST_TEST(result);
}
{
const toml::value v1 = "1979-05-27T07:32:00"_toml;
BOOST_TEST(v1.is_local_datetime());
BOOST_TEST(toml::get<toml::local_datetime>(v1) ==
toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0)));
}
{
const toml::value v1 = "1979-05-27T07:32:00Z"_toml;
BOOST_TEST(v1.is_offset_datetime());
BOOST_TEST(toml::get<toml::offset_datetime>(v1) ==
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
}
}
BOOST_AUTO_TEST_CASE(test_file_as_u8_literal)
{
using namespace toml::literals::toml_literals;
{
const toml::value r{{"a", 42}, {"b", "baz"}};
const toml::value v = u8R"(
@@ -19,7 +183,7 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
b = "baz"
)"_toml;
BOOST_CHECK_EQUAL(r, v);
BOOST_TEST(r == v);
}
{
const toml::value r{
@@ -33,11 +197,33 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
b = "baz"
)"_toml;
BOOST_CHECK_EQUAL(r, v);
BOOST_TEST(r == v);
}
{
const toml::value r{
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = u8R"(
[table]
a = 42
b = "baz"
)"_toml;
BOOST_TEST(r == v);
}
{
const toml::value r{
{"array_of_tables", toml::array{toml::table{}}}
};
const toml::value v = u8R"(
[[array_of_tables]]
)"_toml;
BOOST_TEST(r == v);
}
}
BOOST_AUTO_TEST_CASE(test_value_as_literal)
BOOST_AUTO_TEST_CASE(test_value_as_u8_literal)
{
using namespace toml::literals::toml_literals;
@@ -45,84 +231,109 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
const toml::value v1 = u8"true"_toml;
const toml::value v2 = u8"false"_toml;
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK(v2.is_boolean());
BOOST_CHECK(toml::get<bool>(v1));
BOOST_CHECK(!toml::get<bool>(v2));
BOOST_TEST(v1.is_boolean());
BOOST_TEST(v2.is_boolean());
BOOST_TEST(toml::get<bool>(v1));
BOOST_TEST(!toml::get<bool>(v2));
}
{
const toml::value v1 = u8"123_456"_toml;
const toml::value v2 = u8"0b0010"_toml;
const toml::value v3 = u8"0xDEADBEEF"_toml;
BOOST_CHECK(v1.is_integer());
BOOST_CHECK(v2.is_integer());
BOOST_CHECK(v3.is_integer());
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v1), 123456);
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v2), 2);
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v3), 0xDEADBEEF);
BOOST_TEST(v1.is_integer());
BOOST_TEST(v2.is_integer());
BOOST_TEST(v3.is_integer());
BOOST_TEST(toml::get<toml::integer>(v1) == 123456);
BOOST_TEST(toml::get<toml::integer>(v2) == 2);
BOOST_TEST(toml::get<toml::integer>(v3) == 0xDEADBEEF);
}
{
const toml::value v1 = u8"3.1415"_toml;
const toml::value v2 = u8"6.02e+23"_toml;
BOOST_CHECK(v1.is_float());
BOOST_CHECK(v2.is_float());
BOOST_CHECK_CLOSE(toml::get<double>(v1), 3.1415, 0.00001);
BOOST_CHECK_CLOSE(toml::get<double>(v2), 6.02e23, 0.0001);
BOOST_TEST(v1.is_floating());
BOOST_TEST(v2.is_floating());
BOOST_TEST(toml::get<double>(v1) == 3.1415, boost::test_tools::tolerance(0.00001));
BOOST_TEST(toml::get<double>(v2) == 6.02e23, boost::test_tools::tolerance(0.0001));
}
{
const toml::value v1 = u8R"("foo")"_toml;
const toml::value v2 = u8R"('foo')"_toml;
const toml::value v3 = u8R"("""foo""")"_toml;
const toml::value v4 = u8R"('''foo''')"_toml;
const toml::value v5 = u8R"("")"_toml;
BOOST_CHECK(v1.is_string());
BOOST_CHECK(v2.is_string());
BOOST_CHECK(v3.is_string());
BOOST_CHECK(v4.is_string());
BOOST_CHECK_EQUAL(toml::get<std::string>(v1), "foo");
BOOST_CHECK_EQUAL(toml::get<std::string>(v2), "foo");
BOOST_CHECK_EQUAL(toml::get<std::string>(v3), "foo");
BOOST_CHECK_EQUAL(toml::get<std::string>(v4), "foo");
BOOST_TEST(v1.is_string());
BOOST_TEST(v2.is_string());
BOOST_TEST(v3.is_string());
BOOST_TEST(v4.is_string());
BOOST_TEST(v5.is_string());
BOOST_TEST(toml::get<std::string>(v1) == "foo");
BOOST_TEST(toml::get<std::string>(v2) == "foo");
BOOST_TEST(toml::get<std::string>(v3) == "foo");
BOOST_TEST(toml::get<std::string>(v4) == "foo");
BOOST_TEST(toml::get<std::string>(v5) == "\xE3\x81\xB2\xE3\x82\x89\xE3\x81\x8C\xE3\x81\xAA");
}
{
const toml::value v1 = u8R"([1,2,3])"_toml;
BOOST_CHECK(v1.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3}));
{
const toml::value v1 = u8R"([1,2,3])"_toml;
BOOST_TEST(v1.is_array());
const bool result = (toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3});
BOOST_TEST(result);
}
{
const toml::value v2 = u8R"([1,])"_toml;
BOOST_TEST(v2.is_array());
const bool result = (toml::get<std::vector<int>>(v2) == std::vector<int>{1});
BOOST_TEST(result);
}
{
const toml::value v3 = u8R"([[1,]])"_toml;
BOOST_TEST(v3.is_array());
const bool result = (toml::get<std::vector<int>>(toml::get<toml::array>(v3).front()) == std::vector<int>{1});
BOOST_TEST(result);
}
{
const toml::value v4 = u8R"([[1],])"_toml;
BOOST_TEST(v4.is_array());
const bool result = (toml::get<std::vector<int>>(toml::get<toml::array>(v4).front()) == std::vector<int>{1});
BOOST_TEST(result);
}
}
{
const toml::value v1 = u8R"({a = 42})"_toml;
BOOST_CHECK(v1.is_table());
BOOST_CHECK((toml::get<std::map<std::string,int>>(v1) ==
std::map<std::string,int>{{"a", 42}}));
BOOST_TEST(v1.is_table());
const bool result = toml::get<std::map<std::string,int>>(v1) ==
std::map<std::string,int>{{"a", 42}};
BOOST_TEST(result);
}
{
const toml::value v1 = u8"1979-05-27"_toml;
BOOST_CHECK(v1.is_local_date());
BOOST_CHECK_EQUAL(toml::get<toml::local_date>(v1),
toml::local_date(1979, toml::month_t::May, 27));
BOOST_TEST(v1.is_local_date());
BOOST_TEST(toml::get<toml::local_date>(v1) ==
toml::local_date(1979, toml::month_t::May, 27));
}
{
const toml::value v1 = u8"12:00:00"_toml;
BOOST_CHECK(v1.is_local_time());
BOOST_CHECK(toml::get<std::chrono::hours>(v1) == std::chrono::hours(12));
BOOST_TEST(v1.is_local_time());
const bool result = toml::get<std::chrono::hours>(v1) == std::chrono::hours(12);
BOOST_TEST(result);
}
{
const toml::value v1 = u8"1979-05-27T07:32:00"_toml;
BOOST_CHECK(v1.is_local_datetime());
BOOST_CHECK_EQUAL(toml::get<toml::local_datetime>(v1),
BOOST_TEST(v1.is_local_datetime());
BOOST_TEST(toml::get<toml::local_datetime>(v1) ==
toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0)));
}
{
const toml::value v1 = "1979-05-27T07:32:00Z"_toml;
BOOST_CHECK(v1.is_offset_datetime());
BOOST_CHECK_EQUAL(toml::get<toml::offset_datetime>(v1),
const toml::value v1 = u8"1979-05-27T07:32:00Z"_toml;
BOOST_TEST(v1.is_offset_datetime());
BOOST_TEST(toml::get<toml::offset_datetime>(v1) ==
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
}

View File

@@ -7,5 +7,5 @@ int main()
const std::string content("a = 0");
std::istringstream iss(content);
const auto data = toml::parse(iss, "test_multiple_translation_unit.toml");
return read_a(data);
return read_a(toml::get<toml::table>(data));
}

View File

@@ -1,4 +1,4 @@
#define BOOST_TEST_MODULE "parse_array_test"
#define BOOST_TEST_MODULE "parse_array<toml::value>_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
@@ -13,118 +13,281 @@ using namespace detail;
BOOST_AUTO_TEST_CASE(test_oneline_array)
{
TOML11_TEST_PARSE_EQUAL(parse_array, "[]", array());
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[]", array());
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL(parse_array, "[3,1,4,1,5]", a);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,1,4,1,5]", a);
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL(parse_array, "[\"foo\", \"bar\", \"baz\"]", a);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\"]", a);
}
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL(parse_array, "[3,1,4,1,5,]", a);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,1,4,1,5,]", a);
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL(parse_array, "[\"foo\", \"bar\", \"baz\",]", a);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\",]", a);
}
}
BOOST_AUTO_TEST_CASE(test_oneline_array_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[]", toml::value(array()));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[]", toml::value(array()));
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[3,1,4,1,5]", toml::value(a));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[3,1,4,1,5]", toml::value(a));
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[\"foo\", \"bar\", \"baz\"]", toml::value(a));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\", \"bar\", \"baz\"]", toml::value(a));
}
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[3,1,4,1,5,]", toml::value(a));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[3,1,4,1,5,]", toml::value(a));
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[\"foo\", \"bar\", \"baz\",]", toml::value(a));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\", \"bar\", \"baz\",]", toml::value(a));
}
}
BOOST_AUTO_TEST_CASE(test_multiline_array)
{
TOML11_TEST_PARSE_EQUAL(parse_array, "[\n#comment\n]", array());
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value< discard_comments>>, "[\n#comment\n]", typename basic_value< discard_comments>::array_type());
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<preserve_comments>>, "[\n#comment\n]", typename basic_value<preserve_comments>::array_type());
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL(parse_array, "[3,\n1,\n4,\n1,\n5]", a);
typename basic_value<discard_comments>::array_type a(5);
a[0] = basic_value<discard_comments>(3);
a[1] = basic_value<discard_comments>(1);
a[2] = basic_value<discard_comments>(4);
a[3] = basic_value<discard_comments>(1);
a[4] = basic_value<discard_comments>(5);
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<discard_comments>>, "[3,\n1,\n4,\n1,\n5]", a);
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL(parse_array, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
typename basic_value<preserve_comments>::array_type a(5);
a[0] = basic_value<preserve_comments>(3);
a[1] = basic_value<preserve_comments>(1);
a[2] = basic_value<preserve_comments>(4);
a[3] = basic_value<preserve_comments>(1);
a[4] = basic_value<preserve_comments>(5);
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<preserve_comments>>, "[3,\n1,\n4,\n1,\n5]", a);
}
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL(parse_array, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5]", a);
typename basic_value<discard_comments>::array_type a(5);
a[0] = basic_value<discard_comments>(3);
a[1] = basic_value<discard_comments>(1);
a[2] = basic_value<discard_comments>(4);
a[3] = basic_value<discard_comments>(1);
a[4] = basic_value<discard_comments>(5);
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<discard_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", a);
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("b#r");
a[2] = toml::value("b#z");
TOML11_TEST_PARSE_EQUAL(parse_array, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
typename basic_value<preserve_comments>::array_type a(5);
a[0] = basic_value<preserve_comments>(3, {"comment"});
a[1] = basic_value<preserve_comments>(1, {"comment"});
a[2] = basic_value<preserve_comments>(4, {"comment"});
a[3] = basic_value<preserve_comments>(1, {"comment"});
a[4] = basic_value<preserve_comments>(5, {"comment"});
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<preserve_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", a);
}
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("bar");
a[2] = basic_value<discard_comments>("baz");
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<discard_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo");
a[1] = basic_value<preserve_comments>("bar");
a[2] = basic_value<preserve_comments>("baz");
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<preserve_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
}
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("b#r");
a[2] = basic_value<discard_comments>("b#z");
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<discard_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo", {"comment"});
a[1] = basic_value<preserve_comments>("b#r", {"comment"});
a[2] = basic_value<preserve_comments>("b#z", {"comment"});
TOML11_TEST_PARSE_EQUAL(parse_array<basic_value<preserve_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
}
}
BOOST_AUTO_TEST_CASE(test_multiline_array_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[\n#comment\n]", toml::value(array()));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value< discard_comments>>, "[\n#comment\n]", basic_value< discard_comments>(typename basic_value< discard_comments>::array_type()));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\n#comment\n]", basic_value<preserve_comments>(typename basic_value<preserve_comments>::array_type()));
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[3,\n1,\n4,\n1,\n5]", toml::value(a));
typename basic_value<discard_comments>::array_type a(5);
a[0] = basic_value<discard_comments>(3);
a[1] = basic_value<discard_comments>(1);
a[2] = basic_value<discard_comments>(4);
a[3] = basic_value<discard_comments>(1);
a[4] = basic_value<discard_comments>(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[3,\n1,\n4,\n1,\n5]", basic_value<discard_comments>(a));
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[\"foo\",\n\"bar\",\n\"baz\"]", toml::value(a));
typename basic_value<preserve_comments>::array_type a(5);
a[0] = basic_value<preserve_comments>(3);
a[1] = basic_value<preserve_comments>(1);
a[2] = basic_value<preserve_comments>(4);
a[3] = basic_value<preserve_comments>(1);
a[4] = basic_value<preserve_comments>(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[3,\n1,\n4,\n1,\n5]", basic_value<preserve_comments>(a));
}
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5]", toml::value(a));
typename basic_value<discard_comments>::array_type a(5);
a[0] = basic_value<discard_comments>(3);
a[1] = basic_value<discard_comments>(1);
a[2] = basic_value<discard_comments>(4);
a[3] = basic_value<discard_comments>(1);
a[4] = basic_value<discard_comments>(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", basic_value<discard_comments>(a));
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("b#r");
a[2] = toml::value("b#z");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", toml::value(a));
typename basic_value<preserve_comments>::array_type a(5);
a[0] = basic_value<preserve_comments>(3, {"comment"});
a[1] = basic_value<preserve_comments>(1, {"comment"});
a[2] = basic_value<preserve_comments>(4, {"comment"});
a[3] = basic_value<preserve_comments>(1, {"comment"});
a[4] = basic_value<preserve_comments>(5, {"comment"});
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", basic_value<preserve_comments>(a));
}
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("bar");
a[2] = basic_value<discard_comments>("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", basic_value<discard_comments>(a));
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo");
a[1] = basic_value<preserve_comments>("bar");
a[2] = basic_value<preserve_comments>("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", basic_value<preserve_comments>(a));
}
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("b#r");
a[2] = basic_value<discard_comments>("b#z");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", basic_value<discard_comments>(a));
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo", {"comment"});
a[1] = basic_value<preserve_comments>("b#r", {"comment"});
a[2] = basic_value<preserve_comments>("b#z", {"comment"});
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", basic_value<preserve_comments>(a));
}
}
BOOST_AUTO_TEST_CASE(test_heterogeneous_array)
{
#ifndef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("In strict TOML v0.5.0, heterogeneous arrays are not allowed.");
#else
{
array a(5);
a[0] = toml::value("foo");
a[1] = toml::value(3.14);
a[2] = toml::value(42);
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
a[4] = toml::value{{"key", "value"}};
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\", 3.14, 42, [\"array\", \"of\", \"hetero-array\", 1], {key = \"value\"}]", toml::value(a));
}
{
array a(5);
a[0] = toml::value("foo");
a[1] = toml::value(3.14);
a[2] = toml::value(42);
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
a[4] = toml::value{{"key", "value"}};
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n 3.14,\n 42,\n [\"array\", \"of\", \"hetero-array\", 1],\n {key = \"value\"},\n]", toml::value(a));
}
{
array a(5);
a[0] = toml::value("foo");
a[1] = toml::value(3.14);
a[2] = toml::value(42);
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
a[4] = toml::value{{"key", "value"}};
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n 3.14,#comment\n 42,#comment\n [\"array\", \"of\", \"hetero-array\", 1],#comment\n {key = \"value\"},#comment\n]#comment", toml::value(a));
}
{
array a(5);
a[0] = toml::value("foo");
a[1] = toml::value(3.14);
a[2] = toml::value(42);
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
a[4] = toml::value{{"key", "value"}};
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n 3.14,\n 42,\n [\"array\",\n \"of\",\n \"hetero-array\",\n 1],\n {key = \"value\"},\n]", toml::value(a));
}
#endif
}
BOOST_AUTO_TEST_CASE(test_comments_after_comma)
{
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("bar");
a[2] = basic_value<discard_comments>("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>,
"[ \"foo\" # comment\n"
", \"bar\" # comment\n"
", \"baz\" # comment\n"
"]", basic_value<discard_comments>(a));
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo", {" comment"});
a[1] = basic_value<preserve_comments>("bar", {" comment"});
a[2] = basic_value<preserve_comments>("baz", {" comment"});
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>,
"[ \"foo\" # comment\n"
", \"bar\" # comment\n"
", \"baz\" # comment\n"
"]", basic_value<preserve_comments>(a));
}
}

View File

@@ -1,22 +1,21 @@
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <toml/region.hpp>
#include <toml/result.hpp>
#include <toml.hpp>
// some of the parsers returns not only a value but also a region.
#define TOML11_TEST_PARSE_EQUAL(psr, tkn, expct) \
do { \
const std::string token(tkn); \
toml::detail::location<std::string> loc("test", token); \
toml::detail::location loc("test", token); \
const auto result = psr(loc); \
BOOST_CHECK(result.is_ok()); \
BOOST_TEST(result.is_ok()); \
if(result.is_ok()){ \
BOOST_CHECK(result.unwrap().first == expct); \
BOOST_TEST(result.unwrap().first == expct); \
} else { \
std::cerr << "parser " << #psr << " failed with input `"; \
std::cerr << token << "`.\n"; \
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
std::cerr << "parser " << #psr << " failed with input `"; \
std::cerr << token << "`.\n"; \
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
} \
} while(false); \
/**/
@@ -24,15 +23,15 @@ do { \
#define TOML11_TEST_PARSE_EQUAL_VALUE(psr, tkn, expct) \
do { \
const std::string token(tkn); \
toml::detail::location<std::string> loc("test", token); \
toml::detail::location loc("test", token); \
const auto result = psr(loc); \
BOOST_CHECK(result.is_ok()); \
BOOST_TEST(result.is_ok()); \
if(result.is_ok()){ \
BOOST_CHECK(result.unwrap() == expct); \
BOOST_TEST(result.unwrap() == expct); \
} else { \
std::cerr << "parse_value failed with input `"; \
std::cerr << token << "`.\n"; \
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
std::cerr << "parse_value failed with input `"; \
std::cerr << token << "`.\n"; \
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
} \
} while(false); \
/**/

View File

@@ -19,6 +19,6 @@ BOOST_AUTO_TEST_CASE(test_boolean)
BOOST_AUTO_TEST_CASE(test_boolean_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "true", toml::value( true));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "false", toml::value(false));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "true", toml::value( true));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "false", toml::value(false));
}

View File

@@ -17,25 +17,138 @@ BOOST_AUTO_TEST_CASE(test_time)
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.99", toml::local_time(7, 32, 0, 990, 0));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.999", toml::local_time(7, 32, 0, 999, 0));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.999999", toml::local_time(7, 32, 0, 999, 999));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "00:00:00.000000", toml::local_time( 0, 0, 0, 0, 0));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "23:59:59.999999", toml::local_time(23, 59, 59, 999, 999));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "23:59:60.999999", toml::local_time(23, 59, 60, 999, 999)); // leap second
}
BOOST_AUTO_TEST_CASE(test_time_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "07:32:00", toml::value(toml::local_time(7, 32, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "07:32:00.99", toml::value(toml::local_time(7, 32, 0, 990, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "07:32:00.999", toml::value(toml::local_time(7, 32, 0, 999, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "07:32:00.999999", toml::value(toml::local_time(7, 32, 0, 999, 999)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00", toml::value(toml::local_time(7, 32, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.99", toml::value(toml::local_time(7, 32, 0, 990, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.999", toml::value(toml::local_time(7, 32, 0, 999, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.999999", toml::value(toml::local_time(7, 32, 0, 999, 999)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "00:00:00.000000", toml::value(toml::local_time( 0, 0, 0, 0, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "23:59:59.999999", toml::value(toml::local_time(23, 59, 59, 999, 999)));
std::istringstream stream1(std::string("invalid-datetime = 24:00:00"));
std::istringstream stream2(std::string("invalid-datetime = 00:60:00"));
std::istringstream stream3(std::string("invalid-datetime = 00:00:61"));
BOOST_CHECK_THROW(toml::parse(stream1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream3), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_date)
{
TOML11_TEST_PARSE_EQUAL(parse_local_date, "1979-05-27",
toml::local_date(1979, toml::month_t::May, 27));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "1979-05-27", toml::local_date(1979, toml::month_t::May, 27));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-01-01", toml::local_date(2000, toml::month_t::Jan, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-01-31", toml::local_date(2000, toml::month_t::Jan, 31));
std::istringstream stream1_1(std::string("invalid-datetime = 2000-01-00"));
std::istringstream stream1_2(std::string("invalid-datetime = 2000-01-32"));
BOOST_CHECK_THROW(toml::parse(stream1_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream1_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-02-01", toml::local_date(2000, toml::month_t::Feb, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-02-29", toml::local_date(2000, toml::month_t::Feb, 29));
std::istringstream stream2_1(std::string("invalid-datetime = 2000-02-00"));
std::istringstream stream2_2(std::string("invalid-datetime = 2000-02-30"));
BOOST_CHECK_THROW(toml::parse(stream2_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2001-02-28", toml::local_date(2001, toml::month_t::Feb, 28));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2004-02-29", toml::local_date(2004, toml::month_t::Feb, 29));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2100-02-28", toml::local_date(2100, toml::month_t::Feb, 28));
std::istringstream stream2_3(std::string("invalid-datetime = 2001-02-29"));
std::istringstream stream2_4(std::string("invalid-datetime = 2004-02-30"));
std::istringstream stream2_5(std::string("invalid-datetime = 2100-02-29"));
BOOST_CHECK_THROW(toml::parse(stream2_3), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2_4), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2_5), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-03-01", toml::local_date(2000, toml::month_t::Mar, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-03-31", toml::local_date(2000, toml::month_t::Mar, 31));
std::istringstream stream3_1(std::string("invalid-datetime = 2000-03-00"));
std::istringstream stream3_2(std::string("invalid-datetime = 2000-03-32"));
BOOST_CHECK_THROW(toml::parse(stream3_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream3_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-04-01", toml::local_date(2000, toml::month_t::Apr, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-04-30", toml::local_date(2000, toml::month_t::Apr, 30));
std::istringstream stream4_1(std::string("invalid-datetime = 2000-04-00"));
std::istringstream stream4_2(std::string("invalid-datetime = 2000-04-31"));
BOOST_CHECK_THROW(toml::parse(stream4_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream4_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-05-01", toml::local_date(2000, toml::month_t::May, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-05-31", toml::local_date(2000, toml::month_t::May, 31));
std::istringstream stream5_1(std::string("invalid-datetime = 2000-05-00"));
std::istringstream stream5_2(std::string("invalid-datetime = 2000-05-32"));
BOOST_CHECK_THROW(toml::parse(stream5_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream5_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-06-01", toml::local_date(2000, toml::month_t::Jun, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-06-30", toml::local_date(2000, toml::month_t::Jun, 30));
std::istringstream stream6_1(std::string("invalid-datetime = 2000-06-00"));
std::istringstream stream6_2(std::string("invalid-datetime = 2000-06-31"));
BOOST_CHECK_THROW(toml::parse(stream6_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream6_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-07-01", toml::local_date(2000, toml::month_t::Jul, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-07-31", toml::local_date(2000, toml::month_t::Jul, 31));
std::istringstream stream7_1(std::string("invalid-datetime = 2000-07-00"));
std::istringstream stream7_2(std::string("invalid-datetime = 2000-07-32"));
BOOST_CHECK_THROW(toml::parse(stream7_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream7_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-08-01", toml::local_date(2000, toml::month_t::Aug, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-08-31", toml::local_date(2000, toml::month_t::Aug, 31));
std::istringstream stream8_1(std::string("invalid-datetime = 2000-08-00"));
std::istringstream stream8_2(std::string("invalid-datetime = 2000-08-32"));
BOOST_CHECK_THROW(toml::parse(stream8_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream8_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-09-01", toml::local_date(2000, toml::month_t::Sep, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-09-30", toml::local_date(2000, toml::month_t::Sep, 30));
std::istringstream stream9_1(std::string("invalid-datetime = 2000-09-00"));
std::istringstream stream9_2(std::string("invalid-datetime = 2000-09-31"));
BOOST_CHECK_THROW(toml::parse(stream9_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream9_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-10-01", toml::local_date(2000, toml::month_t::Oct, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-10-31", toml::local_date(2000, toml::month_t::Oct, 31));
std::istringstream stream10_1(std::string("invalid-datetime = 2000-10-00"));
std::istringstream stream10_2(std::string("invalid-datetime = 2000-10-32"));
BOOST_CHECK_THROW(toml::parse(stream10_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream10_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-11-01", toml::local_date(2000, toml::month_t::Nov, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-11-30", toml::local_date(2000, toml::month_t::Nov, 30));
std::istringstream stream11_1(std::string("invalid-datetime = 2000-11-00"));
std::istringstream stream11_2(std::string("invalid-datetime = 2000-11-31"));
BOOST_CHECK_THROW(toml::parse(stream11_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream11_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-12-01", toml::local_date(2000, toml::month_t::Dec, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-12-31", toml::local_date(2000, toml::month_t::Dec, 31));
std::istringstream stream12_1(std::string("invalid-datetime = 2000-12-00"));
std::istringstream stream12_2(std::string("invalid-datetime = 2000-12-32"));
BOOST_CHECK_THROW(toml::parse(stream12_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream12_2), toml::syntax_error);
std::istringstream stream13_1(std::string("invalid-datetime = 2000-13-01"));
BOOST_CHECK_THROW(toml::parse(stream13_1), toml::syntax_error);
std::istringstream stream0_1(std::string("invalid-datetime = 2000-00-01"));
BOOST_CHECK_THROW(toml::parse(stream0_1), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_date_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27",
value(toml::local_date(1979, toml::month_t::May, 27)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27", value(toml::local_date(1979, toml::month_t::May, 27)));
}
BOOST_AUTO_TEST_CASE(test_datetime)
@@ -64,25 +177,25 @@ BOOST_AUTO_TEST_CASE(test_datetime)
BOOST_AUTO_TEST_CASE(test_datetime_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00.99",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00.99",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 990, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00.999999",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00.999999",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 999, 999))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27t07:32:00",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27t07:32:00",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27t07:32:00.99",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27t07:32:00.99",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 990, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27t07:32:00.999999",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27t07:32:00.999999",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 999, 999))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27 07:32:00",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27 07:32:00",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27 07:32:00.99",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27 07:32:00.99",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 990, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27 07:32:00.999999",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27 07:32:00.999999",
toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 999, 999))));
}
@@ -107,27 +220,32 @@ BOOST_AUTO_TEST_CASE(test_offset_datetime)
TOML11_TEST_PARSE_EQUAL(parse_offset_datetime, "1979-05-27T07:32:00.999999+09:00",
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0, 999, 999), toml::time_offset(9, 0)));
std::istringstream stream1(std::string("invalid-datetime = 2000-01-01T00:00:00+24:00"));
std::istringstream stream2(std::string("invalid-datetime = 2000-01-01T00:00:00+00:60"));
BOOST_CHECK_THROW(toml::parse(stream1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_offset_datetime_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00Z",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00Z",
toml::value(toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0), toml::time_offset(0, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00.99Z",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00.99Z",
toml::value(toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0, 990, 0), toml::time_offset(0, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00.999999Z",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00.999999Z",
toml::value(toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0, 999, 999), toml::time_offset(0, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00+09:00",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00+09:00",
toml::value(toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0), toml::time_offset(9, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00.99+09:00",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00.99+09:00",
toml::value(toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0, 990, 0), toml::time_offset(9, 0))));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1979-05-27T07:32:00.999999+09:00",
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27T07:32:00.999999+09:00",
toml::value(toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0, 999, 999), toml::time_offset(9, 0))));
}

View File

@@ -8,192 +8,385 @@
#include <toml.hpp>
#include <iostream>
#include <fstream>
#include <map>
#include <deque>
BOOST_AUTO_TEST_CASE(test_example)
{
const auto data = toml::parse("toml/tests/example.toml");
BOOST_CHECK_EQUAL(toml::get<std::string>(data.at("title")), "TOML Example");
toml::Table owner = toml::get<toml::Table>(data.at("owner"));
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
{
BOOST_CHECK_EQUAL(toml::get<std::string>(owner.at("name")), "Tom Preston-Werner");
BOOST_CHECK_EQUAL(toml::get<std::string>(owner.at("organization")), "GitHub");
BOOST_CHECK_EQUAL(toml::get<std::string>(owner.at("bio")),
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
BOOST_TEST(toml::find<std::string>(owner, "bio") ==
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
BOOST_CHECK_EQUAL(toml::get<toml::Datetime>(owner.at("dob")),
BOOST_TEST(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)));
}
toml::Table database = toml::get<toml::Table>(data.at("database"));
const auto& database = toml::find(data, "database");
{
BOOST_CHECK_EQUAL(toml::get<std::string>(database.at("server")), "192.168.1.1");
BOOST_TEST(toml::find<std::string>(database, "server") == "192.168.1.1");
const std::vector<int> expected_ports{8001, 8001, 8002};
BOOST_CHECK(toml::get<std::vector<int>>(database.at("ports")) == expected_ports);
BOOST_CHECK_EQUAL(toml::get<int>(database.at("connection_max")), 5000);
BOOST_CHECK_EQUAL(toml::get<bool>(database.at("enabled")), true);
BOOST_CHECK(toml::find<std::vector<int>>(database, "ports") == expected_ports);
BOOST_TEST(toml::find<int >(database, "connection_max") == 5000);
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
}
toml::Table servers = toml::get<toml::Table>(data.at("servers"));
const auto& servers = toml::find(data, "servers");
{
toml::Table alpha = toml::get<toml::Table>(servers.at("alpha"));
BOOST_CHECK_EQUAL(toml::get<std::string>(alpha.at("ip")), "10.0.0.1");
BOOST_CHECK_EQUAL(toml::get<std::string>(alpha.at("dc")), "eqdc10");
toml::table alpha = toml::find<toml::table>(servers, "alpha");
BOOST_TEST(toml::get<std::string>(alpha.at("ip")) == "10.0.0.1");
BOOST_TEST(toml::get<std::string>(alpha.at("dc")) == "eqdc10");
toml::Table beta = toml::get<toml::Table>(servers.at("beta"));
BOOST_CHECK_EQUAL(toml::get<std::string>(beta.at("ip")), "10.0.0.2");
BOOST_CHECK_EQUAL(toml::get<std::string>(beta.at("dc")), "eqdc10");
BOOST_CHECK_EQUAL(toml::get<std::string>(beta.at("country")), "\xE4\xB8\xAD\xE5\x9B\xBD");
toml::table beta = toml::find<toml::table>(servers, "beta");
BOOST_TEST(toml::get<std::string>(beta.at("ip")) == "10.0.0.2");
BOOST_TEST(toml::get<std::string>(beta.at("dc")) == "eqdc10");
BOOST_TEST(toml::get<std::string>(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD");
}
toml::Table clients = toml::get<toml::Table>(data.at("clients"));
const auto& clients = toml::find(data, "clients");
{
toml::Array clients_data = toml::get<toml::Array>(clients.at("data"));
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);
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);
BOOST_CHECK(toml::get<std::vector<int>>(clients_data.at(1)) == expected_number);
std::vector<std::string> expected_hosts{"alpha", "omega"};
BOOST_CHECK(toml::get<std::vector<std::string>>(clients.at("hosts")) ==
expected_hosts);
BOOST_CHECK(toml::find<std::vector<std::string>>(clients, "hosts") == expected_hosts);
}
std::vector<toml::Table> products =
toml::get<std::vector<toml::Table>>(data.at("products"));
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_TEST(toml::get<std::string>(products.at(0).at("name")) == "Hammer");
BOOST_TEST(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_TEST(toml::get<std::string>(products.at(1).at("name")) == "Nail");
BOOST_TEST(toml::get<std::int64_t>(products.at(1).at("sku")) == 284758393);
BOOST_TEST(toml::get<std::string>(products.at(1).at("color")) == "gray");
}
}
BOOST_AUTO_TEST_CASE(test_example_stream)
{
std::ifstream ifs("toml/tests/example.toml");
std::ifstream ifs("toml/tests/example.toml", std::ios::binary);
const auto data = toml::parse(ifs);
BOOST_CHECK_EQUAL(toml::get<std::string>(data.at("title")), "TOML Example");
toml::Table owner = toml::get<toml::Table>(data.at("owner"));
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
{
BOOST_CHECK_EQUAL(toml::get<std::string>(owner.at("name")), "Tom Preston-Werner");
BOOST_CHECK_EQUAL(toml::get<std::string>(owner.at("organization")), "GitHub");
BOOST_CHECK_EQUAL(toml::get<std::string>(owner.at("bio")),
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
BOOST_TEST(toml::find<std::string>(owner, "bio") ==
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
BOOST_CHECK_EQUAL(toml::get<toml::Datetime>(owner.at("dob")),
BOOST_TEST(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)));
}
toml::Table database = toml::get<toml::Table>(data.at("database"));
const auto& database = toml::find(data, "database");
{
BOOST_CHECK_EQUAL(toml::get<std::string>(database.at("server")), "192.168.1.1");
BOOST_TEST(toml::find<std::string>(database, "server") == "192.168.1.1");
const std::vector<int> expected_ports{8001, 8001, 8002};
BOOST_CHECK(toml::get<std::vector<int>>(database.at("ports")) == expected_ports);
BOOST_CHECK_EQUAL(toml::get<int>(database.at("connection_max")), 5000);
BOOST_CHECK_EQUAL(toml::get<bool>(database.at("enabled")), true);
BOOST_CHECK(toml::find<std::vector<int>>(database, "ports") == expected_ports);
BOOST_TEST(toml::find<int >(database, "connection_max") == 5000);
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
}
toml::Table servers = toml::get<toml::Table>(data.at("servers"));
const auto& servers = toml::find(data, "servers");
{
toml::Table alpha = toml::get<toml::Table>(servers.at("alpha"));
BOOST_CHECK_EQUAL(toml::get<std::string>(alpha.at("ip")), "10.0.0.1");
BOOST_CHECK_EQUAL(toml::get<std::string>(alpha.at("dc")), "eqdc10");
toml::table alpha = toml::find<toml::table>(servers, "alpha");
BOOST_TEST(toml::get<std::string>(alpha.at("ip")) == "10.0.0.1");
BOOST_TEST(toml::get<std::string>(alpha.at("dc")) == "eqdc10");
toml::Table beta = toml::get<toml::Table>(servers.at("beta"));
BOOST_CHECK_EQUAL(toml::get<std::string>(beta.at("ip")), "10.0.0.2");
BOOST_CHECK_EQUAL(toml::get<std::string>(beta.at("dc")), "eqdc10");
BOOST_CHECK_EQUAL(toml::get<std::string>(beta.at("country")), "\xE4\xB8\xAD\xE5\x9B\xBD");
toml::table beta = toml::find<toml::table>(servers, "beta");
BOOST_TEST(toml::get<std::string>(beta.at("ip")) == "10.0.0.2");
BOOST_TEST(toml::get<std::string>(beta.at("dc")) == "eqdc10");
BOOST_TEST(toml::get<std::string>(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD");
}
toml::Table clients = toml::get<toml::Table>(data.at("clients"));
const auto& clients = toml::find(data, "clients");
{
toml::Array clients_data = toml::get<toml::Array>(clients.at("data"));
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);
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);
BOOST_CHECK(toml::get<std::vector<int>>(clients_data.at(1)) == expected_number);
std::vector<std::string> expected_hosts{"alpha", "omega"};
BOOST_CHECK(toml::get<std::vector<std::string>>(clients.at("hosts")) ==
expected_hosts);
BOOST_CHECK(toml::find<std::vector<std::string>>(clients, "hosts") == expected_hosts);
}
std::vector<toml::Table> products =
toml::get<std::vector<toml::Table>>(data.at("products"));
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")),
BOOST_TEST(toml::get<std::string>(products.at(0).at("name")) ==
"Hammer");
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(0).at("sku")),
BOOST_TEST(toml::get<std::int64_t>(products.at(0).at("sku")) ==
738594937);
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("name")),
BOOST_TEST(toml::get<std::string>(products.at(1).at("name")) ==
"Nail");
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(products.at(1).at("sku")),
BOOST_TEST(toml::get<std::int64_t>(products.at(1).at("sku")) ==
284758393);
BOOST_CHECK_EQUAL(toml::get<std::string>(products.at(1).at("color")),
BOOST_TEST(toml::get<std::string>(products.at(1).at("color")) ==
"gray");
}
}
BOOST_AUTO_TEST_CASE(test_fruit)
{
const auto data = toml::parse("toml/tests/fruit.toml");
const auto blah = toml::get<std::vector<toml::Table>>(
toml::get<toml::Table>(data.at("fruit")).at("blah"));
BOOST_CHECK_EQUAL(toml::get<std::string>(blah.at(0).at("name")), "apple");
BOOST_CHECK_EQUAL(toml::get<std::string>(blah.at(1).at("name")), "banana");
const auto blah = toml::find<toml::array>(toml::find(data, "fruit"), "blah");
BOOST_TEST(toml::find<std::string>(blah.at(0), "name") == "apple");
BOOST_TEST(toml::find<std::string>(blah.at(1), "name") == "banana");
{
const auto physical = toml::get<toml::Table>(blah.at(0).at("physical"));
BOOST_CHECK_EQUAL(toml::get<std::string>(physical.at("color")), "red");
BOOST_CHECK_EQUAL(toml::get<std::string>(physical.at("shape")), "round");
const auto physical = toml::find(blah.at(0), "physical");
BOOST_TEST(toml::find<std::string>(physical, "color") == "red");
BOOST_TEST(toml::find<std::string>(physical, "shape") == "round");
}
{
const auto physical = toml::get<toml::Table>(blah.at(1).at("physical"));
BOOST_CHECK_EQUAL(toml::get<std::string>(physical.at("color")), "yellow");
BOOST_CHECK_EQUAL(toml::get<std::string>(physical.at("shape")), "bent");
const auto physical = toml::find(blah.at(1), "physical");
BOOST_TEST(toml::find<std::string>(physical, "color") == "yellow");
BOOST_TEST(toml::find<std::string>(physical, "shape") == "bent");
}
}
BOOST_AUTO_TEST_CASE(test_hard_example)
{
const auto data = toml::parse("toml/tests/hard_example.toml");
const auto the = toml::get<toml::Table>(data.at("the"));
BOOST_CHECK_EQUAL(toml::get<std::string>(the.at("test_string")),
const auto the = toml::find(data, "the");
BOOST_TEST(toml::find<std::string>(the, "test_string") ==
"You'll hate me after this - #");
const auto hard = toml::get<toml::Table>(the.at("hard"));
const auto hard = toml::find(the, "hard");
const std::vector<std::string> expected_the_hard_test_array{"] ", " # "};
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("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::get<std::vector<std::string>>(hard.at("test_array2")) ==
BOOST_CHECK(toml::find<std::vector<std::string>>(hard, "test_array2") ==
expected_the_hard_test_array2);
BOOST_CHECK_EQUAL(toml::get<std::string>(hard.at("another_test_string")),
BOOST_TEST(toml::find<std::string>(hard, "another_test_string") ==
" Same thing, but with a string #");
BOOST_CHECK_EQUAL(toml::get<std::string>(hard.at("harder_test_string")),
BOOST_TEST(toml::find<std::string>(hard, "harder_test_string") ==
" And when \"'s are in the string, along with # \"");
const auto bit = toml::get<toml::Table>(hard.at("bit#"));
BOOST_CHECK_EQUAL(toml::get<std::string>(bit.at("what?")),
const auto bit = toml::find(hard, "bit#");
BOOST_TEST(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::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
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_TEST(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_TEST(toml::find<std::string>(hard, "another_test_string") ==
" Same thing, but with a string #");
BOOST_TEST(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_TEST(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_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
{
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
BOOST_TEST(toml::find<std::string>(owner, "bio") ==
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
BOOST_TEST(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_TEST(toml::find(owner, "dob").comments().at(0) ==
" First class dates? Why not?");
}
const auto& database = toml::find(data, "database");
{
BOOST_TEST(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_TEST(toml::find<int >(database, "connection_max") == 5000);
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
}
const auto& servers = toml::find(data, "servers");
{
const auto& alpha = toml::find(servers, "alpha");
BOOST_TEST(alpha.comments().at(0) ==
" You can indent as you please. Tabs or spaces. TOML don't care.");
BOOST_TEST(toml::find<std::string>(alpha, "ip") == "10.0.0.1");
BOOST_TEST(toml::find<std::string>(alpha, "dc") == "eqdc10");
const auto& beta = toml::find(servers, "beta");
BOOST_TEST(toml::find<std::string>(beta, "ip") == "10.0.0.2");
BOOST_TEST(toml::find<std::string>(beta, "dc") == "eqdc10");
BOOST_TEST(toml::find<std::string>(beta, "country") ==
"\xE4\xB8\xAD\xE5\x9B\xBD");
BOOST_TEST(toml::find(beta, "country").comments().at(0) ==
" This should be parsed as UTF-8");
}
const auto& clients = toml::find(data, "clients");
{
BOOST_TEST(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_TEST(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_TEST(toml::get<std::string>(products.at(0).at("name")) ==
"Hammer");
BOOST_TEST(toml::get<std::int64_t>(products.at(0).at("sku")) ==
738594937);
BOOST_TEST(toml::get<std::string>(products.at(1).at("name")) ==
"Nail");
BOOST_TEST(toml::get<std::int64_t>(products.at(1).at("sku")) ==
284758393);
BOOST_TEST(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_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
{
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
BOOST_TEST(toml::find<std::string>(owner, "bio") ==
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
BOOST_TEST(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_TEST(toml::find(owner, "dob").comments().at(0) ==
" First class dates? Why not?");
}
const auto& database = toml::find(data, "database");
{
BOOST_TEST(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_TEST(toml::find<int >(database, "connection_max") == 5000);
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
}
const auto& servers = toml::find(data, "servers");
{
const auto& alpha = toml::find(servers, "alpha");
BOOST_TEST(alpha.comments().at(0) ==
" You can indent as you please. Tabs or spaces. TOML don't care.");
BOOST_TEST(toml::find<std::string>(alpha, "ip") == "10.0.0.1");
BOOST_TEST(toml::find<std::string>(alpha, "dc") == "eqdc10");
const auto& beta = toml::find(servers, "beta");
BOOST_TEST(toml::find<std::string>(beta, "ip") == "10.0.0.2");
BOOST_TEST(toml::find<std::string>(beta, "dc") == "eqdc10");
BOOST_TEST(toml::find<std::string>(beta, "country") ==
"\xE4\xB8\xAD\xE5\x9B\xBD");
BOOST_TEST(toml::find(beta, "country").comments().at(0) ==
" This should be parsed as UTF-8");
}
const auto& clients = toml::find(data, "clients");
{
BOOST_TEST(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_TEST(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_TEST(toml::get<std::string>(products.at(0).at("name")) ==
"Hammer");
BOOST_TEST(toml::get<std::int64_t>(products.at(0).at("sku")) ==
738594937);
BOOST_TEST(toml::get<std::string>(products.at(1).at("name")) ==
"Nail");
BOOST_TEST(toml::get<std::int64_t>(products.at(1).at("sku")) ==
284758393);
BOOST_TEST(toml::get<std::string>(products.at(1).at("color")) ==
"gray");
}
}
// ---------------------------------------------------------------------------
// after here, the test codes generate the content of a file.
@@ -210,8 +403,8 @@ BOOST_AUTO_TEST_CASE(test_file_with_BOM)
std::istringstream iss(table);
const auto data = toml::parse(iss, "test_file_with_BOM.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -226,8 +419,8 @@ BOOST_AUTO_TEST_CASE(test_file_with_BOM)
}
const auto data = toml::parse("tmp.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -239,8 +432,8 @@ BOOST_AUTO_TEST_CASE(test_file_with_BOM)
std::istringstream iss(table);
const auto data = toml::parse(iss, "test_file_with_BOM_CRLF.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -254,12 +447,12 @@ BOOST_AUTO_TEST_CASE(test_file_with_BOM)
// value will be "\r\r\n". To avoid the additional "\r", use binary
// mode.
std::ofstream ofs("tmp.toml", std::ios_base::binary);
ofs.write(table.data(), table.size());
ofs.write(table.data(), static_cast<std::streamsize>(table.size()));
}
const auto data = toml::parse("tmp.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
}
@@ -275,8 +468,8 @@ BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file)
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -288,8 +481,8 @@ BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file)
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_CRLF.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
@@ -302,8 +495,8 @@ BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file)
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -315,8 +508,8 @@ BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file)
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
@@ -329,8 +522,8 @@ BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file)
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_ws.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -342,8 +535,8 @@ BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file)
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_ws.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
}
@@ -362,8 +555,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -377,8 +570,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
// comment w/ newline
@@ -394,8 +587,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -409,8 +602,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
// CRLF version
@@ -426,8 +619,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -441,8 +634,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -455,8 +648,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -470,8 +663,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
}
@@ -489,8 +682,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -504,8 +697,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
// with whitespaces
@@ -521,8 +714,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -536,8 +729,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -551,8 +744,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -566,8 +759,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
// with whitespaces but no newline
@@ -582,8 +775,24 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
// without newline
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"a = 0"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
@@ -600,8 +809,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -615,8 +824,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
// with whitespaces
@@ -632,8 +841,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -647,8 +856,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -662,8 +871,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -677,8 +886,8 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
{
const std::string table(
@@ -691,7 +900,62 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
}
BOOST_AUTO_TEST_CASE(test_file_ends_without_lf)
{
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\""
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_without_lf.toml");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
}
BOOST_AUTO_TEST_CASE(test_parse_function_compiles)
{
// toml::parse("");
const auto string_literal = toml::parse("toml/tests/example.toml");
BOOST_TEST_MESSAGE("string_literal");
const char* fname_cstring = "toml/tests/example.toml";
// toml::parse(const char*);
const auto cstring = toml::parse(fname_cstring);
BOOST_TEST_MESSAGE("const char*");
// toml::parse(char*);
std::array<char, 24> fname_char_ptr;
std::strncpy(fname_char_ptr.data(), fname_cstring, 24);
const auto char_ptr = toml::parse(fname_char_ptr.data());
BOOST_TEST_MESSAGE("char*");
// toml::parse(const std::string&);
const std::string fname_string("toml/tests/example.toml");
const auto string = toml::parse(fname_string);
std::string fname_string_mut("toml/tests/example.toml");
// toml::parse(std::string&);
const auto string_mutref = toml::parse(fname_string_mut);
// toml::parse(std::string&&);
const auto string_rref = toml::parse(std::move(fname_string_mut));
BOOST_TEST_MESSAGE("strings");
#ifdef TOML11_HAS_STD_FILESYSTEM
const std::filesystem::path fname_path(fname_string.begin(), fname_string.end());
const auto filesystem_path = toml::parse(fname_path);
BOOST_TEST_MESSAGE("path");
#endif
}

View File

@@ -32,20 +32,20 @@ BOOST_AUTO_TEST_CASE(test_fractional)
BOOST_AUTO_TEST_CASE(test_fractional_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1.0", value( 1.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0.1", value( 0.1));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0.001", value( 0.001));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0.100", value( 0.1));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+3.14", value( 3.14));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-3.14", value(-3.14));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "3.1415_9265_3589", value( 3.141592653589));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+3.1415_9265_3589", value( 3.141592653589));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-3.1415_9265_3589", value(-3.141592653589));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "123_456.789", value( 123456.789));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+123_456.789", value( 123456.789));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-123_456.789", value(-123456.789));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+0.0", value( 0.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-0.0", value(-0.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1.0", value( 1.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0.1", value( 0.1));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0.001", value( 0.001));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0.100", value( 0.1));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+3.14", value( 3.14));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-3.14", value(-3.14));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "3.1415_9265_3589", value( 3.141592653589));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+3.1415_9265_3589", value( 3.141592653589));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-3.1415_9265_3589", value(-3.141592653589));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "123_456.789", value( 123456.789));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+123_456.789", value( 123456.789));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-123_456.789", value(-123456.789));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+0.0", value( 0.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-0.0", value(-0.0));
}
BOOST_AUTO_TEST_CASE(test_exponential)
@@ -68,28 +68,42 @@ BOOST_AUTO_TEST_CASE(test_exponential)
TOML11_TEST_PARSE_EQUAL(parse_floating, "1_2_3E-1_0", 123e-10);
TOML11_TEST_PARSE_EQUAL(parse_floating, "+0e0", 0.0);
TOML11_TEST_PARSE_EQUAL(parse_floating, "-0e0", -0.0);
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_PARSE_EQUAL(parse_floating, "1_2_3E-01", 123e-1);
TOML11_TEST_PARSE_EQUAL(parse_floating, "1_2_3E-0_1", 123e-1);
#endif
}
BOOST_AUTO_TEST_CASE(test_exponential_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1e10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1e+10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1e-10", value(1e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+1e10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+1e+10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+1e-10", value(1e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-1e10", value(-1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-1e+10", value(-1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-1e-10", value(-1e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "123e-10", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1E10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1E+10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1E-10", value(1e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "123E-10", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1_2_3E-10", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1_2_3E-1_0", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+0e0", value( 0.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-0e0", value(-0.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1e10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1e+10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1e-10", value(1e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+1e10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+1e+10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+1e-10", value(1e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-1e10", value(-1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-1e+10", value(-1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-1e-10", value(-1e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "123e-10", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1E10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1E+10", value(1e10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1E-10", value(1e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "123E-10", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1_2_3E-10", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1_2_3E-1_0", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+0e0", value( 0.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-0e0", value(-0.0));
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1_2_3E-01", value(123e-1));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1_2_3E-0_1", value(123e-1));
#endif
}
BOOST_AUTO_TEST_CASE(test_fe)
{
@@ -99,16 +113,22 @@ BOOST_AUTO_TEST_CASE(test_fe)
}
BOOST_AUTO_TEST_CASE(test_fe_vaule)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "6.02e23", value(6.02e23));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "6.02e+23", value(6.02e23));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1.112_650_06e-17", value(1.11265006e-17));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "6.02e23", value(6.02e23));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "6.02e+23", value(6.02e23));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1.112_650_06e-17", value(1.11265006e-17));
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "3.141_5e-01", value(3.1415e-1));
#endif
}
BOOST_AUTO_TEST_CASE(test_inf)
{
{
const std::string token("inf");
toml::detail::location<std::string> loc("test", token);
toml::detail::location loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isinf(r.unwrap().first));
@@ -116,7 +136,7 @@ BOOST_AUTO_TEST_CASE(test_inf)
}
{
const std::string token("+inf");
toml::detail::location<std::string> loc("test", token);
toml::detail::location loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isinf(r.unwrap().first));
@@ -124,7 +144,7 @@ BOOST_AUTO_TEST_CASE(test_inf)
}
{
const std::string token("-inf");
toml::detail::location<std::string> loc("test", token);
toml::detail::location loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isinf(r.unwrap().first));
@@ -136,21 +156,21 @@ BOOST_AUTO_TEST_CASE(test_nan)
{
{
const std::string token("nan");
toml::detail::location<std::string> loc("test", token);
toml::detail::location loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isnan(r.unwrap().first));
}
{
const std::string token("+nan");
toml::detail::location<std::string> loc("test", token);
toml::detail::location loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isnan(r.unwrap().first));
}
{
const std::string token("-nan");
toml::detail::location<std::string> loc("test", token);
toml::detail::location loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isnan(r.unwrap().first));

View File

@@ -13,36 +13,52 @@ using namespace detail;
BOOST_AUTO_TEST_CASE(test_inline_table)
{
TOML11_TEST_PARSE_EQUAL(parse_inline_table, "{}", table());
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{}", table());
{
table t;
t["foo"] = toml::value(42);
t["bar"] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL(parse_inline_table, "{foo = 42, bar = \"baz\"}", t);
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{foo = 42, bar = \"baz\"}", t);
}
{
table t;
table t_sub;
t_sub["name"] = toml::value("pug");
t["type"] = toml::value(t_sub);
TOML11_TEST_PARSE_EQUAL(parse_inline_table, "{type.name = \"pug\"}", t);
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{type.name = \"pug\"}", t);
}
}
BOOST_AUTO_TEST_CASE(test_inline_table_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "{}", value(table()));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "{}", value(table()));
{
table t;
t["foo"] = toml::value(42);
t["bar"] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "{foo = 42, bar = \"baz\"}", value(t));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "{foo = 42, bar = \"baz\"}", value(t));
}
{
table t;
table t_sub;
t_sub["name"] = toml::value("pug");
t["type"] = toml::value(t_sub);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "{type.name = \"pug\"}", value(t));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "{type.name = \"pug\"}", value(t));
}
}
BOOST_AUTO_TEST_CASE(test_inline_table_immutability)
{
{
std::istringstream stream(std::string(
"a = {b = 1}\n"
"a.c = 2\n"));
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
{
std::istringstream stream(std::string(
"a = {b = {c = 1}}\n"
"a.b.d = 2\n"));
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
}

View File

@@ -25,14 +25,14 @@ BOOST_AUTO_TEST_CASE(test_decimal)
BOOST_AUTO_TEST_CASE(test_decimal_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1234", toml::value( 1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+1234", toml::value( 1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-1234", toml::value( -1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0", toml::value( 0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1_2_3_4", toml::value( 1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "+1_2_3_4", toml::value( +1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "-1_2_3_4", toml::value( -1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "123_456_789", toml::value(123456789));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1234", toml::value( 1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+1234", toml::value( 1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-1234", toml::value( -1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0", toml::value( 0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1_2_3_4", toml::value( 1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+1_2_3_4", toml::value( +1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-1_2_3_4", toml::value( -1234));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "123_456_789", toml::value(123456789));
}
BOOST_AUTO_TEST_CASE(test_hex)
@@ -50,15 +50,15 @@ BOOST_AUTO_TEST_CASE(test_hex)
BOOST_AUTO_TEST_CASE(test_hex_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0xDEADBEEF", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0xdeadbeef", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0xDEADbeef", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0xDEAD_BEEF", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0xdead_beef", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0xdead_BEEF", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0xFF", value(0xFF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0x00FF", value(0xFF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0x0000FF", value(0xFF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0xDEADBEEF", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0xdeadbeef", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0xDEADbeef", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0xDEAD_BEEF", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0xdead_beef", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0xdead_BEEF", value(0xDEADBEEF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0xFF", value(0xFF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0x00FF", value(0xFF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0x0000FF", value(0xFF));
}
BOOST_AUTO_TEST_CASE(test_oct)
@@ -70,9 +70,9 @@ BOOST_AUTO_TEST_CASE(test_oct)
BOOST_AUTO_TEST_CASE(test_oct_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0o777", value(64*7+8*7+7));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0o7_7_7", value(64*7+8*7+7));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0o007", value(7));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0o777", value(64*7+8*7+7));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0o7_7_7", value(64*7+8*7+7));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0o007", value(7));
}
BOOST_AUTO_TEST_CASE(test_bin)
@@ -85,8 +85,8 @@ BOOST_AUTO_TEST_CASE(test_bin)
BOOST_AUTO_TEST_CASE(test_bin_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0b10000", value(16));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0b010000", value(16));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0b01_00_00", value(16));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0b111111", value(63));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b10000", value(16));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b010000", value(16));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b01_00_00", value(16));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b111111", value(63));
}

View File

@@ -29,16 +29,16 @@ BOOST_AUTO_TEST_CASE(test_string)
BOOST_AUTO_TEST_CASE(test_string_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"The quick brown fox jumps over the lazy dog\"",
toml::value("The quick brown fox jumps over the lazy dog", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\'The quick brown fox jumps over the lazy dog\'",
toml::value("The quick brown fox jumps over the lazy dog", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"The quick brown fox \\\njumps over the lazy dog\"\"\"",
toml::value("The quick brown fox jumps over the lazy dog", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'''The quick brown fox \njumps over the lazy dog'''",
toml::value("The quick brown fox \njumps over the lazy dog", string_t::literal));
}
@@ -69,31 +69,37 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
TOML11_TEST_PARSE_EQUAL(parse_string,
"\" And when \\\"'s are in the along with # \\\"\"",
string(" And when \"'s are in the along with # \"", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"Here are fifteen apostrophes: '''''''''''''''\"",
string("Here are fifteen apostrophes: '''''''''''''''", string_t::basic));
}
BOOST_AUTO_TEST_CASE(test_basic_string_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"GitHub Cofounder & CEO\\nLikes tater tots and beer.\"",
value("GitHub Cofounder & CEO\nLikes tater tots and beer.", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"192.168.1.1\"",
value("192.168.1.1", string_t::basic));
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"",
value("\xE4\xB8\xAD\xE5\x9B\xBD", string_t::basic));
#else
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"中国\"",
value("中国", string_t::basic));
#endif
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"You'll hate me after this - #\"",
value("You'll hate me after this - #", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\" And when \\\"'s are in the along with # \\\"\"",
value(" And when \"'s are in the along with # \"", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"Here are fifteen apostrophes: '''''''''''''''\"",
value("Here are fifteen apostrophes: '''''''''''''''", string_t::basic));
}
BOOST_AUTO_TEST_CASE(test_ml_basic_string)
@@ -104,16 +110,41 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
string("The quick brown fox jumps over the lazy dog.", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
string("Here are two quotation marks: \"\". Simple enough.", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
string("Here are three quotation marks: \"\"\".", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
string("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
string("\"This,\" she said, \"is just a pointless statement.\"", string_t::basic));
}
BOOST_AUTO_TEST_CASE(test_ml_basic_string_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"\nThe quick brown \\\n\n fox jumps over \\\n the lazy dog.\"\"\"",
value("The quick brown fox jumps over the lazy dog.", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
value("The quick brown fox jumps over the lazy dog.", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
value("Here are two quotation marks: \"\". Simple enough.", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
value("Here are three quotation marks: \"\"\".", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
value("\"This,\" she said, \"is just a pointless statement.\"", string_t::basic));
}
BOOST_AUTO_TEST_CASE(test_literal_string)
@@ -134,16 +165,16 @@ BOOST_AUTO_TEST_CASE(test_literal_string)
BOOST_AUTO_TEST_CASE(test_literal_string_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'C:\\Users\\nodejs\\templates'",
value("C:\\Users\\nodejs\\templates", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'\\\\ServerX\\admin$\\system32\\'",
value("\\\\ServerX\\admin$\\system32\\", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'Tom \"Dubs\" Preston-Werner'",
value("Tom \"Dubs\" Preston-Werner", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'<\\i\\c*\\s*>'",
value("<\\i\\c*\\s*>", string_t::literal));
}
@@ -156,16 +187,34 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
TOML11_TEST_PARSE_EQUAL(parse_string,
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
string("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
TOML11_TEST_PARSE_EQUAL(parse_string,
"''''That's still pointless', she said.'''",
string("'That's still pointless', she said.", string_t::literal));
TOML11_TEST_PARSE_EQUAL(parse_string,
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
string("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal));
TOML11_TEST_PARSE_EQUAL(parse_string,
"''''This,' she said, 'is just a pointless statement.''''",
string("'This,' she said, 'is just a pointless statement.'", string_t::literal));
}
BOOST_AUTO_TEST_CASE(test_ml_literal_string_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'''I [dw]on't need \\d{2} apples'''",
value("I [dw]on't need \\d{2} apples", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value,
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
value("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"''''That's still pointless', she said.'''",
value("'That's still pointless', she said.", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"''''This,' she said, 'is just a pointless statement.''''",
value("'This,' she said, 'is just a pointless statement.'", string_t::literal));
}
BOOST_AUTO_TEST_CASE(test_unicode_escape_sequence)

View File

@@ -19,15 +19,15 @@ BOOST_AUTO_TEST_CASE(test_normal_table)
"key2 = 42\n"
"key3 = 3.14\n"
);
location<std::string> loc("test", table);
location loc("test", table);
const auto result = toml::detail::parse_ml_table(loc);
BOOST_CHECK(result.is_ok());
const auto result = toml::detail::parse_ml_table<toml::value>(loc);
BOOST_TEST(result.is_ok());
const auto data = result.unwrap();
BOOST_CHECK_EQUAL(toml::get<std::string >(data.at("key1")), "value");
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(data.at("key2")), 42);
BOOST_CHECK_EQUAL(toml::get<double >(data.at("key3")), 3.14);
BOOST_TEST(toml::get<std::string >(data.at("key1")) == "value");
BOOST_TEST(toml::get<std::int64_t>(data.at("key2")) == 42);
BOOST_TEST(toml::get<double >(data.at("key3")) == 3.14);
}
BOOST_AUTO_TEST_CASE(test_nested_table)
@@ -36,15 +36,15 @@ BOOST_AUTO_TEST_CASE(test_nested_table)
"a.b = \"value\"\n"
"a.c.d = 42\n"
);
location<std::string> loc("test", table);
location loc("test", table);
const auto result = toml::detail::parse_ml_table(loc);
BOOST_CHECK(result.is_ok());
const auto result = toml::detail::parse_ml_table<toml::value>(loc);
BOOST_TEST(result.is_ok());
const auto data = result.unwrap();
const auto a = toml::get<toml::table>(data.at("a"));
const auto c = toml::get<toml::table>(a.at("c"));
BOOST_CHECK_EQUAL(toml::get<std::string >(a.at("b")), "value");
BOOST_CHECK_EQUAL(toml::get<std::int64_t>(c.at("d")), 42);
BOOST_TEST(toml::get<std::string >(a.at("b")) == "value");
BOOST_TEST(toml::get<std::int64_t>(c.at("d")) == 42);
}

View File

@@ -9,16 +9,15 @@
#include <iostream>
#include <fstream>
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
{
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
const auto the = toml::get<toml::Table>(data.at("the"));
BOOST_CHECK_EQUAL(toml::get<std::string>(the.at("test_string")),
const auto the = toml::find<toml::table>(data, "the");
BOOST_TEST(toml::get<std::string>(the.at("test_string")) ==
std::string("\xC3\x9D\xC3\xB4\xC3\xBA\x27\xE2\x84\x93\xE2\x84\x93\x20\xCE\xBB\xC3\xA1\xC6\xAD\xC3\xA8\x20\xE2\x82\xA5\xC3\xA8\x20\xC3\xA1\xC6\x92\xC6\xAD\xC3\xA8\xC5\x99\x20\xC6\xAD\xCE\xBB\xC3\xAF\xC6\xA8\x20\x2D\x20\x23"));
const auto hard = toml::get<toml::Table>(the.at("hard"));
const auto hard = toml::get<toml::table>(the.at("hard"));
const std::vector<std::string> expected_the_hard_test_array{"] ", " # "};
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("test_array")) ==
expected_the_hard_test_array);
@@ -28,47 +27,15 @@ BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
};
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("test_array2")) ==
expected_the_hard_test_array2);
BOOST_CHECK_EQUAL(toml::get<std::string>(hard.at("another_test_string")),
BOOST_TEST(toml::get<std::string>(hard.at("another_test_string")) ==
std::string("\xC2\xA7\xC3\xA1\xE2\x82\xA5\xC3\xA8\x20\xC6\xAD\xCE\xBB\xC3\xAF\xC3\xB1\xCF\xB1\x2C\x20\xCE\xB2\xC3\xBA\xC6\xAD\x20\xCF\x89\xC3\xAF\xC6\xAD\xCE\xBB\x20\xC3\xA1\x20\xC6\xA8\xC6\xAD\xC5\x99\xC3\xAF\xC3\xB1\xCF\xB1\x20\x23"));
BOOST_CHECK_EQUAL(toml::get<std::string>(hard.at("harder_test_string")),
BOOST_TEST(toml::get<std::string>(hard.at("harder_test_string")) ==
std::string("\x20\xC3\x82\xC3\xB1\xCE\xB4\x20\xCF\x89\xCE\xBB\xC3\xA8\xC3\xB1\x20\x22\x27\xC6\xA8\x20\xC3\xA1\xC5\x99\xC3\xA8\x20\xC3\xAF\xC3\xB1\x20\xC6\xAD\xCE\xBB\xC3\xA8\x20\xC6\xA8\xC6\xAD\xC5\x99\xC3\xAF\xC3\xB1\xCF\xB1\x2C\x20\xC3\xA1\xE2\x84\x93\xC3\xB4\xC3\xB1\xCF\xB1\x20\xCF\x89\xC3\xAF\xC6\xAD\xCE\xBB\x20\x23\x20\x22"));
//
const auto bit = toml::get<toml::Table>(hard.at(std::string("\xCE\xB2\xC3\xAF\xC6\xAD\x23")));
BOOST_CHECK_EQUAL(toml::get<std::string>(bit.at(std::string("\xCF\x89\xCE\xBB\xC3\xA1\xC6\xAD\x3F"))),
const auto bit = toml::get<toml::table>(hard.at(std::string("\xCE\xB2\xC3\xAF\xC6\xAD\x23")));
BOOST_TEST(toml::get<std::string>(bit.at(std::string("\xCF\x89\xCE\xBB\xC3\xA1\xC6\xAD\x3F"))) ==
std::string("\xC3\x9D\xC3\xB4\xC3\xBA\x20\xCE\xB4\xC3\xB4\xC3\xB1\x27\xC6\xAD\x20\xC6\xAD\xCE\xBB\xC3\xAF\xC3\xB1\xC6\x99\x20\xC6\xA8\xC3\xB4\xE2\x82\xA5\xC3\xA8\x20\xC3\xBA\xC6\xA8\xC3\xA8\xC5\x99\x20\xCF\x89\xC3\xB4\xC3\xB1\x27\xC6\xAD\x20\xCE\xB4\xC3\xB4\x20\xC6\xAD\xCE\xBB\xC3\xA1\xC6\xAD\x3F"));
const std::vector<std::string> expected_multi_line_array{"]"};
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
expected_multi_line_array);
}
#else
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
{
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
const auto the = toml::get<toml::Table>(data.at("the"));
BOOST_CHECK_EQUAL(toml::get<std::string>(the.at("test_string")),
std::string(u8"Ýôú' λáƭè ₥è áƒƭèř ƭλïƨ - #"));
const auto hard = toml::get<toml::Table>(the.at("hard"));
const std::vector<std::string> expected_the_hard_test_array{"] ", " # "};
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("test_array")) ==
expected_the_hard_test_array);
const std::vector<std::string> expected_the_hard_test_array2{
std::string(u8"Tèƨƭ #11 ]ƥřôƲèδ ƭλáƭ"),
std::string(u8"Éжƥèřï₥èñƭ #9 ωáƨ á ƨúççèƨƨ")};
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("test_array2")) ==
expected_the_hard_test_array2);
BOOST_CHECK_EQUAL(toml::get<std::string>(hard.at("another_test_string")),
std::string(u8"§á₥è ƭλïñϱ, βúƭ ωïƭλ á ƨƭřïñϱ #"));
BOOST_CHECK_EQUAL(toml::get<std::string>(hard.at("harder_test_string")),
std::string(u8" Âñδ ωλèñ \"'ƨ ářè ïñ ƭλè ƨƭřïñϱ, áℓôñϱ ωïƭλ # \""));
const auto bit = toml::get<toml::Table>(hard.at(std::string(u8"βïƭ#")));
BOOST_CHECK_EQUAL(toml::get<std::string>(bit.at(std::string(u8"ωλáƭ?"))),
std::string(u8"Ýôú δôñ'ƭ ƭλïñƙ ƨô₥è úƨèř ωôñ'ƭ δô ƭλáƭ?"));
const std::vector<std::string> expected_multi_line_array{"]"};
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
expected_multi_line_array);
}
#endif

View File

@@ -8,49 +8,49 @@ BOOST_AUTO_TEST_CASE(test_construct)
{
auto s = toml::ok(42);
toml::result<int, std::string> result(s);
BOOST_CHECK(!!result);
BOOST_CHECK(result.is_ok());
BOOST_CHECK(!result.is_err());
BOOST_CHECK_EQUAL(result.unwrap(), 42);
BOOST_TEST(!!result);
BOOST_TEST(result.is_ok());
BOOST_TEST(!result.is_err());
BOOST_TEST(result.unwrap() == 42);
}
{
const auto s = toml::ok(42);
toml::result<int, std::string> result(s);
BOOST_CHECK(!!result);
BOOST_CHECK(result.is_ok());
BOOST_CHECK(!result.is_err());
BOOST_CHECK_EQUAL(result.unwrap(), 42);
BOOST_TEST(!!result);
BOOST_TEST(result.is_ok());
BOOST_TEST(!result.is_err());
BOOST_TEST(result.unwrap() == 42);
}
{
toml::result<int, std::string> result(toml::ok(42));
BOOST_CHECK(!!result);
BOOST_CHECK(result.is_ok());
BOOST_CHECK(!result.is_err());
BOOST_CHECK_EQUAL(result.unwrap(), 42);
BOOST_TEST(!!result);
BOOST_TEST(result.is_ok());
BOOST_TEST(!result.is_err());
BOOST_TEST(result.unwrap() == 42);
}
{
auto f = toml::err<std::string>("foobar");
toml::result<int, std::string> result(f);
BOOST_CHECK(!result);
BOOST_CHECK(!result.is_ok());
BOOST_CHECK(result.is_err());
BOOST_CHECK_EQUAL(result.unwrap_err(), "foobar");
BOOST_TEST(!result);
BOOST_TEST(!result.is_ok());
BOOST_TEST(result.is_err());
BOOST_TEST(result.unwrap_err() == "foobar");
}
{
const auto f = toml::err<std::string>("foobar");
toml::result<int, std::string> result(f);
BOOST_CHECK(!result);
BOOST_CHECK(!result.is_ok());
BOOST_CHECK(result.is_err());
BOOST_CHECK_EQUAL(result.unwrap_err(), "foobar");
BOOST_TEST(!result);
BOOST_TEST(!result.is_ok());
BOOST_TEST(result.is_err());
BOOST_TEST(result.unwrap_err() == "foobar");
}
{
toml::result<int, std::string> result(toml::err<std::string>("foobar"));
BOOST_CHECK(!result);
BOOST_CHECK(!result.is_ok());
BOOST_CHECK(result.is_err());
BOOST_CHECK_EQUAL(result.unwrap_err(), "foobar");
BOOST_TEST(!result);
BOOST_TEST(!result.is_ok());
BOOST_TEST(result.is_err());
BOOST_TEST(result.unwrap_err() == "foobar");
}
}
@@ -59,54 +59,54 @@ BOOST_AUTO_TEST_CASE(test_assignment)
{
toml::result<int, std::string> result(toml::err<std::string>("foobar"));
result = toml::ok(42);
BOOST_CHECK(!!result);
BOOST_CHECK(result.is_ok());
BOOST_CHECK(!result.is_err());
BOOST_CHECK_EQUAL(result.unwrap(), 42);
BOOST_TEST(!!result);
BOOST_TEST(result.is_ok());
BOOST_TEST(!result.is_err());
BOOST_TEST(result.unwrap() == 42);
}
{
toml::result<int, std::string> result(toml::err<std::string>("foobar"));
auto s = toml::ok(42);
result = s;
BOOST_CHECK(!!result);
BOOST_CHECK(result.is_ok());
BOOST_CHECK(!result.is_err());
BOOST_CHECK_EQUAL(result.unwrap(), 42);
BOOST_TEST(!!result);
BOOST_TEST(result.is_ok());
BOOST_TEST(!result.is_err());
BOOST_TEST(result.unwrap() == 42);
}
{
toml::result<int, std::string> result(toml::err<std::string>("foobar"));
const auto s = toml::ok(42);
result = s;
BOOST_CHECK(!!result);
BOOST_CHECK(result.is_ok());
BOOST_CHECK(!result.is_err());
BOOST_CHECK_EQUAL(result.unwrap(), 42);
BOOST_TEST(!!result);
BOOST_TEST(result.is_ok());
BOOST_TEST(!result.is_err());
BOOST_TEST(result.unwrap() == 42);
}
{
toml::result<int, std::string> result(toml::err<std::string>("foobar"));
result = toml::err<std::string>("hoge");
BOOST_CHECK(!result);
BOOST_CHECK(!result.is_ok());
BOOST_CHECK(result.is_err());
BOOST_CHECK_EQUAL(result.unwrap_err(), "hoge");
BOOST_TEST(!result);
BOOST_TEST(!result.is_ok());
BOOST_TEST(result.is_err());
BOOST_TEST(result.unwrap_err() == "hoge");
}
{
toml::result<int, std::string> result(toml::err<std::string>("foobar"));
auto f = toml::err<std::string>("hoge");
result = f;
BOOST_CHECK(!result);
BOOST_CHECK(!result.is_ok());
BOOST_CHECK(result.is_err());
BOOST_CHECK_EQUAL(result.unwrap_err(), "hoge");
BOOST_TEST(!result);
BOOST_TEST(!result.is_ok());
BOOST_TEST(result.is_err());
BOOST_TEST(result.unwrap_err() == "hoge");
}
{
toml::result<int, std::string> result(toml::err<std::string>("foobar"));
const auto f = toml::err<std::string>("hoge");
result = f;
BOOST_CHECK(!result);
BOOST_CHECK(!result.is_ok());
BOOST_CHECK(result.is_err());
BOOST_CHECK_EQUAL(result.unwrap_err(), "hoge");
BOOST_TEST(!result);
BOOST_TEST(!result.is_ok());
BOOST_TEST(result.is_err());
BOOST_TEST(result.unwrap_err() == "hoge");
}
}
@@ -119,10 +119,10 @@ BOOST_AUTO_TEST_CASE(test_map)
return i * 2;
});
BOOST_CHECK(!!mapped);
BOOST_CHECK(mapped.is_ok());
BOOST_CHECK(!mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap(), 42 * 2);
BOOST_TEST(!!mapped);
BOOST_TEST(mapped.is_ok());
BOOST_TEST(!mapped.is_err());
BOOST_TEST(mapped.unwrap() == 42 * 2);
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -132,10 +132,10 @@ BOOST_AUTO_TEST_CASE(test_map)
return *i;
});
BOOST_CHECK(!!mapped);
BOOST_CHECK(mapped.is_ok());
BOOST_CHECK(!mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap(), 42);
BOOST_TEST(!!mapped);
BOOST_TEST(mapped.is_ok());
BOOST_TEST(!mapped.is_err());
BOOST_TEST(mapped.unwrap() == 42);
}
{
const toml::result<int, std::string> result(toml::err<std::string>("hoge"));
@@ -144,10 +144,10 @@ BOOST_AUTO_TEST_CASE(test_map)
return i * 2;
});
BOOST_CHECK(!mapped);
BOOST_CHECK(!mapped.is_ok());
BOOST_CHECK(mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap_err(), "hoge");
BOOST_TEST(!mapped);
BOOST_TEST(!mapped.is_ok());
BOOST_TEST(mapped.is_err());
BOOST_TEST(mapped.unwrap_err() == "hoge");
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -157,10 +157,10 @@ BOOST_AUTO_TEST_CASE(test_map)
return *i;
});
BOOST_CHECK(!mapped);
BOOST_CHECK(!mapped.is_ok());
BOOST_CHECK(mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap_err(), "hoge");
BOOST_TEST(!mapped);
BOOST_TEST(!mapped.is_ok());
BOOST_TEST(mapped.is_err());
BOOST_TEST(mapped.unwrap_err() == "hoge");
}
}
@@ -173,10 +173,10 @@ BOOST_AUTO_TEST_CASE(test_map_err)
return s + s;
});
BOOST_CHECK(!!mapped);
BOOST_CHECK(mapped.is_ok());
BOOST_CHECK(!mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap(), 42);
BOOST_TEST(!!mapped);
BOOST_TEST(mapped.is_ok());
BOOST_TEST(!mapped.is_err());
BOOST_TEST(mapped.unwrap() == 42);
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -186,10 +186,10 @@ BOOST_AUTO_TEST_CASE(test_map_err)
return s + s;
});
BOOST_CHECK(!!mapped);
BOOST_CHECK(mapped.is_ok());
BOOST_CHECK(!mapped.is_err());
BOOST_CHECK_EQUAL(*(mapped.unwrap()), 42);
BOOST_TEST(!!mapped);
BOOST_TEST(mapped.is_ok());
BOOST_TEST(!mapped.is_err());
BOOST_TEST(*(mapped.unwrap()) == 42);
}
{
const toml::result<int, std::string> result(toml::err<std::string>("hoge"));
@@ -197,10 +197,10 @@ BOOST_AUTO_TEST_CASE(test_map_err)
[](const std::string s) -> std::string {
return s + s;
});
BOOST_CHECK(!mapped);
BOOST_CHECK(!mapped.is_ok());
BOOST_CHECK(mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap_err(), "hogehoge");
BOOST_TEST(!mapped);
BOOST_TEST(!mapped.is_ok());
BOOST_TEST(mapped.is_err());
BOOST_TEST(mapped.unwrap_err() == "hogehoge");
}
{
toml::result<int, std::unique_ptr<std::string>>
@@ -210,10 +210,10 @@ BOOST_AUTO_TEST_CASE(test_map_err)
return *p;
});
BOOST_CHECK(!mapped);
BOOST_CHECK(!mapped.is_ok());
BOOST_CHECK(mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap_err(), "hoge");
BOOST_TEST(!mapped);
BOOST_TEST(!mapped.is_ok());
BOOST_TEST(mapped.is_err());
BOOST_TEST(mapped.unwrap_err() == "hoge");
}
}
@@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE(test_map_or_else)
return i * 2;
}, 54);
BOOST_CHECK_EQUAL(mapped, 42 * 2);
BOOST_TEST(mapped == 42 * 2);
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE(test_map_or_else)
return *i;
}, 54);
BOOST_CHECK_EQUAL(mapped, 42);
BOOST_TEST(mapped == 42);
}
{
const toml::result<int, std::string> result(toml::err<std::string>("hoge"));
@@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE(test_map_or_else)
return i * 2;
}, 54);
BOOST_CHECK_EQUAL(mapped, 54);
BOOST_TEST(mapped == 54);
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(test_map_or_else)
return *i;
}, 54);
BOOST_CHECK_EQUAL(mapped, 54);
BOOST_TEST(mapped == 54);
}
}
@@ -268,7 +268,7 @@ BOOST_AUTO_TEST_CASE(test_map_err_or_else)
return i + i;
}, "foobar");
BOOST_CHECK_EQUAL(mapped, "foobar");
BOOST_TEST(mapped == "foobar");
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(test_map_err_or_else)
return i + i;
}, "foobar");
BOOST_CHECK_EQUAL(mapped, "foobar");
BOOST_TEST(mapped == "foobar");
}
{
const toml::result<int, std::string> result(toml::err<std::string>("hoge"));
@@ -287,7 +287,7 @@ BOOST_AUTO_TEST_CASE(test_map_err_or_else)
return i + i;
}, "foobar");
BOOST_CHECK_EQUAL(mapped, "hogehoge");
BOOST_TEST(mapped == "hogehoge");
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -297,7 +297,7 @@ BOOST_AUTO_TEST_CASE(test_map_err_or_else)
return i + i;
}, "foobar");
BOOST_CHECK_EQUAL(mapped, "hogehoge");
BOOST_TEST(mapped == "hogehoge");
}
}
@@ -311,10 +311,10 @@ BOOST_AUTO_TEST_CASE(test_and_then)
return toml::ok(i * 2);
});
BOOST_CHECK(!!mapped);
BOOST_CHECK(mapped.is_ok());
BOOST_CHECK(!mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap(), 42 * 2);
BOOST_TEST(!!mapped);
BOOST_TEST(mapped.is_ok());
BOOST_TEST(!mapped.is_err());
BOOST_TEST(mapped.unwrap() == 42 * 2);
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -324,10 +324,10 @@ BOOST_AUTO_TEST_CASE(test_and_then)
return toml::ok(*i);
});
BOOST_CHECK(!!mapped);
BOOST_CHECK(mapped.is_ok());
BOOST_CHECK(!mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap(), 42);
BOOST_TEST(!!mapped);
BOOST_TEST(mapped.is_ok());
BOOST_TEST(!mapped.is_err());
BOOST_TEST(mapped.unwrap() == 42);
}
{
const toml::result<int, std::string> result(toml::err<std::string>("hoge"));
@@ -336,10 +336,10 @@ BOOST_AUTO_TEST_CASE(test_and_then)
return toml::ok(i * 2);
});
BOOST_CHECK(!mapped);
BOOST_CHECK(!mapped.is_ok());
BOOST_CHECK(mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap_err(), "hoge");
BOOST_TEST(!mapped);
BOOST_TEST(!mapped.is_ok());
BOOST_TEST(mapped.is_err());
BOOST_TEST(mapped.unwrap_err() == "hoge");
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -349,10 +349,10 @@ BOOST_AUTO_TEST_CASE(test_and_then)
return toml::ok(*i);
});
BOOST_CHECK(!mapped);
BOOST_CHECK(!mapped.is_ok());
BOOST_CHECK(mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap_err(), "hoge");
BOOST_TEST(!mapped);
BOOST_TEST(!mapped.is_ok());
BOOST_TEST(mapped.is_err());
BOOST_TEST(mapped.unwrap_err() == "hoge");
}
}
@@ -365,10 +365,10 @@ BOOST_AUTO_TEST_CASE(test_or_else)
return toml::err(s + s);
});
BOOST_CHECK(!!mapped);
BOOST_CHECK(mapped.is_ok());
BOOST_CHECK(!mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap(), 42);
BOOST_TEST(!!mapped);
BOOST_TEST(mapped.is_ok());
BOOST_TEST(!mapped.is_err());
BOOST_TEST(mapped.unwrap() == 42);
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -378,10 +378,10 @@ BOOST_AUTO_TEST_CASE(test_or_else)
return toml::err(s + s);
});
BOOST_CHECK(!!mapped);
BOOST_CHECK(mapped.is_ok());
BOOST_CHECK(!mapped.is_err());
BOOST_CHECK_EQUAL(*mapped.unwrap(), 42);
BOOST_TEST(!!mapped);
BOOST_TEST(mapped.is_ok());
BOOST_TEST(!mapped.is_err());
BOOST_TEST(*mapped.unwrap() == 42);
}
{
const toml::result<int, std::string> result(toml::err<std::string>("hoge"));
@@ -390,10 +390,10 @@ BOOST_AUTO_TEST_CASE(test_or_else)
return toml::err(s + s);
});
BOOST_CHECK(!mapped);
BOOST_CHECK(!mapped.is_ok());
BOOST_CHECK(mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap_err(), "hogehoge");
BOOST_TEST(!mapped);
BOOST_TEST(!mapped.is_ok());
BOOST_TEST(mapped.is_err());
BOOST_TEST(mapped.unwrap_err() == "hogehoge");
}
{
toml::result<std::unique_ptr<int>, std::string>
@@ -403,10 +403,10 @@ BOOST_AUTO_TEST_CASE(test_or_else)
return toml::err(s + s);
});
BOOST_CHECK(!mapped);
BOOST_CHECK(!mapped.is_ok());
BOOST_CHECK(mapped.is_err());
BOOST_CHECK_EQUAL(mapped.unwrap_err(), "hogehoge");
BOOST_TEST(!mapped);
BOOST_TEST(!mapped.is_ok());
BOOST_TEST(mapped.is_err());
BOOST_TEST(mapped.unwrap_err() == "hogehoge");
}
}
@@ -416,10 +416,10 @@ BOOST_AUTO_TEST_CASE(test_and_or_other)
const toml::result<int, std::string> r1(toml::ok(42));
const toml::result<int, std::string> r2(toml::err<std::string>("foo"));
BOOST_CHECK_EQUAL(r1, r1.or_other(r2));
BOOST_CHECK_EQUAL(r2, r1.and_other(r2));
BOOST_CHECK_EQUAL(42, r1.or_other(r2).unwrap());
BOOST_CHECK_EQUAL("foo", r1.and_other(r2).unwrap_err());
BOOST_TEST(r1 == r1.or_other(r2));
BOOST_TEST(r2 == r1.and_other(r2));
BOOST_TEST(42 == r1.or_other(r2).unwrap());
BOOST_TEST("foo" == r1.and_other(r2).unwrap_err());
}
{
auto r1_gen = []() -> toml::result<int, std::string> {
@@ -431,10 +431,10 @@ BOOST_AUTO_TEST_CASE(test_and_or_other)
const auto r3 = r1_gen();
const auto r4 = r2_gen();
BOOST_CHECK_EQUAL(r3, r1_gen().or_other (r2_gen()));
BOOST_CHECK_EQUAL(r4, r1_gen().and_other(r2_gen()));
BOOST_CHECK_EQUAL(42, r1_gen().or_other (r2_gen()).unwrap());
BOOST_CHECK_EQUAL("foo", r1_gen().and_other(r2_gen()).unwrap_err());
BOOST_TEST(r3 == r1_gen().or_other (r2_gen()));
BOOST_TEST(r4 == r1_gen().and_other(r2_gen()));
BOOST_TEST(42 == r1_gen().or_other (r2_gen()).unwrap());
BOOST_TEST("foo" == r1_gen().and_other(r2_gen()).unwrap_err());
}
}

View File

@@ -6,9 +6,44 @@
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <deque>
#include <map>
#include <iostream>
#include <fstream>
#include <sstream>
template<typename Comment,
template<typename ...> class Table,
template<typename ...> class Array>
bool has_comment_inside(const toml::basic_value<Comment, Table, Array>& v)
{
if(!v.comments().empty())
{
return false;
}
// v itself does not have a comment.
if(v.is_array())
{
for(const auto& x : v.as_array())
{
if(has_comment_inside(x))
{
return false;
}
}
}
if(v.is_table())
{
for(const auto& x : v.as_table())
{
if(has_comment_inside(x.second))
{
return false;
}
}
}
return true;
}
BOOST_AUTO_TEST_CASE(test_example)
{
@@ -20,15 +55,146 @@ BOOST_AUTO_TEST_CASE(test_example)
auto serialized = toml::parse("tmp1.toml");
{
auto& owner = toml::get<toml::table>(serialized.at("owner"));
auto& bio = toml::get<std::string>(owner.at("bio"));
auto& owner = toml::find(serialized, "owner");
auto& bio = toml::find<std::string>(owner, "bio");
const auto CR = std::find(bio.begin(), bio.end(), '\r');
if(CR != bio.end())
{
bio.erase(CR);
}
}
BOOST_CHECK(data == serialized);
BOOST_TEST(data == serialized);
}
BOOST_AUTO_TEST_CASE(test_example_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
"toml/tests/example.toml");
{
std::ofstream ofs("tmp1_map_dq.toml");
ofs << std::setw(80) << data;
}
auto serialized = toml::parse<toml::discard_comments, std::map, std::deque>(
"tmp1_map_dq.toml");
{
auto& owner = toml::find(serialized, "owner");
auto& bio = toml::find<std::string>(owner, "bio");
const auto CR = std::find(bio.begin(), bio.end(), '\r');
if(CR != bio.end())
{
bio.erase(CR);
}
}
BOOST_TEST(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(serialized, "owner");
auto& bio = toml::find<std::string>(owner, "bio");
const auto CR = std::find(bio.begin(), bio.end(), '\r');
if(CR != bio.end())
{
bio.erase(CR);
}
}
BOOST_TEST(data == serialized);
{
std::ofstream ofs("tmp1_com1.toml");
ofs << std::setw(80) << serialized;
}
}
BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
{
{
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
{
std::ofstream ofs("tmp1_com_nocomment.toml");
ofs << std::setw(80) << toml::nocomment << data;
}
const auto serialized = toml::parse<toml::preserve_comments>("tmp1_com_nocomment.toml");
// check no comment exist
BOOST_TEST(!has_comment_inside(serialized));
}
{
const auto data_nocomment = toml::parse<toml::discard_comments>("toml/tests/example.toml");
auto serialized = toml::parse<toml::discard_comments>("tmp1_com_nocomment.toml");
{
auto& owner = toml::find(serialized, "owner");
auto& bio = toml::find<std::string>(owner, "bio");
const auto CR = std::find(bio.begin(), bio.end(), '\r');
if(CR != bio.end())
{
bio.erase(CR);
}
}
// check collectly serialized
BOOST_TEST(data_nocomment == serialized);
}
}
BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
"toml/tests/example.toml");
{
std::ofstream ofs("tmp1_com_map_dq.toml");
ofs << std::setw(80) << data;
}
auto serialized = toml::parse<toml::preserve_comments, std::map, std::deque>(
"tmp1_com_map_dq.toml");
{
auto& owner = toml::find(serialized, "owner");
auto& bio = toml::find<std::string>(owner, "bio");
const auto CR = std::find(bio.begin(), bio.end(), '\r');
if(CR != bio.end())
{
bio.erase(CR);
}
}
BOOST_TEST(data == serialized);
{
std::ofstream ofs("tmp1_com1_map_dq.toml");
ofs << std::setw(80) << serialized;
}
}
BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
{
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>("toml/tests/example.toml");
{
std::ofstream ofs("tmp1_com_map_dq_nocomment.toml");
ofs << std::setw(80) << toml::nocomment << data;
}
const auto serialized = toml::parse<toml::preserve_comments, std::map, std::deque>("tmp1_com_map_dq_nocomment.toml");
BOOST_TEST(!has_comment_inside(serialized));
}
{
const auto data_nocomment = toml::parse<toml::discard_comments>("toml/tests/example.toml");
auto serialized = toml::parse<toml::discard_comments>("tmp1_com_map_dq_nocomment.toml");
{
auto& owner = toml::find(serialized, "owner");
auto& bio = toml::find<std::string>(owner, "bio");
const auto CR = std::find(bio.begin(), bio.end(), '\r');
if(CR != bio.end())
{
bio.erase(CR);
}
}
BOOST_TEST(data_nocomment == serialized);
}
}
BOOST_AUTO_TEST_CASE(test_fruit)
@@ -39,7 +205,43 @@ BOOST_AUTO_TEST_CASE(test_fruit)
ofs << std::setw(80) << data;
}
const auto serialized = toml::parse("tmp2.toml");
BOOST_CHECK(data == serialized);
BOOST_TEST(data == serialized);
}
BOOST_AUTO_TEST_CASE(test_fruit_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
"toml/tests/fruit.toml");
{
std::ofstream ofs("tmp2.toml");
ofs << std::setw(80) << data;
}
const auto serialized = toml::parse<toml::discard_comments, std::map, std::deque>(
"tmp2.toml");
BOOST_TEST(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_TEST(data == serialized);
}
BOOST_AUTO_TEST_CASE(test_fruit_with_comments_map_dq)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
"toml/tests/fruit.toml");
{
std::ofstream ofs("tmp2_com.toml");
ofs << std::setw(80) << data;
}
const auto serialized = toml::parse<toml::preserve_comments, std::map, std::deque>("tmp2_com.toml");
BOOST_TEST(data == serialized);
}
BOOST_AUTO_TEST_CASE(test_hard_example)
@@ -50,5 +252,112 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
ofs << std::setw(80) << data;
}
const auto serialized = toml::parse("tmp3.toml");
BOOST_CHECK(data == serialized);
BOOST_TEST(data == serialized);
}
BOOST_AUTO_TEST_CASE(test_hard_example_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
"toml/tests/hard_example.toml");
{
std::ofstream ofs("tmp3.toml");
ofs << std::setw(80) << data;
}
const auto serialized = toml::parse<toml::discard_comments, std::map, std::deque>(
"tmp3.toml");
BOOST_TEST(data == serialized);
}
BOOST_AUTO_TEST_CASE(test_hard_example_with_comment)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
"toml/tests/hard_example.toml");
{
std::ofstream ofs("tmp3_com.toml");
ofs << std::setw(80) << data;
}
const auto serialized = toml::parse<toml::preserve_comments, std::map, std::deque>(
"tmp3_com.toml");
{
std::ofstream ofs("tmp3_com1.toml");
ofs << std::setw(80) << serialized;
}
BOOST_TEST(data == serialized);
}
BOOST_AUTO_TEST_CASE(test_format_key)
{
{
const toml::key key("normal_bare-key");
BOOST_TEST("normal_bare-key" == toml::format_key(key));
}
{
const toml::key key("key.include.dots");
BOOST_TEST("\"key.include.dots\"" == toml::format_key(key));
}
{
const toml::key key("key-include-unicode-\xE3\x81\x82");
BOOST_TEST("\"key-include-unicode-\xE3\x81\x82\"" == toml::format_key(key));
}
{
const toml::key key("special-chars-\\-\"-\b-\f-\r-\n-\t");
BOOST_TEST("\"special-chars-\\\\-\\\"-\\b-\\f-\\r-\\n-\\t\"" == toml::format_key(key));
}
}
// In toml11, an implicitly-defined value does not have any comments.
// So, in the following file,
// ```toml
// # comment
// [[array-of-tables]]
// foo = "bar"
// ```
// The array named "array-of-tables" does not have the comment, but the first
// element of the array has. That means that, the above file is equivalent to
// the following.
// ```toml
// array-of-tables = [
// # comment
// {foo = "bar"},
// ]
// ```
// If the array itself has a comment (value_has_comment_ == true), we should try
// to make it inline.
// ```toml
// # comment about array
// array-of-tables = [
// # comment about table element
// {foo = "bar"}
// ]
// ```
// If it is formatted as a multiline table, the two comments becomes
// indistinguishable.
// ```toml
// # comment about array
// # comment about table element
// [[array-of-tables]]
// foo = "bar"
// ```
// So we need to try to make it inline, and it force-inlines regardless
// of the line width limit.
// It may fail if the element of a table has comment. In that case,
// the array-of-tables will be formatted as a multiline table.
BOOST_AUTO_TEST_CASE(test_distinguish_comment)
{
const std::string str = R"(# comment about array itself
array_of_table = [
# comment about the first element (table)
{key = "value"},
])";
std::istringstream iss(str);
const auto data = toml::parse<toml::preserve_comments>(iss);
const auto serialized = toml::format(data, /*width = */ 0);
std::istringstream reparse(serialized);
const auto parsed = toml::parse<toml::preserve_comments>(reparse);
BOOST_TEST(parsed.at("array_of_table").comments().size() == 1u);
BOOST_TEST(parsed.at("array_of_table").comments().front() == " comment about array itself");
BOOST_TEST(parsed.at("array_of_table").at(0).comments().size() == 1u);
BOOST_TEST(parsed.at("array_of_table").at(0).comments().front() == " comment about the first element (table)");
}

154
tests/test_string.cpp Normal file
View File

@@ -0,0 +1,154 @@
#define BOOST_TEST_MODULE "test_string"
#include <boost/test/unit_test.hpp>
#include <toml.hpp>
BOOST_AUTO_TEST_CASE(test_basic_string)
{
{
const toml::string str("basic string");
std::ostringstream oss;
oss << str;
BOOST_TEST(oss.str() == "\"basic string\"");
}
{
const std::string s1 ("basic string");
const toml::string str(s1);
std::ostringstream oss;
oss << str;
BOOST_TEST(oss.str() == "\"basic string\"");
}
{
const toml::string str("basic string", toml::string_t::basic);
std::ostringstream oss;
oss << str;
BOOST_TEST(oss.str() == "\"basic string\"");
}
{
const std::string s1 ("basic string");
const toml::string str(s1, toml::string_t::basic);
std::ostringstream oss;
oss << str;
BOOST_TEST(oss.str() == "\"basic string\"");
}
}
BOOST_AUTO_TEST_CASE(test_basic_ml_string)
{
{
const toml::string str("basic\nstring");
std::ostringstream oss1;
oss1 << str;
std::ostringstream oss2;
oss2 << "\"\"\"\nbasic\nstring\\\n\"\"\"";
BOOST_TEST(oss1.str() == oss2.str());
}
{
const std::string s1 ("basic\nstring");
const toml::string str(s1);
std::ostringstream oss1;
oss1 << str;
std::ostringstream oss2;
oss2 << "\"\"\"\nbasic\nstring\\\n\"\"\"";
BOOST_TEST(oss1.str() == oss2.str());
}
{
const toml::string str("basic\nstring", toml::string_t::basic);
std::ostringstream oss1;
oss1 << str;
std::ostringstream oss2;
oss2 << "\"\"\"\nbasic\nstring\\\n\"\"\"";
BOOST_TEST(oss1.str() == oss2.str());
}
{
const std::string s1 ("basic\nstring");
const toml::string str(s1, toml::string_t::basic);
std::ostringstream oss1;
oss1 << str;
std::ostringstream oss2;
oss2 << "\"\"\"\nbasic\nstring\\\n\"\"\"";
BOOST_TEST(oss1.str() == oss2.str());
}
}
BOOST_AUTO_TEST_CASE(test_literal_string)
{
{
const toml::string str("literal string", toml::string_t::literal);
std::ostringstream oss;
oss << str;
BOOST_TEST(oss.str() == "'literal string'");
}
{
const std::string s1 ("literal string");
const toml::string str(s1, toml::string_t::literal);
std::ostringstream oss;
oss << str;
BOOST_TEST(oss.str() == "'literal string'");
}
}
BOOST_AUTO_TEST_CASE(test_literal_ml_string)
{
{
const toml::string str("literal\nstring", toml::string_t::literal);
std::ostringstream oss1;
oss1 << str;
std::ostringstream oss2;
oss2 << "'''\nliteral\nstring'''";
BOOST_TEST(oss1.str() == oss2.str());
}
{
const std::string s1 ("literal\nstring");
const toml::string str(s1, toml::string_t::literal);
std::ostringstream oss1;
oss1 << str;
std::ostringstream oss2;
oss2 << "'''\nliteral\nstring'''";
BOOST_TEST(oss1.str() == oss2.str());
}
}
BOOST_AUTO_TEST_CASE(test_string_add_assign)
{
// string literal
{
toml::string str("foo");
str += "bar";
BOOST_TEST(str.str == "foobar");
}
// std::string
{
toml::string str("foo");
std::string str2("bar");
str += str2;
BOOST_TEST(str.str == "foobar");
}
// toml::string
{
toml::string str("foo");
toml::string str2("bar");
str += str2;
BOOST_TEST(str.str == "foobar");
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
// std::string_view
{
toml::string str("foo");
str += std::string_view("bar");
BOOST_TEST(str == "foobar");
}
#endif
// std::string += toml::string
{
std::string str("foo");
toml::string str2("bar");
str += str2;
BOOST_TEST(str == "foobar");
}
}

View File

@@ -37,48 +37,48 @@ typedef std::unordered_map<std::string, dummy_type> std_unordered_map_type;
BOOST_AUTO_TEST_CASE(test_has_xxx)
{
BOOST_CHECK(toml::detail::has_iterator<std::list<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_iterator<std::forward_list<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_iterator<std::deque<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_iterator<std::vector<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_iterator<std::set<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_iterator<std::unordered_set<std::string>>::value);
BOOST_CHECK(toml::detail::has_iterator<std_array_type>::value);
BOOST_CHECK(toml::detail::has_iterator<std_map_type>::value);
BOOST_CHECK(toml::detail::has_iterator<std_unordered_map_type>::value);
BOOST_CHECK(toml::detail::has_iterator<dummy_container<dummy_type>>::value);
BOOST_TEST(toml::detail::has_iterator<std::list<dummy_type>>::value);
BOOST_TEST(toml::detail::has_iterator<std::forward_list<dummy_type>>::value);
BOOST_TEST(toml::detail::has_iterator<std::deque<dummy_type>>::value);
BOOST_TEST(toml::detail::has_iterator<std::vector<dummy_type>>::value);
BOOST_TEST(toml::detail::has_iterator<std::set<dummy_type>>::value);
BOOST_TEST(toml::detail::has_iterator<std::unordered_set<std::string>>::value);
BOOST_TEST(toml::detail::has_iterator<std_array_type>::value);
BOOST_TEST(toml::detail::has_iterator<std_map_type>::value);
BOOST_TEST(toml::detail::has_iterator<std_unordered_map_type>::value);
BOOST_TEST(toml::detail::has_iterator<dummy_container<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_value_type<std::list<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_value_type<std::forward_list<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_value_type<std::deque<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_value_type<std::vector<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_value_type<std_array_type>::value);
BOOST_CHECK(toml::detail::has_value_type<std::set<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_value_type<std::unordered_set<std::string>>::value);
BOOST_CHECK(toml::detail::has_value_type<std_map_type>::value);
BOOST_CHECK(toml::detail::has_value_type<std_unordered_map_type>::value);
BOOST_CHECK(toml::detail::has_value_type<dummy_container<dummy_type>>::value);
BOOST_TEST(toml::detail::has_value_type<std::list<dummy_type>>::value);
BOOST_TEST(toml::detail::has_value_type<std::forward_list<dummy_type>>::value);
BOOST_TEST(toml::detail::has_value_type<std::deque<dummy_type>>::value);
BOOST_TEST(toml::detail::has_value_type<std::vector<dummy_type>>::value);
BOOST_TEST(toml::detail::has_value_type<std_array_type>::value);
BOOST_TEST(toml::detail::has_value_type<std::set<dummy_type>>::value);
BOOST_TEST(toml::detail::has_value_type<std::unordered_set<std::string>>::value);
BOOST_TEST(toml::detail::has_value_type<std_map_type>::value);
BOOST_TEST(toml::detail::has_value_type<std_unordered_map_type>::value);
BOOST_TEST(toml::detail::has_value_type<dummy_container<dummy_type>>::value);
BOOST_CHECK(toml::detail::has_key_type<std_map_type>::value);
BOOST_CHECK(toml::detail::has_key_type<std_unordered_map_type>::value);
BOOST_CHECK(toml::detail::has_mapped_type<std_map_type>::value);
BOOST_CHECK(toml::detail::has_mapped_type<std_unordered_map_type>::value);
BOOST_TEST(toml::detail::has_key_type<std_map_type>::value);
BOOST_TEST(toml::detail::has_key_type<std_unordered_map_type>::value);
BOOST_TEST(toml::detail::has_mapped_type<std_map_type>::value);
BOOST_TEST(toml::detail::has_mapped_type<std_unordered_map_type>::value);
}
BOOST_AUTO_TEST_CASE(test_is_xxx)
{
BOOST_CHECK(toml::detail::is_container<std::list<dummy_type>>::value);
BOOST_CHECK(toml::detail::is_container<std::forward_list<dummy_type>>::value);
BOOST_CHECK(toml::detail::is_container<std::deque<dummy_type>>::value);
BOOST_CHECK(toml::detail::is_container<std::vector<dummy_type>>::value);
BOOST_CHECK(toml::detail::is_container<std_array_type>::value);
BOOST_CHECK(toml::detail::is_container<std::set<dummy_type>>::value);
BOOST_CHECK(toml::detail::is_container<std::unordered_set<std::string>>::value);
BOOST_CHECK(toml::detail::is_container<dummy_container<dummy_type>>::value);
BOOST_TEST(toml::detail::is_container<std::list<dummy_type>>::value);
BOOST_TEST(toml::detail::is_container<std::forward_list<dummy_type>>::value);
BOOST_TEST(toml::detail::is_container<std::deque<dummy_type>>::value);
BOOST_TEST(toml::detail::is_container<std::vector<dummy_type>>::value);
BOOST_TEST(toml::detail::is_container<std_array_type>::value);
BOOST_TEST(toml::detail::is_container<std::set<dummy_type>>::value);
BOOST_TEST(toml::detail::is_container<std::unordered_set<std::string>>::value);
BOOST_TEST(toml::detail::is_container<dummy_container<dummy_type>>::value);
BOOST_CHECK(!toml::detail::is_container<std_map_type>::value);
BOOST_CHECK(!toml::detail::is_container<std_unordered_map_type>::value);
BOOST_TEST(!toml::detail::is_container<std_map_type>::value);
BOOST_TEST(!toml::detail::is_container<std_unordered_map_type>::value);
BOOST_CHECK(toml::detail::is_map<std_map_type>::value);
BOOST_CHECK(toml::detail::is_map<std_unordered_map_type>::value);
BOOST_TEST(toml::detail::is_map<std_map_type>::value);
BOOST_TEST(toml::detail::is_map<std_unordered_map_type>::value);
}

View File

@@ -9,74 +9,41 @@
#include <vector>
#include <array>
BOOST_AUTO_TEST_CASE(test_resize)
BOOST_AUTO_TEST_CASE(test_try_reserve)
{
{
typedef std::vector<int> resizable_type;
typedef std::array<int,1> non_resizable_type;
BOOST_CHECK(toml::detail::has_resize_method<resizable_type>::value);
BOOST_CHECK(!toml::detail::has_resize_method<non_resizable_type>::value);
// since BOOST_TEST is a macro, it cannot handle commas correctly.
// When toml::detail::has_reserve_method<std::array<int, 1>>::value
// is passed to a macro, C preprocessor considers
// toml::detail::has_reserve_method<std::array<int as the first argument
// and 1>>::value as the second argument. We need an alias to avoid
// this problem.
using reservable_type = std::vector<int> ;
using nonreservable_type = std::array<int, 1>;
BOOST_TEST( toml::detail::has_reserve_method<reservable_type >::value);
BOOST_TEST(!toml::detail::has_reserve_method<nonreservable_type>::value);
}
{
bool thrown = false;
std::vector<int> v;
try
{
toml::resize(v, 10);
}
catch(std::exception& ex)
{
thrown = true;
}
BOOST_CHECK(!thrown);
BOOST_CHECK_EQUAL(v.size(), 10u);
}
{
bool thrown = false;
std::array<int, 15> a;
try
{
toml::resize(a, 10);
}
catch(std::exception& ex)
{
thrown = true;
}
BOOST_CHECK(!thrown);
BOOST_CHECK_EQUAL(a.size(), 15u);
}
{
bool thrown = false;
std::array<int, 15> a;
try
{
toml::resize(a, 20);
}
catch(std::exception& ex)
{
thrown = true;
}
BOOST_CHECK(thrown);
toml::try_reserve(v, 100);
BOOST_TEST(v.capacity() == 100u);
}
}
BOOST_AUTO_TEST_CASE(test_concat_to_string)
{
const std::string cat = toml::concat_to_string("foo", "bar", 42);
BOOST_CHECK(cat == "foobar42");
BOOST_TEST(cat == "foobar42");
}
BOOST_AUTO_TEST_CASE(test_from_string)
{
{
const std::string str("123");
BOOST_CHECK_EQUAL(toml::from_string<int>(str, 0), 123);
BOOST_TEST(toml::from_string<int>(str, 0) == 123);
}
{
const std::string str("01");
BOOST_CHECK_EQUAL(toml::from_string<int>(str, 0), 1);
BOOST_TEST(toml::from_string<int>(str, 0) == 1);
}
}

File diff suppressed because it is too large Load Diff

12
tests/test_windows.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include <windows.h>
#include <toml.hpp>
#include <iostream>
int main()
{
using namespace toml::literals::toml_literals;
const auto data = R"(windows = "defines min and max as a macro")"_toml;
std::cout << toml::find<std::string>(data, "windows") << std::endl;
return 0;
}

View File

@@ -25,18 +25,14 @@
#ifndef TOML_FOR_MODERN_CPP
#define TOML_FOR_MODERN_CPP
#ifndef __cplusplus
# error "__cplusplus is not defined"
#endif
#if __cplusplus < 201103L && _MSC_VER < 1900
# error "toml11 requires C++11 or later."
#endif
#define TOML11_VERSION_MAJOR 3
#define TOML11_VERSION_MINOR 7
#define TOML11_VERSION_PATCH 1
#include "toml/parser.hpp"
#include "toml/literal.hpp"
#include "toml/serializer.hpp"
#include "toml/from_toml.hpp"
#include "toml/get.hpp"
#include "toml/macros.hpp"
#endif// TOML_FOR_MODERN_CPP

64
toml/color.hpp Normal file
View File

@@ -0,0 +1,64 @@
#ifndef TOML11_COLOR_HPP
#define TOML11_COLOR_HPP
#include <cstdint>
#include <ostream>
#ifdef TOML11_COLORIZE_ERROR_MESSAGE
#define TOML11_ERROR_MESSAGE_COLORIZED true
#else
#define TOML11_ERROR_MESSAGE_COLORIZED false
#endif
namespace toml
{
// put ANSI escape sequence to ostream
namespace color_ansi
{
namespace detail
{
inline int colorize_index()
{
static const int index = std::ios_base::xalloc();
return index;
}
} // detail
inline std::ostream& colorize(std::ostream& os)
{
// by default, it is zero.
os.iword(detail::colorize_index()) = 1;
return os;
}
inline std::ostream& nocolorize(std::ostream& os)
{
os.iword(detail::colorize_index()) = 0;
return os;
}
inline std::ostream& reset (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[00m";} return os;}
inline std::ostream& bold (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[01m";} return os;}
inline std::ostream& grey (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[30m";} return os;}
inline std::ostream& red (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[31m";} return os;}
inline std::ostream& green (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[32m";} return os;}
inline std::ostream& yellow (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[33m";} return os;}
inline std::ostream& blue (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[34m";} return os;}
inline std::ostream& magenta(std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[35m";} return os;}
inline std::ostream& cyan (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
inline std::ostream& white (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
} // color_ansi
// ANSI escape sequence is the only and default colorization method currently
namespace color = color_ansi;
} // toml
#endif// TOML11_COLOR_HPP

View File

@@ -2,15 +2,20 @@
// Distributed under the MIT License.
#ifndef TOML11_COMBINATOR_HPP
#define TOML11_COMBINATOR_HPP
#include "traits.hpp"
#include "result.hpp"
#include "utility.hpp"
#include "region.hpp"
#include <type_traits>
#include <cassert>
#include <cctype>
#include <cstdio>
#include <array>
#include <iomanip>
#include <iterator>
#include <limits>
#include <iomanip>
#include <cctype>
#include <type_traits>
#include "region.hpp"
#include "result.hpp"
#include "traits.hpp"
#include "utility.hpp"
// they scans characters and returns region if it matches to the condition.
// when they fail, it does not change the location.
@@ -24,7 +29,7 @@ namespace detail
// to output character as an error message.
inline std::string show_char(const char c)
{
// It supress an error that occurs only in Debug mode of MSVC++ on Windows.
// It suppresses an error that occurs only in Debug mode of MSVC++ on Windows.
// I'm not completely sure but they check the value of char to be in the
// range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes
// has negative value (if char has sign). So here it re-interprets c as
@@ -38,10 +43,13 @@ inline std::string show_char(const char c)
}
else
{
std::ostringstream oss;
oss << "0x" << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<int>(c);
return oss.str();
std::array<char, 5> buf;
buf.fill('\0');
const auto r = std::snprintf(
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
(void) r; // Unused variable warning
assert(r == static_cast<int>(buf.size()) - 1);
return std::string(buf.data());
}
}
@@ -50,27 +58,21 @@ struct character
{
static constexpr char target = C;
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
if(loc.iter() == loc.end()) {return none();}
const auto first = loc.iter();
const char c = *(loc.iter());
if(c != target)
{
return err(concat_to_string("expected '", show_char(target),
"' but got '", show_char(c), "'."));
return none();
}
++(loc.iter()); // update location
loc.advance(); // update location
return ok(region<Cont>(loc, first, loc.iter()));
return ok(region(loc, first, loc.iter()));
}
static std::string pattern() {return show_char(target);}
};
template<char C>
constexpr char character<C>::target;
@@ -85,30 +87,20 @@ struct in_range
static constexpr char upper = Up;
static constexpr char lower = Low;
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
if(loc.iter() == loc.end()) {return none();}
const auto first = loc.iter();
const char c = *(loc.iter());
if(c < lower || upper < c)
{
return err(concat_to_string("expected character in range "
"[", show_char(lower), ", ", show_char(upper), "] but got ",
"'", show_char(c), "'."));
return none();
}
++(loc.iter());
return ok(region<Cont>(loc, first, loc.iter()));
}
static std::string pattern()
{
return concat_to_string("[",show_char(lower),"-",show_char(upper),"]");
loc.advance();
return ok(region(loc, first, loc.iter()));
}
};
template<char L, char U> constexpr char in_range<L, U>::upper;
@@ -119,30 +111,20 @@ template<char L, char U> constexpr char in_range<L, U>::lower;
template<typename Combinator>
struct exclude
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
if(loc.iter() == loc.end()) {return none();}
auto first = loc.iter();
auto rslt = Combinator::invoke(loc);
if(rslt.is_ok())
{
loc.iter() = first; // rollback
return err(concat_to_string(
"invalid pattern (", Combinator::pattern(), ") appeared ",
rslt.unwrap().str()));
loc.reset(first);
return none();
}
loc.iter() = std::next(first);
return ok(region<Cont>(loc, first, loc.iter()));
}
static std::string pattern()
{
return concat_to_string("^(", Combinator::pattern(), ')');
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
return ok(region(loc, first, loc.iter()));
}
};
@@ -150,23 +132,15 @@ struct exclude
template<typename Combinator>
struct maybe
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
const auto rslt = Combinator::invoke(loc);
if(rslt.is_ok())
{
return rslt;
}
return ok(region<Cont>(loc));
}
static std::string pattern()
{
return concat_to_string('(', Combinator::pattern(), ")?");
return ok(region(loc));
}
};
@@ -176,61 +150,52 @@ struct sequence;
template<typename Head, typename ... Tail>
struct sequence<Head, Tail...>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
const auto first = loc.iter();
const auto rslt = Head::invoke(loc);
auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
}
// called from the above function only, recursively.
template<typename Cont, typename Iterator>
static result<region<Cont>, std::string>
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
template<typename Iterator>
static result<region, none_t>
invoke(location& loc, region reg, Iterator first)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
reg += rslt.unwrap(); // concat regions
return sequence<Tail...>::invoke(loc, std::move(reg), first);
}
static std::string pattern()
{
return concat_to_string(Head::pattern(), sequence<Tail...>::pattern());
}
};
template<typename Head>
struct sequence<Head>
{
// would be called from sequence<T ...>::invoke only.
template<typename Cont, typename Iterator>
static result<region<Cont>, std::string>
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
template<typename Iterator>
static result<region, none_t>
invoke(location& loc, region reg, Iterator first)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
reg += rslt.unwrap(); // concat regions
return ok(reg);
}
static std::string pattern() {return Head::pattern();}
};
template<typename ... Ts>
@@ -239,36 +204,22 @@ struct either;
template<typename Head, typename ... Tail>
struct either<Head, Tail...>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
const auto rslt = Head::invoke(loc);
if(rslt.is_ok()) {return rslt;}
return either<Tail...>::invoke(loc);
}
static std::string pattern()
{
return concat_to_string('(', Head::pattern(), ")|", either<Tail...>::pattern());
}
};
template<typename Head>
struct either<Head>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
return Head::invoke(loc);
}
static std::string pattern()
{
return concat_to_string('(', Head::pattern(), ')');
}
};
template<typename T, typename N>
@@ -281,36 +232,32 @@ struct unlimited{};
template<typename T, std::size_t N>
struct repeat<T, exactly<N>>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
region<Cont> retval(loc);
region retval(loc);
const auto first = loc.iter();
for(std::size_t i=0; i<N; ++i)
{
auto rslt = T::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
retval += rslt.unwrap();
}
return ok(std::move(retval));
}
static std::string pattern()
{
return concat_to_string('(', T::pattern(), "){", N, '}');
}
};
template<typename T, std::size_t N>
struct repeat<T, at_least<N>>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
region<Cont> retval(loc);
region retval(loc);
const auto first = loc.iter();
for(std::size_t i=0; i<N; ++i)
@@ -318,8 +265,8 @@ struct repeat<T, at_least<N>>
auto rslt = T::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
retval += rslt.unwrap();
}
@@ -333,19 +280,15 @@ struct repeat<T, at_least<N>>
retval += rslt.unwrap();
}
}
static std::string pattern()
{
return concat_to_string('(',T::pattern(), "){", N, ",}");
}
};
template<typename T>
struct repeat<T, unlimited>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region, none_t>
invoke(location& loc)
{
region<Cont> retval(loc);
region retval(loc);
while(true)
{
auto rslt = T::invoke(loc);
@@ -356,7 +299,6 @@ struct repeat<T, unlimited>
retval += rslt.unwrap();
}
}
static std::string pattern() {return concat_to_string('(', T::pattern(), ")*");}
};
} // detail

472
toml/comments.hpp Normal file
View File

@@ -0,0 +1,472 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_COMMENTS_HPP
#define TOML11_COMMENTS_HPP
#include <initializer_list>
#include <iterator>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
#else
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
#endif
// This file provides mainly two classes, `preserve_comments` and `discard_comments`.
// Those two are a container that have the same interface as `std::vector<std::string>`
// but bahaves in the opposite way. `preserve_comments` is just the same as
// `std::vector<std::string>` and each `std::string` corresponds to a comment line.
// Conversely, `discard_comments` discards all the strings and ignores everything
// assigned in it. `discard_comments` is always empty and you will encounter an
// error whenever you access to the element.
namespace toml
{
struct discard_comments; // forward decl
// use it in the following way
//
// const toml::basic_value<toml::preserve_comments> data =
// toml::parse<toml::preserve_comments>("example.toml");
//
// the interface is almost the same as std::vector<std::string>.
struct preserve_comments
{
// `container_type` is not provided in discard_comments.
// do not use this inner-type in a generic code.
using container_type = std::vector<std::string>;
using size_type = container_type::size_type;
using difference_type = container_type::difference_type;
using value_type = container_type::value_type;
using reference = container_type::reference;
using const_reference = container_type::const_reference;
using pointer = container_type::pointer;
using const_pointer = container_type::const_pointer;
using iterator = container_type::iterator;
using const_iterator = container_type::const_iterator;
using reverse_iterator = container_type::reverse_iterator;
using const_reverse_iterator = container_type::const_reverse_iterator;
preserve_comments() = default;
~preserve_comments() = default;
preserve_comments(preserve_comments const&) = default;
preserve_comments(preserve_comments &&) = default;
preserve_comments& operator=(preserve_comments const&) = default;
preserve_comments& operator=(preserve_comments &&) = default;
explicit preserve_comments(const std::vector<std::string>& c): comments(c){}
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) {}
preserve_comments(size_type n, const std::string& x): comments(n, x) {}
preserve_comments(std::initializer_list<std::string> x): comments(x) {}
template<typename InputIterator>
preserve_comments(InputIterator first, InputIterator last)
: comments(first, last)
{}
template<typename InputIterator>
void assign(InputIterator first, InputIterator last) {comments.assign(first, last);}
void assign(std::initializer_list<std::string> ini) {comments.assign(ini);}
void assign(size_type n, const std::string& val) {comments.assign(n, val);}
// Related to the issue #97.
//
// It is known that `std::vector::insert` and `std::vector::erase` in
// the standard library implementation included in GCC 4.8.5 takes
// `std::vector::iterator` instead of `std::vector::const_iterator`.
// Because of the const-correctness, we cannot convert a `const_iterator` to
// an `iterator`. It causes compilation error in GCC 4.8.5.
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)
# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805
# define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
# endif
#endif
#ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
iterator insert(iterator p, const std::string& x)
{
return comments.insert(p, x);
}
iterator insert(iterator p, std::string&& x)
{
return comments.insert(p, std::move(x));
}
void insert(iterator p, size_type n, const std::string& x)
{
return comments.insert(p, n, x);
}
template<typename InputIterator>
void insert(iterator p, InputIterator first, InputIterator last)
{
return comments.insert(p, first, last);
}
void insert(iterator p, std::initializer_list<std::string> ini)
{
return comments.insert(p, ini);
}
template<typename ... Ts>
iterator emplace(iterator p, Ts&& ... args)
{
return comments.emplace(p, std::forward<Ts>(args)...);
}
iterator erase(iterator pos) {return comments.erase(pos);}
iterator erase(iterator first, iterator last)
{
return comments.erase(first, last);
}
#else
iterator insert(const_iterator p, const std::string& x)
{
return comments.insert(p, x);
}
iterator insert(const_iterator p, std::string&& x)
{
return comments.insert(p, std::move(x));
}
iterator insert(const_iterator p, size_type n, const std::string& x)
{
return comments.insert(p, n, x);
}
template<typename InputIterator>
iterator insert(const_iterator p, InputIterator first, InputIterator last)
{
return comments.insert(p, first, last);
}
iterator insert(const_iterator p, std::initializer_list<std::string> ini)
{
return comments.insert(p, ini);
}
template<typename ... Ts>
iterator emplace(const_iterator p, Ts&& ... args)
{
return comments.emplace(p, std::forward<Ts>(args)...);
}
iterator erase(const_iterator pos) {return comments.erase(pos);}
iterator erase(const_iterator first, const_iterator last)
{
return comments.erase(first, last);
}
#endif
void swap(preserve_comments& other) {comments.swap(other.comments);}
void push_back(const std::string& v) {comments.push_back(v);}
void push_back(std::string&& v) {comments.push_back(std::move(v));}
void pop_back() {comments.pop_back();}
template<typename ... Ts>
void emplace_back(Ts&& ... args) {comments.emplace_back(std::forward<Ts>(args)...);}
void clear() {comments.clear();}
size_type size() const noexcept {return comments.size();}
size_type max_size() const noexcept {return comments.max_size();}
size_type capacity() const noexcept {return comments.capacity();}
bool empty() const noexcept {return comments.empty();}
void reserve(size_type n) {comments.reserve(n);}
void resize(size_type n) {comments.resize(n);}
void resize(size_type n, const std::string& c) {comments.resize(n, c);}
void shrink_to_fit() {comments.shrink_to_fit();}
reference operator[](const size_type n) noexcept {return comments[n];}
const_reference operator[](const size_type n) const noexcept {return comments[n];}
reference at(const size_type n) {return comments.at(n);}
const_reference at(const size_type n) const {return comments.at(n);}
reference front() noexcept {return comments.front();}
const_reference front() const noexcept {return comments.front();}
reference back() noexcept {return comments.back();}
const_reference back() const noexcept {return comments.back();}
pointer data() noexcept {return comments.data();}
const_pointer data() const noexcept {return comments.data();}
iterator begin() noexcept {return comments.begin();}
iterator end() noexcept {return comments.end();}
const_iterator begin() const noexcept {return comments.begin();}
const_iterator end() const noexcept {return comments.end();}
const_iterator cbegin() const noexcept {return comments.cbegin();}
const_iterator cend() const noexcept {return comments.cend();}
reverse_iterator rbegin() noexcept {return comments.rbegin();}
reverse_iterator rend() noexcept {return comments.rend();}
const_reverse_iterator rbegin() const noexcept {return comments.rbegin();}
const_reverse_iterator rend() const noexcept {return comments.rend();}
const_reverse_iterator crbegin() const noexcept {return comments.crbegin();}
const_reverse_iterator crend() const noexcept {return comments.crend();}
friend bool operator==(const preserve_comments&, const preserve_comments&);
friend bool operator!=(const preserve_comments&, const preserve_comments&);
friend bool operator< (const preserve_comments&, const preserve_comments&);
friend bool operator<=(const preserve_comments&, const preserve_comments&);
friend bool operator> (const preserve_comments&, const preserve_comments&);
friend bool operator>=(const preserve_comments&, const preserve_comments&);
friend void swap(preserve_comments&, std::vector<std::string>&);
friend void swap(std::vector<std::string>&, preserve_comments&);
private:
container_type comments;
};
inline bool operator==(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments == rhs.comments;}
inline bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments != rhs.comments;}
inline bool operator< (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments < rhs.comments;}
inline bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments <= rhs.comments;}
inline bool operator> (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments > rhs.comments;}
inline bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments >= rhs.comments;}
inline void swap(preserve_comments& lhs, preserve_comments& rhs)
{
lhs.swap(rhs);
return;
}
inline void swap(preserve_comments& lhs, std::vector<std::string>& rhs)
{
lhs.comments.swap(rhs);
return;
}
inline void swap(std::vector<std::string>& lhs, preserve_comments& rhs)
{
lhs.swap(rhs.comments);
return;
}
template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const preserve_comments& com)
{
for(const auto& c : com)
{
os << '#' << c << '\n';
}
return os;
}
namespace detail
{
// To provide the same interface with `preserve_comments`, `discard_comments`
// should have an iterator. But it does not contain anything, so we need to
// add an iterator that points nothing.
//
// It always points null, so DO NOT unwrap this iterator. It always crashes
// your program.
template<typename T, bool is_const>
struct empty_iterator
{
using value_type = T;
using reference_type = typename std::conditional<is_const, T const&, T&>::type;
using pointer_type = typename std::conditional<is_const, T const*, T*>::type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
empty_iterator() = default;
~empty_iterator() = default;
empty_iterator(empty_iterator const&) = default;
empty_iterator(empty_iterator &&) = default;
empty_iterator& operator=(empty_iterator const&) = default;
empty_iterator& operator=(empty_iterator &&) = default;
// DO NOT call these operators.
reference_type operator*() const noexcept {std::terminate();}
pointer_type operator->() const noexcept {return nullptr;}
reference_type operator[](difference_type) const noexcept {return this->operator*();}
// These operators do nothing.
empty_iterator& operator++() noexcept {return *this;}
empty_iterator operator++(int) noexcept {return *this;}
empty_iterator& operator--() noexcept {return *this;}
empty_iterator operator--(int) noexcept {return *this;}
empty_iterator& operator+=(difference_type) noexcept {return *this;}
empty_iterator& operator-=(difference_type) noexcept {return *this;}
empty_iterator operator+(difference_type) const noexcept {return *this;}
empty_iterator operator-(difference_type) const noexcept {return *this;}
};
template<typename T, bool C>
bool operator==(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
template<typename T, bool C>
bool operator!=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
template<typename T, bool C>
bool operator< (const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
template<typename T, bool C>
bool operator<=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
template<typename T, bool C>
bool operator> (const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
template<typename T, bool C>
bool operator>=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
template<typename T, bool C>
typename empty_iterator<T, C>::difference_type
operator-(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return 0;}
template<typename T, bool C>
empty_iterator<T, C>
operator+(typename empty_iterator<T, C>::difference_type, const empty_iterator<T, C>& rhs) noexcept {return rhs;}
template<typename T, bool C>
empty_iterator<T, C>
operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::difference_type) noexcept {return lhs;}
} // detail
// The default comment type. It discards all the comments. It requires only one
// byte to contain, so the memory footprint is smaller than preserve_comments.
//
// It just ignores `push_back`, `insert`, `erase`, and any other modifications.
// IT always returns size() == 0, the iterator taken by `begin()` is always the
// same as that of `end()`, and accessing through `operator[]` or iterators
// always causes a segmentation fault. DO NOT access to the element of this.
//
// Why this is chose as the default type is because the last version (2.x.y)
// does not contain any comments in a value. To minimize the impact on the
// efficiency, this is chosen as a default.
//
// To reduce the memory footprint, later we can try empty base optimization (EBO).
struct discard_comments
{
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using value_type = std::string;
using reference = std::string&;
using const_reference = std::string const&;
using pointer = std::string*;
using const_pointer = std::string const*;
using iterator = detail::empty_iterator<std::string, false>;
using const_iterator = detail::empty_iterator<std::string, true>;
using reverse_iterator = detail::empty_iterator<std::string, false>;
using const_reverse_iterator = detail::empty_iterator<std::string, true>;
discard_comments() = default;
~discard_comments() = default;
discard_comments(discard_comments const&) = default;
discard_comments(discard_comments &&) = default;
discard_comments& operator=(discard_comments const&) = default;
discard_comments& operator=(discard_comments &&) = default;
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 {}
discard_comments(size_type, const std::string&) noexcept {}
discard_comments(std::initializer_list<std::string>) noexcept {}
template<typename InputIterator>
discard_comments(InputIterator, InputIterator) noexcept {}
template<typename InputIterator>
void assign(InputIterator, InputIterator) noexcept {}
void assign(std::initializer_list<std::string>) noexcept {}
void assign(size_type, const std::string&) noexcept {}
iterator insert(const_iterator, const std::string&) {return iterator{};}
iterator insert(const_iterator, std::string&&) {return iterator{};}
iterator insert(const_iterator, size_type, const std::string&) {return iterator{};}
template<typename InputIterator>
iterator insert(const_iterator, InputIterator, InputIterator) {return iterator{};}
iterator insert(const_iterator, std::initializer_list<std::string>) {return iterator{};}
template<typename ... Ts>
iterator emplace(const_iterator, Ts&& ...) {return iterator{};}
iterator erase(const_iterator) {return iterator{};}
iterator erase(const_iterator, const_iterator) {return iterator{};}
void swap(discard_comments&) {return;}
void push_back(const std::string&) {return;}
void push_back(std::string&& ) {return;}
void pop_back() {return;}
template<typename ... Ts>
void emplace_back(Ts&& ...) {return;}
void clear() {return;}
size_type size() const noexcept {return 0;}
size_type max_size() const noexcept {return 0;}
size_type capacity() const noexcept {return 0;}
bool empty() const noexcept {return true;}
void reserve(size_type) {return;}
void resize(size_type) {return;}
void resize(size_type, const std::string&) {return;}
void shrink_to_fit() {return;}
// DO NOT access to the element of this container. This container is always
// empty, so accessing through operator[], front/back, data causes address
// error.
reference operator[](const size_type) noexcept {return *data();}
const_reference operator[](const size_type) const noexcept {return *data();}
reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}
const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
reference front() noexcept {return *data();}
const_reference front() const noexcept {return *data();}
reference back() noexcept {return *data();}
const_reference back() const noexcept {return *data();}
pointer data() noexcept {return nullptr;}
const_pointer data() const noexcept {return nullptr;}
iterator begin() noexcept {return iterator{};}
iterator end() noexcept {return iterator{};}
const_iterator begin() const noexcept {return const_iterator{};}
const_iterator end() const noexcept {return const_iterator{};}
const_iterator cbegin() const noexcept {return const_iterator{};}
const_iterator cend() const noexcept {return const_iterator{};}
reverse_iterator rbegin() noexcept {return iterator{};}
reverse_iterator rend() noexcept {return iterator{};}
const_reverse_iterator rbegin() const noexcept {return const_iterator{};}
const_reverse_iterator rend() const noexcept {return const_iterator{};}
const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
const_reverse_iterator crend() const noexcept {return const_iterator{};}
};
inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}
inline bool operator!=(const discard_comments&, const discard_comments&) noexcept {return false;}
inline bool operator< (const discard_comments&, const discard_comments&) noexcept {return false;}
inline bool operator<=(const discard_comments&, const discard_comments&) noexcept {return true;}
inline bool operator> (const discard_comments&, const discard_comments&) noexcept {return false;}
inline bool operator>=(const discard_comments&, const discard_comments&) noexcept {return true;}
inline void swap(const discard_comments&, const discard_comments&) noexcept {return;}
template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const discard_comments&)
{
return os;
}
} // toml11
#endif// TOML11_COMMENTS_HPP

View File

@@ -2,15 +2,16 @@
// Distributed under the MIT License.
#ifndef TOML11_DATETIME_HPP
#define TOML11_DATETIME_HPP
#include <chrono>
#include <tuple>
#include <array>
#include <ostream>
#include <iomanip>
#include <cstdint>
#include <cstdlib>
#include <ctime>
#include <array>
#include <chrono>
#include <iomanip>
#include <ostream>
#include <tuple>
namespace toml
{
@@ -20,31 +21,53 @@ namespace toml
namespace detail
{
// TODO: find more sophisticated way to handle this
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE
#if defined(_MSC_VER)
inline std::tm localtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::localtime_s(&dst, src);
if (result) { throw std::runtime_error("localtime_s failed."); }
return dst;
}
inline std::tm gmtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::gmtime_s(&dst, src);
if (result) { throw std::runtime_error("gmtime_s failed."); }
return dst;
}
#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
inline std::tm localtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::localtime_r(src, &dst);
if(!result)
{
throw std::runtime_error("localtime_r failed.");
}
if (!result) { throw std::runtime_error("localtime_r failed."); }
return dst;
}
#else
// XXX: On Windows, std::localtime is thread-safe because they uses thread-local
// storage to store the instance of std::tm. On the other platforms, it may not
// be thread-safe.
inline std::tm gmtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::gmtime_r(src, &dst);
if (!result) { throw std::runtime_error("gmtime_r failed."); }
return dst;
}
#else // fallback. not threadsafe
inline std::tm localtime_s(const std::time_t* src)
{
const auto result = std::localtime(src);
if(!result) {throw std::runtime_error("localtime failed.");}
if (!result) { throw std::runtime_error("localtime failed."); }
return *result;
}
inline std::tm gmtime_s(const std::time_t* src)
{
const auto result = std::gmtime(src);
if (!result) { throw std::runtime_error("gmtime failed."); }
return *result;
}
#endif
} // detail
enum class month_t : std::int8_t
enum class month_t : std::uint8_t
{
Jan = 0,
Feb = 1,
@@ -96,9 +119,9 @@ struct local_date
t.tm_sec = 0;
t.tm_min = 0;
t.tm_hour = 0;
t.tm_mday = this->day;
t.tm_mon = this->month;
t.tm_year = this->year - 1900;
t.tm_mday = static_cast<int>(this->day);
t.tm_mon = static_cast<int>(this->month);
t.tm_year = static_cast<int>(this->year) - 1900;
t.tm_wday = 0; // the value will be ignored
t.tm_yday = 0; // the value will be ignored
t.tm_isdst = -1;
@@ -150,9 +173,9 @@ template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
{
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month + 1) << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day );
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day ) ;
return os;
}
@@ -186,22 +209,22 @@ struct local_time
explicit local_time(const std::chrono::duration<Rep, Period>& t)
{
const auto h = std::chrono::duration_cast<std::chrono::hours>(t);
this->hour = h.count();
this->hour = static_cast<std::uint8_t>(h.count());
const auto t2 = t - h;
const auto m = std::chrono::duration_cast<std::chrono::minutes>(t2);
this->minute = m.count();
this->minute = static_cast<std::uint8_t>(m.count());
const auto t3 = t2 - m;
const auto s = std::chrono::duration_cast<std::chrono::seconds>(t3);
this->second = s.count();
this->second = static_cast<std::uint8_t>(s.count());
const auto t4 = t3 - s;
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t4);
this->millisecond = ms.count();
this->millisecond = static_cast<std::uint16_t>(ms.count());
const auto t5 = t4 - ms;
const auto us = std::chrono::duration_cast<std::chrono::microseconds>(t5);
this->microsecond = us.count();
this->microsecond = static_cast<std::uint16_t>(us.count());
const auto t6 = t5 - us;
const auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(t6);
this->nanosecond = ns.count();
this->nanosecond = static_cast<std::uint16_t>(ns.count());
}
operator std::chrono::nanoseconds() const
@@ -351,21 +374,21 @@ struct local_datetime
explicit local_datetime(const std::chrono::system_clock::time_point& tp)
{
const auto t = std::chrono::system_clock::to_time_t(tp);
std::tm time = detail::localtime_s(&t);
std::tm ltime = detail::localtime_s(&t);
this->date = local_date(time);
this->time = local_time(time);
this->date = local_date(ltime);
this->time = local_time(ltime);
// std::tm lacks subsecond information, so diff between tp and tm
// can be used to get millisecond & microsecond information.
const auto t_diff = tp -
std::chrono::system_clock::from_time_t(std::mktime(&time));
this->time.millisecond = std::chrono::duration_cast<
std::chrono::milliseconds>(t_diff).count();
this->time.microsecond = std::chrono::duration_cast<
std::chrono::microseconds>(t_diff).count();
this->time.nanosecond = std::chrono::duration_cast<
std::chrono::nanoseconds >(t_diff).count();
std::chrono::system_clock::from_time_t(std::mktime(&ltime));
this->time.millisecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());
this->time.microsecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::microseconds>(t_diff).count());
this->time.nanosecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::nanoseconds >(t_diff).count());
}
explicit local_datetime(const std::time_t t)
@@ -376,10 +399,31 @@ struct local_datetime
{
using internal_duration =
typename std::chrono::system_clock::time_point::duration;
// Normally DST begins at A.M. 3 or 4. If we re-use conversion operator
// of local_date and local_time independently, the conversion fails if
// it is the day when DST begins or ends. Since local_date considers the
// time is 00:00 A.M. and local_time does not consider DST because it
// does not have any date information. We need to consider both date and
// time information at the same time to convert it correctly.
std::tm t;
t.tm_sec = static_cast<int>(this->time.second);
t.tm_min = static_cast<int>(this->time.minute);
t.tm_hour = static_cast<int>(this->time.hour);
t.tm_mday = static_cast<int>(this->date.day);
t.tm_mon = static_cast<int>(this->date.month);
t.tm_year = static_cast<int>(this->date.year) - 1900;
t.tm_wday = 0; // the value will be ignored
t.tm_yday = 0; // the value will be ignored
t.tm_isdst = -1;
// std::mktime returns date as local time zone. no conversion needed
auto dt = std::chrono::system_clock::time_point(this->date);
auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t));
dt += std::chrono::duration_cast<internal_duration>(
std::chrono::nanoseconds(this->time));
std::chrono::milliseconds(this->time.millisecond) +
std::chrono::microseconds(this->time.microsecond) +
std::chrono::nanoseconds (this->time.nanosecond));
return dt;
}
@@ -445,40 +489,71 @@ struct offset_datetime
: date(dt.date), time(dt.time), offset(o)
{}
explicit offset_datetime(const local_datetime& ld)
: date(ld.date), time(ld.time), offset(get_local_offset())
: date(ld.date), time(ld.time), offset(get_local_offset(nullptr))
// use the current local timezone offset
{}
explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
: offset_datetime(local_datetime(tp))
{}
: offset(0, 0) // use gmtime
{
const auto timet = std::chrono::system_clock::to_time_t(tp);
const auto tm = detail::gmtime_s(&timet);
this->date = local_date(tm);
this->time = local_time(tm);
}
explicit offset_datetime(const std::time_t& t)
: offset_datetime(local_datetime(t))
{}
: offset(0, 0) // use gmtime
{
const auto tm = detail::gmtime_s(&t);
this->date = local_date(tm);
this->time = local_time(tm);
}
explicit offset_datetime(const std::tm& t)
: offset_datetime(local_datetime(t))
{}
: offset(0, 0) // assume gmtime
{
this->date = local_date(t);
this->time = local_time(t);
}
operator std::chrono::system_clock::time_point() const
{
// get date-time
using internal_duration =
typename std::chrono::system_clock::time_point::duration;
std::chrono::system_clock::time_point tp =
std::chrono::system_clock::time_point(this->date) +
std::chrono::duration_cast<internal_duration>(
std::chrono::nanoseconds(this->time));
// get date-time in UTC. let's say we are in +09:00 (JPN).
// writing 12:00:00 in +09:00 means 03:00:00Z. to represent
// 12:00:00Z, first we need to add +09:00.
const auto ofs = get_local_offset();
// first, convert it to local date-time information in the same way as
// local_datetime does. later we will use time_t to adjust time offset.
std::tm t;
t.tm_sec = static_cast<int>(this->time.second);
t.tm_min = static_cast<int>(this->time.minute);
t.tm_hour = static_cast<int>(this->time.hour);
t.tm_mday = static_cast<int>(this->date.day);
t.tm_mon = static_cast<int>(this->date.month);
t.tm_year = static_cast<int>(this->date.year) - 1900;
t.tm_wday = 0; // the value will be ignored
t.tm_yday = 0; // the value will be ignored
t.tm_isdst = -1;
const std::time_t tp_loc = std::mktime(std::addressof(t));
auto tp = std::chrono::system_clock::from_time_t(tp_loc);
tp += std::chrono::duration_cast<internal_duration>(
std::chrono::milliseconds(this->time.millisecond) +
std::chrono::microseconds(this->time.microsecond) +
std::chrono::nanoseconds (this->time.nanosecond));
// Since mktime uses local time zone, it should be corrected.
// `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if
// we are in `+09:00` timezone. To represent `12:00:00Z` there, we need
// to add `+09:00` to `03:00:00Z`.
// Here, it uses the time_t converted from date-time info to handle
// daylight saving time.
const auto ofs = get_local_offset(std::addressof(tp_loc));
tp += std::chrono::hours (ofs.hour);
tp += std::chrono::minutes(ofs.minute);
// here, tp represents 12:00:00 in UTC but we have offset information.
// we need to subtract it. For example, let's say the input is
// 12:00:00-08:00. now we have tp = 12:00:00Z as a result of the above
// conversion. But the actual time we need to return is 20:00:00Z
// because of -08:00.
// We got `12:00:00Z` by correcting local timezone applied by mktime.
// Then we will apply the offset. Let's say `12:00:00-08:00` is given.
// And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`.
// So we need to subtract the offset.
tp -= std::chrono::minutes(this->offset);
return tp;
}
@@ -498,11 +573,10 @@ struct offset_datetime
private:
static time_offset get_local_offset()
static time_offset get_local_offset(const std::time_t* tp)
{
// get current timezone
const auto tmp1 = std::time(nullptr);
const auto t = detail::localtime_s(&tmp1);
// get local timezone with the same date-time information as mktime
const auto t = detail::localtime_s(tp);
std::array<char, 6> buf;
const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0

View File

@@ -5,21 +5,29 @@
#include <stdexcept>
#include <string>
#include "source_location.hpp"
namespace toml
{
struct exception : public std::exception
{
public:
explicit exception(const source_location& loc): loc_(loc) {}
virtual ~exception() noexcept override = default;
virtual const char* what() const noexcept override {return "";}
virtual source_location const& location() const noexcept {return loc_;}
protected:
source_location loc_;
};
struct syntax_error : public toml::exception
{
public:
explicit syntax_error(const std::string& what_arg) : what_(what_arg){}
explicit syntax_error(const char* what_arg) : what_(what_arg){}
explicit syntax_error(const std::string& what_arg, const source_location& loc)
: exception(loc), what_(what_arg)
{}
virtual ~syntax_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();}
@@ -30,8 +38,9 @@ struct syntax_error : public toml::exception
struct type_error : public toml::exception
{
public:
explicit type_error(const std::string& what_arg) : what_(what_arg){}
explicit type_error(const char* what_arg) : what_(what_arg){}
explicit type_error(const std::string& what_arg, const source_location& loc)
: exception(loc), what_(what_arg)
{}
virtual ~type_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();}
@@ -42,10 +51,12 @@ struct type_error : public toml::exception
struct internal_error : public toml::exception
{
public:
explicit internal_error(const std::string& what_arg) : what_(what_arg){}
explicit internal_error(const char* what_arg) : what_(what_arg){}
explicit internal_error(const std::string& what_arg, const source_location& loc)
: exception(loc), what_(what_arg)
{}
virtual ~internal_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();}
protected:
std::string what_;
};

View File

@@ -2,7 +2,6 @@
// Distributed under the MIT License.
#ifndef TOML11_FROM_HPP
#define TOML11_FROM_HPP
#include "traits.hpp"
namespace toml
{

View File

@@ -1,71 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_FROM_TOML_HPP
#define TOML11_FROM_TOML_HPP
#include "get.hpp"
namespace toml
{
template<typename T>
void from_toml(T& x, const toml::value& v)
{
x = toml::get<typename std::remove_reference<T>::type>(v);
return;
}
namespace detail
{
template<typename T>
constexpr toml::value_t determine_castable_type()
{
return check_type<T>() != toml::value_t::Unknown ? check_type<T>() :
toml::detail::is_map<T>::value ? toml::value_t::Table :
toml::detail::is_container<T>::value ? toml::value_t::Array :
toml::value_t::Unknown;
}
template<std::size_t N, typename ... Ts>
struct from_toml_tie_impl
{
constexpr static std::size_t index = sizeof...(Ts) - N;
constexpr static toml::value_t type_index =
determine_castable_type<
typename std::tuple_element<index, std::tuple<Ts...>>::type>();
static void invoke(std::tuple<Ts& ...> tie, const toml::value& v)
{
// static_cast is needed because with intel c++ compiler, operator==
// is only defined when the two types are strictly equal, and type_index
// is const toml::value_t, while v.type() is toml::value_t.
if(static_cast<toml::value_t>(type_index) == v.type())
{
from_toml(std::get<index>(tie), v);
return;
}
return from_toml_tie_impl<N-1, Ts...>::invoke(tie, v);
}
};
template<typename ... Ts>
struct from_toml_tie_impl<0, Ts...>
{
static void invoke(std::tuple<Ts& ...> tie, const toml::value& v)
{
return;
}
};
} // detail
template<typename ... Ts>
void from_toml(std::tuple<Ts& ...> tie, const toml::value& v)
{
detail::from_toml_tie_impl<sizeof...(Ts), Ts...>::invoke(tie, v);
return;
}
} // toml
#endif // TOML11_FROM_TOML

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,6 @@
// Distributed under the MIT License.
#ifndef TOML11_INTO_HPP
#define TOML11_INTO_HPP
#include "traits.hpp"
namespace toml
{

View File

@@ -2,12 +2,13 @@
// Distributed under the MIT License.
#ifndef TOML11_LEXER_HPP
#define TOML11_LEXER_HPP
#include "combinator.hpp"
#include <stdexcept>
#include <istream>
#include <sstream>
#include <stdexcept>
#include <fstream>
#include "combinator.hpp"
namespace toml
{
namespace detail
@@ -63,12 +64,15 @@ using lex_integer = either<lex_bin_int, lex_oct_int, lex_hex_int, lex_dec_int>;
using lex_inf = sequence<character<'i'>, character<'n'>, character<'f'>>;
using lex_nan = sequence<character<'n'>, character<'a'>, character<'n'>>;
using lex_special_float = sequence<maybe<lex_sign>, either<lex_inf, lex_nan>>;
using lex_exponent_part = sequence<either<character<'e'>, character<'E'>>, lex_dec_int>;
using lex_zero_prefixable_int = sequence<lex_digit, repeat<either<lex_digit,
sequence<lex_underscore, lex_digit>>, unlimited>>;
sequence<lex_underscore, lex_digit>>, unlimited>>;
using lex_fractional_part = sequence<character<'.'>, lex_zero_prefixable_int>;
using lex_exponent_part = sequence<either<character<'e'>, character<'E'>>,
maybe<lex_sign>, lex_zero_prefixable_int>;
using lex_float = either<lex_special_float,
sequence<lex_dec_int, either<lex_exponent_part,
sequence<lex_fractional_part, maybe<lex_exponent_part>>>>>;
@@ -115,9 +119,11 @@ using lex_local_time = lex_partial_time;
// ===========================================================================
using lex_quotation_mark = character<'"'>;
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x1F>,
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab) is allowed
in_range<0x0A, 0x1F>,
character<0x22>, character<0x5C>,
character<0x7F>>>;
using lex_escape = character<'\\'>;
using lex_escape_unicode_short = sequence<character<'u'>,
repeat<lex_hex_dig, exactly<4>>>;
@@ -136,10 +142,46 @@ using lex_basic_string = sequence<lex_quotation_mark,
repeat<lex_basic_char, unlimited>,
lex_quotation_mark>;
// After toml post-v0.5.0, it is explicitly clarified how quotes in ml-strings
// are allowed to be used.
// After this, the following strings are *explicitly* allowed.
// - One or two `"`s in a multi-line basic string is allowed wherever it is.
// - Three consecutive `"`s in a multi-line basic string is considered as a delimiter.
// - One or two `"`s can appear just before or after the delimiter.
// ```toml
// str4 = """Here are two quotation marks: "". Simple enough."""
// str5 = """Here are three quotation marks: ""\"."""
// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
// str7 = """"This," she said, "is just a pointless statement.""""
// ```
// In the current implementation (v3.3.0), it is difficult to parse `str7` in
// the above example. It is difficult to recognize `"` at the end of string body
// collectly. It will be misunderstood as a `"""` delimiter and an additional,
// invalid `"`. Like this:
// ```console
// what(): [error] toml::parse_table: invalid line format
// --> hoge.toml
// |
// 13 | str7 = """"This," she said, "is just a pointless statement.""""
// | ^- expected newline, but got '"'.
// ```
// As a quick workaround for this problem, `lex_ml_basic_string_delim` was
// split into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`.
// `lex_ml_basic_string_open` allows only `"""`. `_close` allows 3-5 `"`s.
// In parse_ml_basic_string() function, the trailing `"`s will be attached to
// the string body.
//
using lex_ml_basic_string_delim = repeat<lex_quotation_mark, exactly<3>>;
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x1F>,
character<0x5C>,
character<0x7F>,
using lex_ml_basic_string_open = lex_ml_basic_string_delim;
using lex_ml_basic_string_close = sequence<
repeat<lex_quotation_mark, exactly<3>>,
maybe<lex_quotation_mark>, maybe<lex_quotation_mark>
>;
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 is tab
in_range<0x0A, 0x1F>,
character<0x5C>, // backslash
character<0x7F>, // DEL
lex_ml_basic_string_delim>>;
using lex_ml_basic_escaped_newline = sequence<
@@ -150,39 +192,39 @@ using lex_ml_basic_char = either<lex_ml_basic_unescaped, lex_escaped>;
using lex_ml_basic_body = repeat<either<lex_ml_basic_char, lex_newline,
lex_ml_basic_escaped_newline>,
unlimited>;
using lex_ml_basic_string = sequence<lex_ml_basic_string_delim,
using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
lex_ml_basic_body,
lex_ml_basic_string_delim>;
lex_ml_basic_string_close>;
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
in_range<0x10, 0x19>, character<0x27>>>;
using lex_literal_char = exclude<either<in_range<0x00, 0x08>, in_range<0x0A, 0x1F>,
character<0x7F>, character<0x27>>>;
using lex_apostrophe = character<'\''>;
using lex_literal_string = sequence<lex_apostrophe,
repeat<lex_literal_char, unlimited>,
lex_apostrophe>;
// the same reason as above.
using lex_ml_literal_string_delim = repeat<lex_apostrophe, exactly<3>>;
using lex_ml_literal_string_open = lex_ml_literal_string_delim;
using lex_ml_literal_string_close = sequence<
repeat<lex_apostrophe, exactly<3>>,
maybe<lex_apostrophe>, maybe<lex_apostrophe>
>;
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
in_range<0x10, 0x1F>,
in_range<0x0A, 0x1F>,
character<0x7F>,
lex_ml_literal_string_delim>>;
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
unlimited>;
using lex_ml_literal_string = sequence<lex_ml_literal_string_delim,
using lex_ml_literal_string = sequence<lex_ml_literal_string_open,
lex_ml_literal_body,
lex_ml_literal_string_delim>;
lex_ml_literal_string_close>;
using lex_string = either<lex_ml_basic_string, lex_basic_string,
lex_ml_literal_string, lex_literal_string>;
// ===========================================================================
using lex_comment_start_symbol = character<'#'>;
using lex_non_eol = either<character<'\t'>, exclude<in_range<0x00, 0x19>>>;
using lex_comment = sequence<lex_comment_start_symbol,
repeat<lex_non_eol, unlimited>>;
using lex_dot_sep = sequence<maybe<lex_ws>, character<'.'>, maybe<lex_ws>>;
using lex_unquoted_key = repeat<either<lex_alpha, lex_digit,
@@ -217,6 +259,35 @@ using lex_array_table = sequence<lex_array_table_open,
maybe<lex_ws>,
lex_array_table_close>;
using lex_utf8_1byte = in_range<0x00, 0x7F>;
using lex_utf8_2byte = sequence<
in_range<static_cast<char>(0xC2), static_cast<char>(0xDF)>,
in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>
>;
using lex_utf8_3byte = sequence<either<
sequence<character<static_cast<char>(0xE0)>, in_range<static_cast<char>(0xA0), static_cast<char>(0xBF)>>,
sequence<in_range <static_cast<char>(0xE1), static_cast<char>(0xEC)>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>,
sequence<character<static_cast<char>(0xED)>, in_range<static_cast<char>(0x80), static_cast<char>(0x9F)>>,
sequence<in_range <static_cast<char>(0xEE), static_cast<char>(0xEF)>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>
>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>;
using lex_utf8_4byte = sequence<either<
sequence<character<static_cast<char>(0xF0)>, in_range<static_cast<char>(0x90), static_cast<char>(0xBF)>>,
sequence<in_range <static_cast<char>(0xF1), static_cast<char>(0xF3)>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>,
sequence<character<static_cast<char>(0xF4)>, in_range<static_cast<char>(0x80), static_cast<char>(0x8F)>>
>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>,
in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>;
using lex_utf8_code = either<
lex_utf8_1byte,
lex_utf8_2byte,
lex_utf8_3byte,
lex_utf8_4byte
>;
using lex_comment_start_symbol = character<'#'>;
using lex_non_eol_ascii = either<character<0x09>, in_range<0x20, 0x7E>>;
using lex_comment = sequence<lex_comment_start_symbol, repeat<either<
lex_non_eol_ascii, lex_utf8_2byte, lex_utf8_3byte, lex_utf8_4byte>, unlimited>>;
} // detail
} // toml
#endif // TOML_LEXER_HPP

View File

@@ -11,12 +11,12 @@ inline namespace literals
inline namespace toml_literals
{
inline ::toml::value operator""_toml(const char* str, std::size_t len)
// implementation
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
literal_internal_impl(::toml::detail::location loc)
{
::toml::detail::location<std::vector<char>>
loc(/* filename = */ std::string("TOML literal encoded in a C++ code"),
/* contents = */ std::vector<char>(str, str + len));
using value_type = ::toml::basic_value<
TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
// if there are some comments or empty lines, skip them.
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
::toml::detail::maybe<::toml::detail::lex_ws>,
@@ -30,25 +30,83 @@ inline ::toml::value operator""_toml(const char* str, std::size_t len)
::toml::detail::lex_ws, ::toml::detail::at_least<1>>;
skip_ws::invoke(loc);
// literal may be a bare value. try them first.
if(auto data = ::toml::detail::parse_value(loc))
// to distinguish arrays and tables, first check it is a table or not.
//
// "[1,2,3]"_toml; // this is an array
// "[table]"_toml; // a table that has an empty table named "table" inside.
// "[[1,2,3]]"_toml; // this is an array of arrays
// "[[table]]"_toml; // this is a table that has an array of tables inside.
//
// "[[1]]"_toml; // this can be both... (currently it becomes a table)
// "1 = [{}]"_toml; // this is a table that has an array of table named 1.
// "[[1,]]"_toml; // this is an array of arrays.
// "[[1],]"_toml; // this also.
const auto the_front = loc.iter();
const bool is_table_key = ::toml::detail::lex_std_table::invoke(loc);
loc.reset(the_front);
const bool is_aots_key = ::toml::detail::lex_array_table::invoke(loc);
loc.reset(the_front);
// If it is neither a table-key or a array-of-table-key, it may be a value.
if(!is_table_key && !is_aots_key)
{
if(auto data = ::toml::detail::parse_value<value_type>(loc))
{
return data.unwrap();
}
}
// Note that still it can be a table, because the literal might be something
// like the following.
// ```cpp
// R"( // c++11 raw string literals
// key = "value"
// int = 42
// )"_toml;
// ```
// It is a valid toml file.
// It should be parsed as if we parse a file with this content.
if(auto data = ::toml::detail::parse_toml_file<value_type>(loc))
{
return data.unwrap();
}
// literal is a TOML file (i.e. multiline table).
if(auto data = ::toml::detail::parse_toml_file(loc))
{
loc.iter() = loc.begin(); // rollback to the top of the literal
return ::toml::value(std::move(data.unwrap()),
::toml::detail::region<std::vector<char>>(std::move(loc)));
}
else // none of them.
{
throw ::toml::syntax_error(data.unwrap_err());
throw ::toml::syntax_error(data.unwrap_err(), source_location(loc));
}
}
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
operator"" _toml(const char* str, std::size_t len)
{
::toml::detail::location loc(
std::string("TOML literal encoded in a C++ code"),
std::vector<char>(str, str + len));
// literal length does not include the null character at the end.
return literal_internal_impl(std::move(loc));
}
// value of __cplusplus in C++2a/20 mode is not fixed yet along compilers.
// So here we use the feature test macro for `char8_t` itself.
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
// value of u8"" literal has been changed from char to char8_t and char8_t is
// NOT compatible to char
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
operator"" _toml(const char8_t* str, std::size_t len)
{
::toml::detail::location loc(
std::string("TOML literal encoded in a C++ code"),
std::vector<char>(reinterpret_cast<const char*>(str),
reinterpret_cast<const char*>(str) + len));
return literal_internal_impl(std::move(loc));
}
#endif
} // toml_literals
} // literals
} // toml

121
toml/macros.hpp Normal file
View File

@@ -0,0 +1,121 @@
#ifndef TOML11_MACROS_HPP
#define TOML11_MACROS_HPP
#define TOML11_STRINGIZE_AUX(x) #x
#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x)
#define TOML11_CONCATENATE_AUX(x, y) x##y
#define TOML11_CONCATENATE(x, y) TOML11_CONCATENATE_AUX(x, y)
// ============================================================================
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
// ----------------------------------------------------------------------------
// TOML11_ARGS_SIZE
#define TOML11_INDEX_RSEQ() \
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
#define TOML11_ARGS_SIZE_IMPL(\
ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, ARG10, \
ARG11, ARG12, ARG13, ARG14, ARG15, ARG16, ARG17, ARG18, ARG19, ARG20, \
ARG21, ARG22, ARG23, ARG24, ARG25, ARG26, ARG27, ARG28, ARG29, ARG30, \
ARG31, ARG32, N, ...) N
#define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__)
#define TOML11_ARGS_SIZE(...) TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ())
// ----------------------------------------------------------------------------
// TOML11_FOR_EACH_VA_ARGS
#define TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, ARG1 ) FUNCTOR(ARG1)
#define TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\
TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__)
// ----------------------------------------------------------------------------
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
// use it in the following way.
// ```cpp
// namespace foo
// {
// struct Foo
// {
// std::string s;
// double d;
// int i;
// };
// } // foo
//
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)
// ```
// And then you can use `toml::find<foo::Foo>(file, "foo");`
//
#define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\
obj.VAR_NAME = toml::find<decltype(obj.VAR_NAME)>(v, TOML11_STRINGIZE(VAR_NAME));
#define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME)\
v[TOML11_STRINGIZE(VAR_NAME)] = obj.VAR_NAME;
#define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\
namespace toml { \
template<> \
struct from<NAME> \
{ \
template<typename C, template<typename ...> class T, \
template<typename ...> class A> \
static NAME from_toml(const basic_value<C, T, A>& v) \
{ \
NAME obj; \
TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \
return obj; \
} \
}; \
template<> \
struct into<NAME> \
{ \
static value into_toml(const NAME& obj) \
{ \
::toml::value v = ::toml::table{}; \
TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \
return v; \
} \
}; \
} /* toml */
#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
#endif// TOML11_MACROS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -2,13 +2,14 @@
// Distributed under the MIT License.
#ifndef TOML11_REGION_HPP
#define TOML11_REGION_HPP
#include "exception.hpp"
#include <memory>
#include <vector>
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <iomanip>
#include <cassert>
#include "color.hpp"
namespace toml
{
@@ -40,6 +41,7 @@ struct region_base
region_base& operator=(region_base&& ) = default;
virtual bool is_ok() const noexcept {return false;}
virtual char front() const noexcept {return '\0';}
virtual std::string str() const {return std::string("unknown region");}
virtual std::string name() const {return std::string("unknown file");}
@@ -52,6 +54,12 @@ struct region_base
virtual std::size_t before() const noexcept {return 0;}
// number of characters in the line after the region
virtual std::size_t after() const noexcept {return 0;}
virtual std::vector<std::string> comments() const {return {};}
// ```toml
// # comment_before
// key = "value" # comment_inline
// ```
};
// location represents a position in a container, which contains a file content.
@@ -59,17 +67,21 @@ struct region_base
//
// it contains pointer to the file content and iterator that points the current
// location.
template<typename Container>
struct location final : public region_base
{
static_assert(std::is_same<char, typename Container::value_type>::value,"");
using const_iterator = typename Container::const_iterator;
using source_ptr = std::shared_ptr<const Container>;
using const_iterator = typename std::vector<char>::const_iterator;
using difference_type = typename const_iterator::difference_type;
using source_ptr = std::shared_ptr<const std::vector<char>>;
location(std::string name, Container cont)
: source_(std::make_shared<Container>(std::move(cont))),
source_name_(std::move(name)), iter_(source_->cbegin())
location(std::string source_name, std::vector<char> cont)
: source_(std::make_shared<std::vector<char>>(std::move(cont))),
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
{}
location(std::string source_name, const std::string& cont)
: source_(std::make_shared<std::vector<char>>(cont.begin(), cont.end())),
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
{}
location(const location&) = default;
location(location&&) = default;
location& operator=(const location&) = default;
@@ -77,19 +89,60 @@ struct location final : public region_base
~location() = default;
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
char front() const noexcept override {return *iter_;}
const_iterator& iter() noexcept {return iter_;}
const_iterator iter() const noexcept {return iter_;}
// this const prohibits codes like `++(loc.iter())`.
const const_iterator iter() const noexcept {return iter_;}
const_iterator begin() const noexcept {return source_->cbegin();}
const_iterator end() const noexcept {return source_->cend();}
const_iterator begin() const noexcept {return source_->cbegin();}
const_iterator end() const noexcept {return source_->cend();}
// XXX `location::line_num()` used to be implemented using `std::count` to
// count a number of '\n'. But with a long toml file (typically, 10k lines),
// it becomes intolerably slow because each time it generates error messages,
// it counts '\n' from thousands of characters. To workaround it, I decided
// to introduce `location::line_number_` member variable and synchronize it
// to the location changes the point to look. So an overload of `iter()`
// which returns mutable reference is removed and `advance()`, `retrace()`
// and `reset()` is added.
void advance(difference_type n = 1) noexcept
{
this->line_number_ += static_cast<std::size_t>(
std::count(this->iter_, std::next(this->iter_, n), '\n'));
this->iter_ += n;
return;
}
void retrace(difference_type n = 1) noexcept
{
this->line_number_ -= static_cast<std::size_t>(
std::count(std::prev(this->iter_, n), this->iter_, '\n'));
this->iter_ -= n;
return;
}
void reset(const_iterator rollback) noexcept
{
// since c++11, std::distance works in both ways for random-access
// iterators and returns a negative value if `first > last`.
if(0 <= std::distance(rollback, this->iter_)) // rollback < iter
{
this->line_number_ -= static_cast<std::size_t>(
std::count(rollback, this->iter_, '\n'));
}
else // iter < rollback [[unlikely]]
{
this->line_number_ += static_cast<std::size_t>(
std::count(this->iter_, rollback, '\n'));
}
this->iter_ = rollback;
return;
}
std::string str() const override {return make_string(1, *this->iter());}
std::string name() const override {return source_name_;}
std::string line_num() const override
{
return std::to_string(1+std::count(this->begin(), this->iter(), '\n'));
return std::to_string(this->line_number_);
}
std::string line() const override
@@ -115,11 +168,15 @@ struct location final : public region_base
}
std::size_t before() const noexcept override
{
return std::distance(this->line_begin(), this->iter());
const auto sz = std::distance(this->line_begin(), this->iter());
assert(sz >= 0);
return static_cast<std::size_t>(sz);
}
std::size_t after() const noexcept override
{
return std::distance(this->iter(), this->line_end());
const auto sz = std::distance(this->iter(), this->line_end());
assert(sz >= 0);
return static_cast<std::size_t>(sz);
}
source_ptr const& source() const& noexcept {return source_;}
@@ -128,6 +185,7 @@ struct location final : public region_base
private:
source_ptr source_;
std::size_t line_number_;
std::string source_name_;
const_iterator iter_;
};
@@ -136,29 +194,27 @@ struct location final : public region_base
//
// it contains pointer to the file content and iterator that points the first
// and last location.
template<typename Container>
struct region final : public region_base
{
static_assert(std::is_same<char, typename Container::value_type>::value,"");
using const_iterator = typename Container::const_iterator;
using source_ptr = std::shared_ptr<const Container>;
using const_iterator = typename std::vector<char>::const_iterator;
using source_ptr = std::shared_ptr<const std::vector<char>>;
// delete default constructor. source_ never be null.
region() = delete;
region(const location<Container>& loc)
explicit region(const location& loc)
: source_(loc.source()), source_name_(loc.name()),
first_(loc.iter()), last_(loc.iter())
{}
region(location<Container>&& loc)
explicit region(location&& loc)
: source_(loc.source()), source_name_(loc.name()),
first_(loc.iter()), last_(loc.iter())
{}
region(const location<Container>& loc, const_iterator f, const_iterator l)
region(const location& loc, const_iterator f, const_iterator l)
: source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
{}
region(location<Container>&& loc, const_iterator f, const_iterator l)
region(location&& loc, const_iterator f, const_iterator l)
: source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
{}
@@ -170,16 +226,16 @@ struct region final : public region_base
region& operator+=(const region& other)
{
if(this->begin() != other.begin() || this->end() != other.end() ||
this->last_ != other.first_)
{
throw internal_error("invalid region concatenation");
}
// different regions cannot be concatenated
assert(this->begin() == other.begin() && this->end() == other.end() &&
this->last_ == other.first_);
this->last_ = other.last_;
return *this;
}
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
char front() const noexcept override {return *first_;}
std::string str() const override {return make_string(first_, last_);}
std::string line() const override
@@ -198,15 +254,21 @@ struct region final : public region_base
std::size_t size() const noexcept override
{
return std::distance(first_, last_);
const auto sz = std::distance(first_, last_);
assert(sz >= 0);
return static_cast<std::size_t>(sz);
}
std::size_t before() const noexcept override
{
return std::distance(this->line_begin(), this->first());
const auto sz = std::distance(this->line_begin(), this->first());
assert(sz >= 0);
return static_cast<std::size_t>(sz);
}
std::size_t after() const noexcept override
{
return std::distance(this->last(), this->line_end());
const auto sz = std::distance(this->last(), this->line_end());
assert(sz >= 0);
return static_cast<std::size_t>(sz);
}
bool contain_newline() const noexcept
@@ -235,6 +297,114 @@ struct region final : public region_base
std::string name() const override {return source_name_;}
std::vector<std::string> comments() const override
{
// assuming the current region (`*this`) points a value.
// ```toml
// a = "value"
// ^^^^^^^- this region
// ```
using rev_iter = std::reverse_iterator<const_iterator>;
std::vector<std::string> com{};
{
// find comments just before the current region.
// ```toml
// # this should be collected.
// # this also.
// a = value # not this.
// ```
// # 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 == '{';}))
{
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.
}
// 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 s = make_string(std::next(comment_found), iter);
if(!s.empty() && s.back() == '\r') {s.pop_back();}
com.push_back(std::move(s));
}
else
{
break;
}
iter = line_start;
}
}
}
if(com.size() > 1)
{
std::reverse(com.begin(), com.end());
}
{
// find comments just after the current region.
// ```toml
// # not this.
// a = value # this one.
// a = [ # not this (technically difficult)
//
// ] # and this.
// ```
// The reason why it's difficult is that it requires parsing in the
// following case.
// ```toml
// a = [ 10 # this comment is for `10`. not for `a` but `a[0]`.
// # ...
// ] # this is apparently a comment for a.
//
// b = [
// 3.14 ] # there is no way to add a comment to `3.14` currently.
//
// c = [
// 3.14 # do this if you need a comment here.
// ]
// ```
const auto comment_found =
std::find(this->last(), this->line_end(), '#');
if(comment_found != this->line_end()) // '#' found
{
// table = {key = "value"} # what is this for?
// the above comment is not for "value", but {key="value"}.
if(comment_found == std::find_if(this->last(), comment_found,
[](const char c) noexcept -> bool {
return !(c == ' ' || c == '\t' || c == ',');
}))
{
// unwrap the first '#' by std::next.
auto s = make_string(std::next(comment_found), this->line_end());
if(!s.empty() && s.back() == '\r') {s.pop_back();}
com.push_back(std::move(s));
}
}
}
return com;
}
private:
source_ptr source_;
@@ -242,84 +412,6 @@ struct region final : public region_base
const_iterator first_, last_;
};
// to show a better error message.
inline std::string format_underline(const std::string& message,
std::vector<std::pair<region_base const*, std::string>> reg_com,
std::vector<std::string> helps = {})
{
assert(!reg_com.empty());
#ifdef _WIN32
const auto newline = "\r\n";
#else
const char newline = '\n';
#endif
const auto line_num_width = std::max_element(reg_com.begin(), reg_com.end(),
[](std::pair<region_base const*, std::string> const& lhs,
std::pair<region_base const*, std::string> const& rhs)
{
return lhs.first->line_num().size() < rhs.first->line_num().size();
}
)->first->line_num().size();
std::ostringstream retval;
retval << message << newline;
for(std::size_t i=0; i<reg_com.size(); ++i)
{
if(i!=0 && reg_com.at(i-1).first->name() == reg_com.at(i).first->name())
{
retval << newline << " ..." << newline;
}
else
{
if(i != 0) {retval << newline;}
retval << " --> " << reg_com.at(i).first->name() << newline;
}
const region_base* const reg = reg_com.at(i).first;
const std::string& comment = reg_com.at(i).second;
retval << ' ' << std::setw(line_num_width) << reg->line_num();
retval << " | " << reg->line() << newline;
retval << make_string(line_num_width + 1, ' ');
retval << " | " << make_string(reg->before(), ' ');
if(reg->size() == 1)
{
// invalid
// ^------
retval << '^';
retval << make_string(reg->after(), '-');
}
else
{
// invalid
// ~~~~~~~
retval << make_string(reg->size(), '~');
}
retval << ' ';
retval << comment;
}
if(helps.size() != 0)
{
retval << newline;
retval << make_string(line_num_width + 1, ' ');
retval << " | ";
for(const auto help : helps)
{
retval << newline;
retval << "Hint: ";
retval << help;
}
}
return retval.str();
}
} // detail
} // toml
#endif// TOML11_REGION_H

View File

@@ -113,21 +113,25 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(s);
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
result(const failure_type& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
result(success_type&& s): is_ok_(true)
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
result(failure_type&& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
template<typename U>
@@ -135,24 +139,28 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
template<typename U>
result(const failure<U>& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
template<typename U>
result(success<U>&& s): is_ok_(true)
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
template<typename U>
result(failure<U>&& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
result& operator=(const success_type& s)
@@ -161,6 +169,7 @@ struct result
this->is_ok_ = true;
auto tmp = ::new(std::addressof(this->succ)) success_type(s);
assert(tmp == std::addressof(this->succ));
(void)tmp;
return *this;
}
result& operator=(const failure_type& f)
@@ -169,6 +178,7 @@ struct result
this->is_ok_ = false;
auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
assert(tmp == std::addressof(this->fail));
(void)tmp;
return *this;
}
result& operator=(success_type&& s)
@@ -177,6 +187,7 @@ struct result
this->is_ok_ = true;
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
assert(tmp == std::addressof(this->succ));
(void)tmp;
return *this;
}
result& operator=(failure_type&& f)
@@ -185,6 +196,7 @@ struct result
this->is_ok_ = false;
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
assert(tmp == std::addressof(this->fail));
(void)tmp;
return *this;
}
@@ -195,6 +207,7 @@ struct result
this->is_ok_ = true;
auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
assert(tmp == std::addressof(this->succ));
(void)tmp;
return *this;
}
template<typename U>
@@ -204,6 +217,7 @@ struct result
this->is_ok_ = false;
auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
assert(tmp == std::addressof(this->fail));
(void)tmp;
return *this;
}
template<typename U>
@@ -213,6 +227,7 @@ struct result
this->is_ok_ = true;
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
assert(tmp == std::addressof(this->succ));
(void)tmp;
return *this;
}
template<typename U>
@@ -222,6 +237,7 @@ struct result
this->is_ok_ = false;
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
assert(tmp == std::addressof(this->fail));
(void)tmp;
return *this;
}
@@ -233,11 +249,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
}
result(result&& other): is_ok_(other.is_ok())
@@ -246,11 +264,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
}
@@ -261,11 +281,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
}
template<typename U, typename F>
@@ -275,11 +297,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
}
@@ -290,11 +314,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
is_ok_ = other.is_ok();
return *this;
@@ -306,11 +332,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
is_ok_ = other.is_ok();
return *this;
@@ -324,11 +352,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
is_ok_ = other.is_ok();
return *this;
@@ -341,11 +371,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
is_ok_ = other.is_ok();
return *this;
@@ -660,5 +692,26 @@ void swap(result<T, E>& lhs, result<T, E>& rhs)
// return lhs.is_ok() ? lhs : rhs;
// }
// ----------------------------------------------------------------------------
// re-use result<T, E> as a optional<T> with none_t
namespace detail
{
struct none_t {};
inline bool operator==(const none_t&, const none_t&) noexcept {return true;}
inline bool operator!=(const none_t&, const none_t&) noexcept {return false;}
inline bool operator< (const none_t&, const none_t&) noexcept {return false;}
inline bool operator<=(const none_t&, const none_t&) noexcept {return true;}
inline bool operator> (const none_t&, const none_t&) noexcept {return false;}
inline bool operator>=(const none_t&, const none_t&) noexcept {return true;}
template<typename charT, typename traitsT>
std::basic_ostream<charT, traitsT>&
operator<<(std::basic_ostream<charT, traitsT>& os, const none_t&)
{
os << "none";
return os;
}
inline failure<none_t> none() noexcept {return failure<none_t>{none_t{}};}
} // detail
} // toml11
#endif// TOML11_RESULT_H

File diff suppressed because it is too large Load Diff

233
toml/source_location.hpp Normal file
View File

@@ -0,0 +1,233 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_SOURCE_LOCATION_HPP
#define TOML11_SOURCE_LOCATION_HPP
#include <cstdint>
#include <sstream>
#include "region.hpp"
namespace toml
{
// A struct to contain location in a toml file.
// The interface imitates std::experimental::source_location,
// but not completely the same.
//
// It would be constructed by toml::value. It can be used to generate
// user-defined error messages.
//
// - std::uint_least32_t line() const noexcept
// - returns the line number where the region is on.
// - std::uint_least32_t column() const noexcept
// - returns the column number where the region starts.
// - std::uint_least32_t region() const noexcept
// - returns the size of the region.
//
// +-- line() +-- region of interest (region() == 9)
// v .---+---.
// 12 | value = "foo bar"
// ^
// +-- column()
//
// - std::string const& file_name() const noexcept;
// - name of the file.
// - std::string const& line_str() const noexcept;
// - the whole line that contains the region of interest.
//
struct source_location
{
public:
source_location()
: line_num_(1), column_num_(1), region_size_(1),
file_name_("unknown file"), line_str_("")
{}
explicit source_location(const detail::region_base* reg)
: line_num_(1), column_num_(1), region_size_(1),
file_name_("unknown file"), line_str_("")
{
if(reg)
{
if(reg->line_num() != detail::region_base().line_num())
{
line_num_ = static_cast<std::uint_least32_t>(
std::stoul(reg->line_num()));
}
column_num_ = static_cast<std::uint_least32_t>(reg->before() + 1);
region_size_ = static_cast<std::uint_least32_t>(reg->size());
file_name_ = reg->name();
line_str_ = reg->line();
}
}
explicit source_location(const detail::region& reg)
: line_num_(static_cast<std::uint_least32_t>(std::stoul(reg.line_num()))),
column_num_(static_cast<std::uint_least32_t>(reg.before() + 1)),
region_size_(static_cast<std::uint_least32_t>(reg.size())),
file_name_(reg.name()),
line_str_ (reg.line())
{}
explicit source_location(const detail::location& loc)
: line_num_(static_cast<std::uint_least32_t>(std::stoul(loc.line_num()))),
column_num_(static_cast<std::uint_least32_t>(loc.before() + 1)),
region_size_(static_cast<std::uint_least32_t>(loc.size())),
file_name_(loc.name()),
line_str_ (loc.line())
{}
~source_location() = default;
source_location(source_location const&) = default;
source_location(source_location &&) = default;
source_location& operator=(source_location const&) = default;
source_location& operator=(source_location &&) = default;
std::uint_least32_t line() const noexcept {return line_num_;}
std::uint_least32_t column() const noexcept {return column_num_;}
std::uint_least32_t region() const noexcept {return region_size_;}
std::string const& file_name() const noexcept {return file_name_;}
std::string const& line_str() const noexcept {return line_str_;}
private:
std::uint_least32_t line_num_;
std::uint_least32_t column_num_;
std::uint_least32_t region_size_;
std::string file_name_;
std::string line_str_;
};
namespace detail
{
// internal error message generation.
inline std::string format_underline(const std::string& message,
const std::vector<std::pair<source_location, std::string>>& loc_com,
const std::vector<std::string>& helps = {},
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
{
std::size_t line_num_width = 0;
for(const auto& lc : loc_com)
{
std::uint_least32_t line = lc.first.line();
std::size_t digit = 0;
while(line != 0)
{
line /= 10;
digit += 1;
}
line_num_width = (std::max)(line_num_width, digit);
}
// 1 is the minimum width
line_num_width = std::max<std::size_t>(line_num_width, 1);
std::ostringstream retval;
if(colorize)
{
retval << color::colorize; // turn on ANSI color
}
// XXX
// Here, before `colorize` support, it does not output `[error]` prefix
// automatically. So some user may output it manually and this change may
// duplicate the prefix. To avoid it, check the first 7 characters and
// if it is "[error]", it removes that part from the message shown.
if(message.size() > 7 && message.substr(0, 7) == "[error]")
{
retval << color::bold << color::red << "[error]" << color::reset
<< color::bold << message.substr(7) << color::reset << '\n';
}
else
{
retval << color::bold << color::red << "[error] " << color::reset
<< color::bold << message << color::reset << '\n';
}
const auto format_one_location = [line_num_width]
(std::ostringstream& oss,
const source_location& loc, const std::string& comment) -> void
{
oss << ' ' << color::bold << color::blue
<< std::setw(static_cast<int>(line_num_width))
<< std::right << loc.line() << " | " << color::reset
<< loc.line_str() << '\n';
oss << make_string(line_num_width + 1, ' ')
<< color::bold << color::blue << " | " << color::reset
<< make_string(loc.column()-1 /*1-origin*/, ' ');
if(loc.region() == 1)
{
// invalid
// ^------
oss << color::bold << color::red << "^---" << color::reset;
}
else
{
// invalid
// ~~~~~~~
const auto underline_len = (std::min)(
static_cast<std::size_t>(loc.region()), loc.line_str().size());
oss << color::bold << color::red
<< make_string(underline_len, '~') << color::reset;
}
oss << ' ';
oss << comment;
return;
};
assert(!loc_com.empty());
// --> example.toml
// |
retval << color::bold << color::blue << " --> " << color::reset
<< loc_com.front().first.file_name() << '\n';
retval << make_string(line_num_width + 1, ' ')
<< color::bold << color::blue << " |\n" << color::reset;
// 1 | key value
// | ^--- missing =
format_one_location(retval, loc_com.front().first, loc_com.front().second);
// process the rest of the locations
for(std::size_t i=1; i<loc_com.size(); ++i)
{
const auto& prev = loc_com.at(i-1);
const auto& curr = loc_com.at(i);
retval << '\n';
// if the filenames are the same, print "..."
if(prev.first.file_name() == curr.first.file_name())
{
retval << color::bold << color::blue << " ...\n" << color::reset;
}
else // if filename differs, print " --> filename.toml" again
{
retval << color::bold << color::blue << " --> " << color::reset
<< curr.first.file_name() << '\n';
retval << make_string(line_num_width + 1, ' ')
<< color::bold << color::blue << " |\n" << color::reset;
}
format_one_location(retval, curr.first, curr.second);
}
if(!helps.empty())
{
retval << '\n';
retval << make_string(line_num_width + 1, ' ');
retval << color::bold << color::blue << " |" << color::reset;
for(const auto& help : helps)
{
retval << color::bold << "\nHint: " << color::reset;
retval << help;
}
}
return retval.str();
}
} // detail
} // toml
#endif// TOML11_SOURCE_LOCATION_HPP

View File

@@ -16,10 +16,9 @@ struct storage
{
using value_type = T;
storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
explicit storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
explicit storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
~storage() = default;
storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
storage& operator=(const storage& rhs)
{

View File

@@ -2,9 +2,21 @@
// Distributed under the MIT License.
#ifndef TOML11_STRING_HPP
#define TOML11_STRING_HPP
#include <string>
#include "version.hpp"
#include <cstdint>
#include <algorithm>
#include <string>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __has_include(<string_view>)
#define TOML11_USING_STRING_VIEW 1
#include <string_view>
#endif
#endif
namespace toml
{
@@ -40,6 +52,24 @@ struct string
operator std::string const& () const& noexcept {return str;}
operator std::string&& () && noexcept {return std::move(str);}
string& operator+=(const char* rhs) {str += rhs; return *this;}
string& operator+=(const char rhs) {str += rhs; return *this;}
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
explicit string(std::string_view s): kind(string_t::basic), str(s){}
string(std::string_view s, string_t k): kind(k), str(s){}
string& operator=(std::string_view s)
{kind = string_t::basic; str = s; return *this;}
explicit operator std::string_view() const noexcept
{return std::string_view(str);}
string& operator+=(const std::string_view& rhs) {str += rhs; return *this;}
#endif
string_t kind;
std::string str;
};
@@ -123,9 +153,74 @@ operator>=(const char* lhs, const string& rhs) {return std::string(lhs) >= rhs.s
template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const string& str)
operator<<(std::basic_ostream<charT, traits>& os, const string& s)
{
os << str.str;
if(s.kind == string_t::basic)
{
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
{
// it contains newline. make it multiline string.
os << "\"\"\"\n";
for(auto i=s.str.cbegin(), e=s.str.cend(); i!=e; ++i)
{
switch(*i)
{
case '\\': {os << "\\\\"; break;}
case '\"': {os << "\\\""; break;}
case '\b': {os << "\\b"; break;}
case '\t': {os << "\\t"; break;}
case '\f': {os << "\\f"; break;}
case '\n': {os << '\n'; break;}
case '\r':
{
// since it is a multiline string,
// CRLF is not needed to be escaped.
if(std::next(i) != e && *std::next(i) == '\n')
{
os << "\r\n";
++i;
}
else
{
os << "\\r";
}
break;
}
default: {os << *i; break;}
}
}
os << "\\\n\"\"\"";
return os;
}
// no newline. make it inline.
os << "\"";
for(const auto c : s.str)
{
switch(c)
{
case '\\': {os << "\\\\"; break;}
case '\"': {os << "\\\""; break;}
case '\b': {os << "\\b"; break;}
case '\t': {os << "\\t"; break;}
case '\f': {os << "\\f"; break;}
case '\n': {os << "\\n"; break;}
case '\r': {os << "\\r"; break;}
default : {os << c; break;}
}
}
os << "\"";
return os;
}
// the string `s` is literal-string.
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
{
// contains newline or single quote. make it multiline.
os << "'''\n" << s.str << "'''";
return os;
}
// normal literal string
os << '\'' << s.str << '\'';
return os;
}

View File

@@ -2,22 +2,31 @@
// Distributed under the MIT License.
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP
#include "from.hpp"
#include "into.hpp"
#include "version.hpp"
#include <chrono>
#include <forward_list>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <chrono>
#include <tuple>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus >= C++17
namespace toml
{
class value; // forward decl
template<typename C, template<typename ...> class T, template<typename ...> class A>
class basic_value;
namespace detail
{
template<typename T>
using unwrap_t = typename std::decay<T>::type;
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class
@@ -41,19 +50,35 @@ struct has_mapped_type_impl
template<typename T> static std::true_type check(typename T::mapped_type*);
template<typename T> static std::false_type check(...);
};
struct has_resize_method_impl
struct has_reserve_method_impl
{
constexpr static std::size_t dummy=0;
template<typename T> static std::true_type check(decltype(std::declval<T>().resize(dummy))*);
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
};
struct has_push_back_method_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
};
struct is_comparable_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>() < std::declval<T>())*);
};
struct has_from_toml_method_impl
{
template<typename T>
template<typename T, typename C,
template<typename ...> class Tb, template<typename ...> class A>
static std::true_type check(
decltype(std::declval<T>().from_toml(std::declval<::toml::value>()))*);
template<typename T>
decltype(std::declval<T>().from_toml(
std::declval<::toml::basic_value<C, Tb, A>>()))*);
template<typename T, typename C,
template<typename ...> class Tb, template<typename ...> class A>
static std::false_type check(...);
};
struct has_into_toml_method_impl
@@ -64,6 +89,22 @@ struct has_into_toml_method_impl
static std::false_type check(...);
};
struct has_specialized_from_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::from<T>)>
static std::true_type check(::toml::from<T>*);
};
struct has_specialized_into_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
static std::true_type check(::toml::from<T>*);
};
/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
@@ -79,23 +120,41 @@ struct has_key_type : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};
template<typename T, typename C,
template<typename ...> class Tb, template<typename ...> class A>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T>(nullptr)){};
: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};
template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(nullptr)){};
#ifdef __INTEL_COMPILER
#undef decltype(...)
#undef decltype
#endif
// ---------------------------------------------------------------------------
// C++17 and/or/not
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
using std::conjunction;
using std::disjunction;
using std::negation;
#else
template<typename ...> struct conjunction : std::true_type{};
template<typename T> struct conjunction<T> : T{};
template<typename T, typename ... Ts>
@@ -113,8 +172,10 @@ struct disjunction<T, Ts...> :
template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
#endif
// ---------------------------------------------------------------------------
// normal type checker
// type checkers
template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
@@ -124,13 +185,62 @@ template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};
template<typename T> struct is_std_forward_list : std::false_type{};
template<typename T>
struct is_std_forward_list<std::forward_list<T>> : std::true_type{};
template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
has_iterator<T>, // has T::iterator
has_value_type<T>, // has T::value_type
has_key_type<T>, // has T::key_type
has_mapped_type<T> // has T::mapped_type
>{};
template<typename T> struct is_map<T&> : is_map<T>{};
template<typename T> struct is_map<T const&> : is_map<T>{};
template<typename T> struct is_map<T volatile&> : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
template<typename T>
struct is_container : conjunction<
negation<is_map<T>>, // not a map
negation<std::is_same<T, std::string>>, // not a std::string
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __has_include(<string_view>)
negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif // has_include(<string_view>)
#endif
has_iterator<T>, // has T::iterator
has_value_type<T> // has T::value_type
>{};
template<typename T> struct is_container<T&> : is_container<T>{};
template<typename T> struct is_container<T const&> : is_container<T>{};
template<typename T> struct is_container<T volatile&> : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
template<typename T>
struct is_basic_value: std::false_type{};
template<typename T> struct is_basic_value<T&> : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const&> : is_basic_value<T>{};
template<typename T> struct is_basic_value<T volatile&> : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
template<typename C, template<typename ...> class M, template<typename ...> class V>
struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
// ---------------------------------------------------------------------------
// C++14 index_sequence
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
using std::index_sequence;
using std::make_index_sequence;
#else
template<std::size_t ... Ns> struct index_sequence{};
template<typename IS, std::size_t N> struct push_back_index_sequence{};
@@ -154,10 +264,26 @@ struct index_sequence_maker<0>
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;
#endif // cplusplus >= 2014
// ---------------------------------------------------------------------------
// C++14 enable_if_t
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
using std::enable_if_t;
#else
template<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;
#endif // cplusplus >= 2014
// ---------------------------------------------------------------------------
// return_type_of_t
#if __cplusplus >= 201703L
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703
template<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;
@@ -184,6 +310,19 @@ disjunction<
>
>{};
// ---------------------------------------------------------------------------
// C++20 remove_cvref_t
template<typename T>
struct remove_cvref
{
using type = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
};
template<typename T>
using remove_cvref_t = typename remove_cvref<T>::type;
}// detail
}//toml
#endif // TOML_TRAITS

View File

@@ -2,54 +2,78 @@
// Distributed under the MIT License.
#ifndef TOML11_TYPES_HPP
#define TOML11_TYPES_HPP
#include <unordered_map>
#include <vector>
#include "comments.hpp"
#include "datetime.hpp"
#include "string.hpp"
#include "traits.hpp"
#include <vector>
#include <unordered_map>
namespace toml
{
using character = char;
template<typename Comment, // discard/preserve_comment
template<typename ...> class Table, // map-like class
template<typename ...> class Array> // vector-like class
class basic_value;
class value;
using character = char;
using key = std::string;
using Boolean = bool;
using Integer = std::int64_t;
using Float = double;
using String = ::toml::string;
using Datetime = offset_datetime;
using OffsetDatetime = offset_datetime;
using LocalDatetime = local_datetime;
using LocalDate = local_date;
using LocalTime = local_time;
using Array = std::vector<value>;
using Table = std::unordered_map<key, value>;
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ <= 4
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wshadow"
#endif
// alias for snake_case, consistency with STL/Boost, toml::key, toml::value
using boolean = Boolean;
using integer = Integer;
using floating = Float; // XXX `float` is keyword. we can't use it here
using array = Array;
using table = Table;
using boolean = bool;
using integer = std::int64_t;
using floating = double; // "float" is a keyword, cannot use it here.
// the following stuffs are structs defined here, so aliases are not needed.
// - string
// - offset_datetime
// - offset_datetime
// - local_datetime
// - local_date
// - local_time
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
#endif
// default toml::value and default array/table. these are defined after defining
// basic_value itself.
// using value = basic_value<discard_comments, std::unordered_map, std::vector>;
// using array = typename value::array_type;
// using table = typename value::table_type;
// to avoid warnings about `value_t::integer` is "shadowing" toml::integer in
// GCC -Wshadow=global.
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic push
# if 7 <= __GNUC__
# pragma GCC diagnostic ignored "-Wshadow=global"
# else // gcc-6 or older
# pragma GCC diagnostic ignored "-Wshadow"
# endif
#endif
enum class value_t : std::uint8_t
{
Empty = 0,
Boolean = 1,
Integer = 2,
Float = 3,
String = 4,
OffsetDatetime = 5,
LocalDatetime = 6,
LocalDate = 7,
LocalTime = 8,
Array = 9,
Table = 10,
Unknown = 255,
empty = 0,
boolean = 1,
integer = 2,
floating = 3,
string = 4,
offset_datetime = 5,
local_datetime = 6,
local_date = 7,
local_time = 8,
array = 9,
table = 10,
};
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
#endif
template<typename charT, typename traits>
inline std::basic_ostream<charT, traits>&
@@ -57,27 +81,27 @@ operator<<(std::basic_ostream<charT, traits>& os, value_t t)
{
switch(t)
{
case toml::value_t::Boolean : os << "boolean"; return os;
case toml::value_t::Integer : os << "integer"; return os;
case toml::value_t::Float : os << "float"; return os;
case toml::value_t::String : os << "string"; return os;
case toml::value_t::OffsetDatetime: os << "offset_datetime"; return os;
case toml::value_t::LocalDatetime : os << "local_datetime"; return os;
case toml::value_t::LocalDate : os << "local_date"; return os;
case toml::value_t::LocalTime : os << "local_time"; return os;
case toml::value_t::Array : os << "array"; return os;
case toml::value_t::Table : os << "table"; return os;
case toml::value_t::Empty : os << "empty"; return os;
case toml::value_t::Unknown : os << "unknown"; return os;
default : os << "nothing"; return os;
case value_t::boolean : os << "boolean"; return os;
case value_t::integer : os << "integer"; return os;
case value_t::floating : os << "floating"; return os;
case value_t::string : os << "string"; return os;
case value_t::offset_datetime : os << "offset_datetime"; return os;
case value_t::local_datetime : os << "local_datetime"; return os;
case value_t::local_date : os << "local_date"; return os;
case value_t::local_time : os << "local_time"; return os;
case value_t::array : os << "array"; return os;
case value_t::table : os << "table"; return os;
case value_t::empty : os << "empty"; return os;
default : os << "unknown"; return os;
}
}
template<typename charT = character, typename traits = std::char_traits<charT>,
template<typename charT = char,
typename traits = std::char_traits<charT>,
typename alloc = std::allocator<charT>>
inline std::basic_string<charT, traits, alloc> stringize(value_t t)
{
std::ostringstream oss;
std::basic_ostringstream<charT, traits, alloc> oss;
oss << t;
return oss.str();
}
@@ -85,102 +109,65 @@ inline std::basic_string<charT, traits, alloc> stringize(value_t t)
namespace detail
{
template<typename T>
constexpr inline value_t check_type()
{
using type = typename std::remove_cv<
typename std::remove_reference<T>::type
>::type;
return std::is_same<type, toml::boolean>::value ? value_t::Boolean :
std::is_integral<type>::value ? value_t::Integer :
std::is_floating_point<type>::value ? value_t::Float :
std::is_same<type, std::string>::value ? value_t::String :
std::is_same<type, toml::string>::value ? value_t::String :
std::is_same<type, toml::local_date>::value ? value_t::LocalDate :
std::is_same<type, toml::local_time>::value ? value_t::LocalTime :
is_chrono_duration<type>::value ? value_t::LocalTime :
std::is_same<type, toml::local_datetime>::value ? value_t::LocalDatetime :
std::is_same<type, toml::offset_datetime>::value ? value_t::OffsetDatetime :
std::is_same<type, std::chrono::system_clock::time_point>::value ? value_t::OffsetDatetime :
std::is_convertible<type, toml::array>::value ? value_t::Array :
std::is_convertible<type, toml::table>::value ? value_t::Table :
value_t::Unknown;
}
// helper to define a type that represents a value_t value.
template<value_t V>
using value_t_constant = std::integral_constant<value_t, V>;
constexpr inline bool is_valid(value_t vt)
{
return vt != value_t::Unknown;
}
// meta-function that convertes from value_t to the exact toml type that corresponds to.
// It takes toml::basic_value type because array and table types depend on it.
template<value_t t, typename Value> struct enum_to_type {using type = void ;};
template<typename Value> struct enum_to_type<value_t::empty , Value>{using type = void ;};
template<typename Value> struct enum_to_type<value_t::boolean , Value>{using type = boolean ;};
template<typename Value> struct enum_to_type<value_t::integer , Value>{using type = integer ;};
template<typename Value> struct enum_to_type<value_t::floating , Value>{using type = floating ;};
template<typename Value> struct enum_to_type<value_t::string , Value>{using type = string ;};
template<typename Value> struct enum_to_type<value_t::offset_datetime, Value>{using type = offset_datetime ;};
template<typename Value> struct enum_to_type<value_t::local_datetime , Value>{using type = local_datetime ;};
template<typename Value> struct enum_to_type<value_t::local_date , Value>{using type = local_date ;};
template<typename Value> struct enum_to_type<value_t::local_time , Value>{using type = local_time ;};
template<typename Value> struct enum_to_type<value_t::array , Value>{using type = typename Value::array_type;};
template<typename Value> struct enum_to_type<value_t::table , Value>{using type = typename Value::table_type;};
template<value_t t> struct toml_default_type;
template<> struct toml_default_type<value_t::Boolean > {typedef boolean type;};
template<> struct toml_default_type<value_t::Integer > {typedef integer type;};
template<> struct toml_default_type<value_t::Float > {typedef floating type;};
template<> struct toml_default_type<value_t::String > {typedef string type;};
template<> struct toml_default_type<value_t::OffsetDatetime>{typedef offset_datetime type;};
template<> struct toml_default_type<value_t::LocalDatetime> {typedef local_datetime type;};
template<> struct toml_default_type<value_t::LocalDate> {typedef local_date type;};
template<> struct toml_default_type<value_t::LocalTime> {typedef local_time type;};
template<> struct toml_default_type<value_t::Array > {typedef array type;};
template<> struct toml_default_type<value_t::Table > {typedef table type;};
template<> struct toml_default_type<value_t::Empty > {typedef void type;};
template<> struct toml_default_type<value_t::Unknown > {typedef void type;};
// meta-function that converts from an exact toml type to the enum that corresponds to.
template<typename T, typename Value>
struct type_to_enum : std::conditional<
std::is_same<T, typename Value::array_type>::value, // if T == array_type,
value_t_constant<value_t::array>, // then value_t::array
typename std::conditional< // else...
std::is_same<T, typename Value::table_type>::value, // if T == table_type
value_t_constant<value_t::table>, // then value_t::table
value_t_constant<value_t::empty> // else value_t::empty
>::type
>::type {};
template<typename Value> struct type_to_enum<boolean , Value>: value_t_constant<value_t::boolean > {};
template<typename Value> struct type_to_enum<integer , Value>: value_t_constant<value_t::integer > {};
template<typename Value> struct type_to_enum<floating , Value>: value_t_constant<value_t::floating > {};
template<typename Value> struct type_to_enum<string , Value>: value_t_constant<value_t::string > {};
template<typename Value> struct type_to_enum<offset_datetime, Value>: value_t_constant<value_t::offset_datetime> {};
template<typename Value> struct type_to_enum<local_datetime , Value>: value_t_constant<value_t::local_datetime > {};
template<typename Value> struct type_to_enum<local_date , Value>: value_t_constant<value_t::local_date > {};
template<typename Value> struct type_to_enum<local_time , Value>: value_t_constant<value_t::local_time > {};
template<typename T> struct toml_value_t {static constexpr value_t value = value_t::Unknown ;};
template<> struct toml_value_t<Boolean >{static constexpr value_t value = value_t::Boolean ;};
template<> struct toml_value_t<Integer >{static constexpr value_t value = value_t::Integer ;};
template<> struct toml_value_t<Float >{static constexpr value_t value = value_t::Float ;};
template<> struct toml_value_t<String >{static constexpr value_t value = value_t::String ;};
template<> struct toml_value_t<OffsetDatetime>{static constexpr value_t value = value_t::OffsetDatetime;};
template<> struct toml_value_t<LocalDatetime >{static constexpr value_t value = value_t::LocalDatetime ;};
template<> struct toml_value_t<LocalDate >{static constexpr value_t value = value_t::LocalDate ;};
template<> struct toml_value_t<LocalTime >{static constexpr value_t value = value_t::LocalTime ;};
template<> struct toml_value_t<Array >{static constexpr value_t value = value_t::Array ;};
template<> struct toml_value_t<Table >{static constexpr value_t value = value_t::Table ;};
template<typename T>
// meta-function that checks the type T is the same as one of the toml::* types.
template<typename T, typename Value>
struct is_exact_toml_type : disjunction<
std::is_same<T, Boolean >,
std::is_same<T, Integer >,
std::is_same<T, Float >,
std::is_same<T, String >,
std::is_same<T, boolean >,
std::is_same<T, integer >,
std::is_same<T, floating >,
std::is_same<T, string >,
std::is_same<T, offset_datetime>,
std::is_same<T, local_datetime>,
std::is_same<T, local_date>,
std::is_same<T, local_time>,
std::is_same<T, Array >,
std::is_same<T, Table >
std::is_same<T, local_datetime >,
std::is_same<T, local_date >,
std::is_same<T, local_time >,
std::is_same<T, typename Value::array_type>,
std::is_same<T, typename Value::table_type>
>{};
template<typename T> struct is_exact_toml_type<T&> : is_exact_toml_type<T>{};
template<typename T> struct is_exact_toml_type<T const&> : is_exact_toml_type<T>{};
template<typename T> struct is_exact_toml_type<T volatile&> : is_exact_toml_type<T>{};
template<typename T> struct is_exact_toml_type<T const volatile&>: is_exact_toml_type<T>{};
template<typename T>
struct is_map : conjunction<
has_iterator<T>,
has_value_type<T>,
has_key_type<T>,
has_mapped_type<T>
>{};
template<typename T> struct is_map<T&> : is_map<T>{};
template<typename T> struct is_map<T const&> : is_map<T>{};
template<typename T> struct is_map<T volatile&> : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
template<typename T>
struct is_container : conjunction<
negation<is_map<T>>,
negation<std::is_same<T, std::string>>,
has_iterator<T>,
has_value_type<T>
>{};
template<typename T> struct is_container<T&> : is_container<T>{};
template<typename T> struct is_container<T const&> : is_container<T>{};
template<typename T> struct is_container<T volatile&> : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
template<typename T, typename V> struct is_exact_toml_type<T&, V> : is_exact_toml_type<T, V>{};
template<typename T, typename V> struct is_exact_toml_type<T const&, V> : is_exact_toml_type<T, V>{};
template<typename T, typename V> struct is_exact_toml_type<T volatile&, V> : is_exact_toml_type<T, V>{};
template<typename T, typename V> struct is_exact_toml_type<T const volatile&, V>: is_exact_toml_type<T, V>{};
} // detail
} // toml
#endif// TOML11_TYPES_H

View File

@@ -2,12 +2,14 @@
// Distributed under the MIT License.
#ifndef TOML11_UTILITY_HPP
#define TOML11_UTILITY_HPP
#include "traits.hpp"
#include <utility>
#include <memory>
#include <sstream>
#include <utility>
#if __cplusplus >= 201402L
#include "traits.hpp"
#include "version.hpp"
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
#elif defined(__GNUC__)
# define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg)))
@@ -20,38 +22,41 @@
namespace toml
{
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
using std::make_unique;
#else
template<typename T, typename ... Ts>
inline std::unique_ptr<T> make_unique(Ts&& ... args)
{
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
}
#endif // TOML11_CPLUSPLUS_STANDARD_VERSION >= 2014
namespace detail
{
template<typename T>
inline void resize_impl(T& container, std::size_t N, std::true_type)
template<typename Container>
void try_reserve_impl(Container& container, std::size_t N, std::true_type)
{
container.resize(N);
return ;
container.reserve(N);
return;
}
template<typename T>
inline void resize_impl(T& container, std::size_t N, std::false_type)
template<typename Container>
void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept
{
if(container.size() >= N) {return;}
throw std::invalid_argument("not resizable type");
return;
}
} // detail
template<typename T>
inline void resize(T& container, std::size_t N)
template<typename Container>
void try_reserve(Container& container, std::size_t N)
{
if(container.size() == N) {return;}
return detail::resize_impl(container, N, detail::has_resize_method<T>());
if(N <= container.size()) {return;}
detail::try_reserve_impl(container, N, detail::has_reserve_method<Container>{});
return;
}
namespace detail
@@ -76,14 +81,70 @@ std::string concat_to_string(Ts&& ... args)
return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
}
template<typename T, typename U>
T from_string(const std::string& str, U&& opt)
template<typename T>
T from_string(const std::string& str, T opt)
{
T v(std::forward<U>(opt));
T v(opt);
std::istringstream iss(str);
iss >> v;
return v;
}
namespace detail
{
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
template<typename T>
decltype(auto) last_one(T&& tail) noexcept
{
return std::forward<T>(tail);
}
template<typename T, typename ... Ts>
decltype(auto) last_one(T&& /*head*/, Ts&& ... tail) noexcept
{
return last_one(std::forward<Ts>(tail)...);
}
#else // C++11
// The following code
// ```cpp
// 1 | template<typename T, typename ... Ts>
// 2 | auto last_one(T&& /*head*/, Ts&& ... tail)
// 3 | -> decltype(last_one(std::forward<Ts>(tail)...))
// 4 | {
// 5 | return last_one(std::forward<Ts>(tail)...);
// 6 | }
// ```
// does not work because the function `last_one(...)` is not yet defined at
// line #3, so `decltype()` cannot deduce the type returned from `last_one`.
// So we need to determine return type in a different way, like a meta func.
template<typename T, typename ... Ts>
struct last_one_in_pack
{
using type = typename last_one_in_pack<Ts...>::type;
};
template<typename T>
struct last_one_in_pack<T>
{
using type = T;
};
template<typename ... Ts>
using last_one_in_pack_t = typename last_one_in_pack<Ts...>::type;
template<typename T>
T&& last_one(T&& tail) noexcept
{
return std::forward<T>(tail);
}
template<typename T, typename ... Ts>
enable_if_t<(sizeof...(Ts) > 0), last_one_in_pack_t<Ts&& ...>>
last_one(T&& /*head*/, Ts&& ... tail)
{
return last_one(std::forward<Ts>(tail)...);
}
#endif
} // detail
}// toml
#endif // TOML11_UTILITY

File diff suppressed because it is too large Load Diff

42
toml/version.hpp Normal file
View File

@@ -0,0 +1,42 @@
#ifndef TOML11_VERSION_HPP
#define TOML11_VERSION_HPP
// This file checks C++ version.
#ifndef __cplusplus
# error "__cplusplus is not defined"
#endif
// Since MSVC does not define `__cplusplus` correctly unless you pass
// `/Zc:__cplusplus` when compiling, the workaround macros are added.
// Those enables you to define version manually or to use MSVC specific
// version macro automatically.
//
// The value of `__cplusplus` macro is defined in the C++ standard spec, but
// MSVC ignores the value, maybe because of backward compatibility. Instead,
// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in
// the C++ standard. First we check the manual version definition, and then
// we check if _MSVC_LANG is defined. If neither, use normal `__cplusplus`.
//
// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170
//
#if defined(TOML11_ENFORCE_CXX11)
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201103L
#elif defined(TOML11_ENFORCE_CXX14)
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201402L
#elif defined(TOML11_ENFORCE_CXX17)
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201703L
#elif defined(TOML11_ENFORCE_CXX20)
# define TOML11_CPLUSPLUS_STANDARD_VERSION 202002L
#elif defined(_MSVC_LANG) && defined(_MSC_VER) && 1910 <= _MSC_VER
# define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG
#else
# define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus
#endif
#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L && _MSC_VER < 1900
# error "toml11 requires C++11 or later."
#endif
#endif// TOML11_VERSION_HPP