Merge branch 'v4_1_0' into try-get

This commit is contained in:
ToruNiina 2024-07-03 01:59:52 +09:00
commit 00d6124f59
18 changed files with 444 additions and 104 deletions

View File

@ -53,7 +53,7 @@ jobs:
sudo apt-get install clang-${{ matrix.compiler }}
- name: Configure
run: |
cmake -B build/ -DCMAKE_VERBOSE_MAKEFILE=1 -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
- name: Build
run: |
cmake --build build/

View File

@ -8,7 +8,7 @@
[日本語版](https://github.com/ToruNiina/toml11/blob/main/README_ja.md)
toml11 is a feature-rich TOML language library for C++.
toml11 is a feature-rich TOML language library for C++11/14/17/20.
- It complies with [the latest TOML language specification](https://toml.io/en/v1.0.0).
- It passes all the standard TOML language [test cases](https://github.com/toml-lang/toml-test).
@ -124,6 +124,14 @@ $ cmake -B ./build/ -DTOML11_PRECOMPILE=ON -DCMAKE_CXX_STANDARD=11/14/17/20
$ cmake --build ./build/
```
When linking the library, use `target_link_libraries` in CMake
```cmake
target_link_libraries(your_target PUBLIC toml11::toml11)
```
or pass `-DTOML11_COMPILE_SOURCES` to the compiler.
### Building Example
To compile the examples in the `examples/` directory, set `-DTOML11_BUILD_EXAMPLES=ON`.

View File

@ -5,7 +5,7 @@
[![License](https://img.shields.io/github/license/ToruNiina/toml11.svg?style=flat)](LICENSE)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1209136.svg)](https://doi.org/10.5281/zenodo.1209136)
toml11は、C++のための豊富な機能を持つTOML言語ライブラリです。
toml11は、C++11,14,17,20のための豊富な機能を持つTOML言語ライブラリです。
- [TOML言語の最新規格](https://toml.io/ja/v1.0.0)に準拠しています。
- TOML言語標準のテストケースすべてにパスしています。
@ -122,6 +122,14 @@ $ cmake -B ./build/ -DTOML11_PRECOMPILE=ON -DCMAKE_CXX_STANDARD=11/14/17/20
$ cmake --build ./build/
```
ライブラリをリンクする場合は、CMakeで
```cmake
target_link_libraries(your_target PUBLIC toml11::toml11)
```
とするか、コンパイラに`-DTOML11_COMPILE_SOURCES`を渡してください。
### Building example
`-DTOML11_BUILD_EXAMPLES=ON`とすることで、`examples/`をコンパイルできます。

View File

@ -42,10 +42,18 @@ int main()
}
```
#### Specifying a File with `std::filesystem::path`
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can accept a `std::filesystem::path`.
This requires C++17 or later, as it relies on the `<filesystem>` support.
#### Specifying an Input Stream with `std::istream`
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can also accept an `std::istream`.
Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
Without the filename information, error messages will display `"unknown file"`. To avoid this, you can pass the filename as a `std::string` in the second argument when using `std::istream`.
You can use streams other than `std::ifstream`, such as `std::istringstream`. Note that the entire content is readable at the time of the call.
@ -64,16 +72,12 @@ int main()
}
```
#### Specifying a File with `std::filesystem::path`
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can accept a `std::filesystem::path`.
This requires C++17 or later, as it relies on the `<filesystem>` support.
#### Specifying a File with `FILE*`
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can also accept a `FILE*`.
Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
As with `std::istream`, you need to provide the filename as a string in the second argument.
When passing a `FILE*`, if the file read fails, `errno` will be reported.

View File

@ -54,6 +54,14 @@ By defining `-DTOML11_PRECOMPILE=ON` when running cmake, you can precompile some
$ cmake -B ./build/ -DTOML11_PRECOMPILE=ON
```
When linking the library, use `target_link_libraries` in CMake
```cmake
target_link_libraries(your_target PUBLIC toml11::toml11)
```
or pass `-DTOML11_COMPILE_SOURCES` to the compiler to suppress header-only features.
However, since toml11 supports multiple C++ versions and may switch types based on the value of `__cplusplus`,
there is a possibility of link failures if the version used during build differs from the version used during usage.
If you encounter issues, set the required version using `CMAKE_CXX_STANDARD` during compilation.

View File

@ -17,23 +17,6 @@ In case of failure, `toml::syntax_error` is thrown.
The type information of `basic_value` is provided by a `template`, and the TOML language version is specified by `toml::spec`.
### `parse(std::istream&, std::string filename, toml::spec)`
```cpp
namespace toml
{
template<typename TC = type_config>
basic_value<TC>
parse(std::istream& is,
std::string fname = "unknown file",
spec s = spec::default_version());
}
```
Parses the content of the given `std::istream&`.
The filename information is taken as the third argument. If the filename is not provided, it defaults to `"unknown file"`.
### `parse(std::string filename, toml::spec)`
```cpp
@ -90,6 +73,25 @@ If reading the file fails, `toml::file_io_error` is thrown.
If parsing fails, `toml::syntax_error` is thrown.
### `parse(std::istream&, std::string filename, toml::spec)`
```cpp
namespace toml
{
template<typename TC = type_config>
basic_value<TC>
parse(std::istream& is,
std::string fname = "unknown file",
spec s = spec::default_version());
}
```
Parses the content of the given `std::istream&`.
Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
The filename information is taken as the third argument. If the filename is not provided, it defaults to `"unknown file"`.
### `parse(FILE*, std::string filename, toml::spec)`
```cpp
@ -105,6 +107,8 @@ parse(FILE* fp,
Parses the content of the file pointed to by `FILE*`.
Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
If reading the file fails, `file_io_error` containing `errno` is thrown.
If parsing fails, `syntax_error` is thrown.
@ -166,27 +170,6 @@ For instance, errors occurring internally within `std::ifstream` or memory exhau
{{< /hint >}}
### `try_parse(std::istream&, std::string filename, toml::spec)`
```cpp
namespace toml
{
template<typename TC = type_config>
result<basic_value<TC>, std::vector<error_info>>
try_parse(std::istream& is,
std::string fname = "unknown file",
spec s = spec::default_version());
}
```
Takes a `std::istream&` and parses its content.
The file name information is taken as the second argument. If a file name is not provided, it defaults to `"unknown file"`.
If parsing fails, a `result` holding the error type `std::vector<error_info>` is returned.
If successful, a `result` holding a `basic_value` is returned.
### `try_parse(std::string filename, toml::spec)`
```cpp
@ -241,6 +224,29 @@ If parsing fails, a `result` holding the error type `std::vector<error_info>` is
If successful, a `result` holding a `basic_value` is returned.
### `try_parse(std::istream&, std::string filename, toml::spec)`
```cpp
namespace toml
{
template<typename TC = type_config>
result<basic_value<TC>, std::vector<error_info>>
try_parse(std::istream& is,
std::string fname = "unknown file",
spec s = spec::default_version());
}
```
Takes a `std::istream&` and parses its content.
Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
The file name information is taken as the second argument. If a file name is not provided, it defaults to `"unknown file"`.
If parsing fails, a `result` holding the error type `std::vector<error_info>` is returned.
If successful, a `result` holding a `basic_value` is returned.
### `try_parse(FILE*, std::string filename, toml::spec)`
```cpp
@ -256,6 +262,8 @@ try_parse(FILE* fp,
Takes a `FILE*` and parses its content.
Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
If parsing fails, a `result` holding the error type `std::vector<error_info>` is returned.
If successful, a `result` holding a `basic_value` is returned.

View File

@ -44,11 +44,21 @@ int main()
}
```
#### `std::filesystem::path`でファイルを指定する
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}})
には、`std::filesystem::path`を渡すことも可能です。
当然ですが、`<filesystem>`がサポートされるC++17以降でなければ使用できません。
#### `std::istream`で入力ストリームを指定する
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}})
には、`std::istream`を渡すことも可能です。
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
`std::ios::binary`を使ってバイナリモードで開いてください。
その際、ファイル名の情報がなくなるため、エラーメッセージ中では `"unknown file"` となります。
これを避けるため、 `std::istream` を取る場合は第二引数に `std::string` でファイル名を取ることもできます。
@ -70,18 +80,14 @@ int main()
}
```
#### `std::filesystem::path`でファイルを指定する
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}})
には、`std::filesystem::path`を渡すことも可能です。
当然ですが、`<filesystem>`がサポートされるC++17以降でなければ使用できません。
#### `FILE*`でファイルを指定する
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}})
には、`FILE*`を渡すことも可能です。
標準ライブラリによる改行文字の自動変換によるファイルサイズと文字数との不整合を避けるため、
`fopen("example.toml", "rb")`のようにしてバイナリモードで開いてください。
この場合も、`std::istream`のときと同様に、第二引数に文字列でファイル名を与える必要があります。
`FILE*`を渡した場合、ファイルの読み込みに失敗した際には`errno`が報告されます。

View File

@ -54,6 +54,14 @@ target_link_libraries(main PRIVATE toml11::toml11)
$ cmake -B ./build/ -DTOML11_PRECOMPILE=ON
```
ライブラリをリンクする場合は、CMakeで
```cmake
target_link_libraries(your_target PUBLIC toml11::toml11)
```
とするか、ヘッダ内の関数の`inline`化を避けるためにコンパイラに`-DTOML11_COMPILE_SOURCES`を渡してください。
ただし、toml11は複数のC++バージョンに対応するため、`__cplusplus`の値などによって型を切り替えることがあります。
そのため、ビルドした際のバージョンと使用時のバージョンが異なる場合、リンクに失敗する可能性があります。
問題が生じた場合は`CMAKE_CXX_STANDARD`によって必要なバージョンを設定してコンパイルしてください。

View File

@ -17,23 +17,6 @@ type = "docs"
`basic_value`の持つ型情報は`template`で、TOML言語のバージョンは`toml::spec`で指定します。
### `parse(std::istream&, std::string filename, toml::spec)`
```cpp
namespace toml
{
template<typename TC = type_config>
basic_value<TC>
parse(std::istream& is,
std::string fname = "unknown file",
spec s = spec::default_version());
}
```
`std::istream&`を受け取ってその内容をパースします。
ファイル名の情報は第三引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。
### `parse(std::string filename, toml::spec)`
```cpp
@ -90,6 +73,25 @@ parse(const std::filesystem::path& fpath,
パースに失敗した場合、`syntax_error`が送出されます。
### `parse(std::istream&, std::string filename, toml::spec)`
```cpp
namespace toml
{
template<typename TC = type_config>
basic_value<TC>
parse(std::istream& is,
std::string fname = "unknown file",
spec s = spec::default_version());
}
```
`std::istream&`を受け取ってその内容をパースします。
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
`std::ios::binary`を使ってバイナリモードで開いてください。
ファイル名の情報は第三引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。
### `parse(FILE*, std::string filename, toml::spec)`
@ -106,6 +108,9 @@ parse(FILE* fp,
`FILE*`が指すファイルを読み込んでパースします。
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
`fopen`には`"rb"`などを渡してバイナリモードで開いてください。
ファイルの読み込みに失敗した場合、`errno`が含まれた`file_io_error`が送出されます。
パースに失敗した場合、`syntax_error`が送出されます。
@ -167,28 +172,6 @@ parse_str(std::string content,
{{< /hint >}}
### `try_parse(std::istream&, std::string filename, toml::spec)`
```cpp
namespace toml
{
template<typename TC = type_config>
result<basic_value<TC>, std::vector<error_info>>
try_parse(std::istream& is,
std::string fname = "unknown file",
spec s = spec::default_version());
}
```
`std::istream&`を受け取ってその内容をパースします。
ファイル名の情報は第二引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。
パースに失敗した場合、エラー型である`std::vector<error_info>`を持つ`result`が返されます。
成功した場合、`basic_value`を持つ`result`が返されます。
### `try_parse(std::string filename, toml::spec)`
```cpp
@ -244,6 +227,30 @@ try_parse(const std::filesystem::path& fpath,
成功した場合、`basic_value`を持つ`result`が返されます。
### `try_parse(std::istream&, std::string filename, toml::spec)`
```cpp
namespace toml
{
template<typename TC = type_config>
result<basic_value<TC>, std::vector<error_info>>
try_parse(std::istream& is,
std::string fname = "unknown file",
spec s = spec::default_version());
}
```
`std::istream&`を受け取ってその内容をパースします。
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
`std::ios::binary`を使ってバイナリモードで開いてください。
ファイル名の情報は第二引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。
パースに失敗した場合、エラー型である`std::vector<error_info>`を持つ`result`が返されます。
成功した場合、`basic_value`を持つ`result`が返されます。
### `try_parse(FILE*, std::string filename, toml::spec)`
```cpp
@ -259,6 +266,9 @@ try_parse(FILE* fp,
`FILE*`を受け取って、そのファイルの内容をパースします。
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
`fopen`には`"rb"`などを渡してバイナリモードで開いてください。
パースに失敗した場合、エラー型である`std::vector<error_info>`を持つ`result`が返されます。
成功した場合、`basic_value`を持つ`result`が返されます。

View File

@ -41,6 +41,10 @@ struct error_info
std::string suffix_; // hint or something like that
};
// forward decl
template<typename TypeConfig>
class basic_value;
namespace detail
{
inline error_info make_error_info_rec(error_info e)
@ -53,6 +57,10 @@ inline error_info make_error_info_rec(error_info e, std::string s)
return e;
}
template<typename TC, typename ... Ts>
error_info make_error_info_rec(error_info e,
const basic_value<TC>& v, std::string msg, Ts&& ... tail);
template<typename ... Ts>
error_info make_error_info_rec(error_info e,
source_location loc, std::string msg, Ts&& ... tail)

View File

@ -3524,7 +3524,7 @@ try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::d
// read whole file as a sequence of char
assert(fsize >= 0);
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize), '\0');
is.read(reinterpret_cast<char*>(letters.data()), fsize);
return detail::parse_impl<TC>(std::move(letters), std::move(fname), std::move(s));
@ -3714,7 +3714,15 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
// read whole file as a sequence of char
assert(fsize >= 0);
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
if(actual != static_cast<std::size_t>(fsize))
{
return err(std::vector<error_info>{error_info(
std::string("File size changed: \"") + filename +
std::string("\" make sure that FILE* is in binary mode "
"to avoid LF <-> CRLF conversion"), {}
)});
}
return detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));
}
@ -3752,7 +3760,12 @@ parse(FILE* fp, std::string filename, spec s = spec::default_version())
// read whole file as a sequence of char
assert(fsize >= 0);
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
if(actual != static_cast<std::size_t>(fsize))
{
throw file_io_error(errno, "File size changed; make sure that "
"FILE* is in binary mode to avoid LF <-> CRLF conversion", filename);
}
auto res = detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));
if(res.is_ok())

View File

@ -2102,12 +2102,16 @@ operator>=(const basic_value<TC>& lhs, const basic_value<TC>& rhs)
}
// error_info helper
namespace detail
{
template<typename TC, typename ... Ts>
error_info make_error_info_rec(error_info e,
const basic_value<TC>& v, std::string msg, Ts&& ... tail)
{
return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward<Ts>(tail)...);
}
} // detail
template<typename TC, typename ... Ts>
error_info make_error_info(
std::string title, const basic_value<TC>& v, std::string msg, Ts&& ... tail)

View File

@ -3,7 +3,7 @@
#define TOML11_VERSION_MAJOR 4
#define TOML11_VERSION_MINOR 0
#define TOML11_VERSION_PATCH 1
#define TOML11_VERSION_PATCH 2
#ifndef __cplusplus
# error "__cplusplus is not defined"

View File

@ -52,8 +52,7 @@ struct local_time_format_info;
struct array_format_info;
struct table_format_info;
template<typename Key, typename Val, typename Cmp = std::equal_to<Key>,
typename Allocator = std::allocator<std::pair<Key, Val>>>
template<typename Key, typename Val, typename Cmp, typename Allocator>
class ordered_map;
struct syntax_error;

View File

@ -3,7 +3,7 @@
#define TOML11_VERSION_MAJOR 4
#define TOML11_VERSION_MINOR 0
#define TOML11_VERSION_PATCH 1
#define TOML11_VERSION_PATCH 2
#ifndef __cplusplus
# error "__cplusplus is not defined"
@ -3584,7 +3584,7 @@ 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>*);
static std::true_type check(::toml::into<T>*);
};
@ -5447,6 +5447,10 @@ struct error_info
std::string suffix_; // hint or something like that
};
// forward decl
template<typename TypeConfig>
class basic_value;
namespace detail
{
inline error_info make_error_info_rec(error_info e)
@ -5459,6 +5463,10 @@ inline error_info make_error_info_rec(error_info e, std::string s)
return e;
}
template<typename TC, typename ... Ts>
error_info make_error_info_rec(error_info e,
const basic_value<TC>& v, std::string msg, Ts&& ... tail);
template<typename ... Ts>
error_info make_error_info_rec(error_info e,
source_location loc, std::string msg, Ts&& ... tail)
@ -7588,12 +7596,16 @@ operator>=(const basic_value<TC>& lhs, const basic_value<TC>& rhs)
}
// error_info helper
namespace detail
{
template<typename TC, typename ... Ts>
error_info make_error_info_rec(error_info e,
const basic_value<TC>& v, std::string msg, Ts&& ... tail)
{
return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward<Ts>(tail)...);
}
} // detail
template<typename TC, typename ... Ts>
error_info make_error_info(
std::string title, const basic_value<TC>& v, std::string msg, Ts&& ... tail)
@ -15063,7 +15075,7 @@ try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::d
// read whole file as a sequence of char
assert(fsize >= 0);
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize), '\0');
is.read(reinterpret_cast<char*>(letters.data()), fsize);
return detail::parse_impl<TC>(std::move(letters), std::move(fname), std::move(s));
@ -15253,7 +15265,15 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
// read whole file as a sequence of char
assert(fsize >= 0);
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
if(actual != static_cast<std::size_t>(fsize))
{
return err(std::vector<error_info>{error_info(
std::string("File size changed: \"") + filename +
std::string("\" make sure that FILE* is in binary mode "
"to avoid LF <-> CRLF conversion"), {}
)});
}
return detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));
}
@ -15291,7 +15311,12 @@ parse(FILE* fp, std::string filename, spec s = spec::default_version())
// read whole file as a sequence of char
assert(fsize >= 0);
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
if(actual != static_cast<std::size_t>(fsize))
{
throw file_io_error(errno, "File size changed; make sure that "
"FILE* is in binary mode to avoid LF <-> CRLF conversion", filename);
}
auto res = detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));
if(res.is_ok())

View File

@ -1,6 +1,7 @@
set(TOML11_TEST_NAMES
test_comments
test_datetime
test_error_message
test_find
test_try_find
test_find_or
@ -24,6 +25,7 @@ set(TOML11_TEST_NAMES
test_parse_table
test_result
test_scanner
test_serialize
test_syntax_boolean
test_syntax_integer
test_syntax_floating

View File

@ -0,0 +1,79 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
#include <toml.hpp>
TEST_CASE("testing custom error message using source_location")
{
const toml::value root = toml::parse_str(R"(
range = [0, 42]
val = 54
)");
const auto& lower = root.at("range").at(0);
const auto& upper = root.at("range").at(1);
const auto& val = root.at("val");
const auto err = toml::make_error_info("val not in range",
lower.location(), "lower limit is defined here",
upper.location(), "upper limit is defined here",
val.location(), "this is not in the range",
"Hint: upper limit is inclusive"
);
CHECK_EQ(err.title(), "val not in range");
CHECK_EQ(err.locations().size(), 3);
CHECK_EQ(err.locations().at(0).second, "lower limit is defined here");
CHECK_EQ(err.locations().at(1).second, "upper limit is defined here");
CHECK_EQ(err.locations().at(2).second, "this is not in the range" );
}
TEST_CASE("testing custom error message using value")
{
const toml::value root = toml::parse_str(R"(
range = [0, 42]
val = 54
)");
const auto& lower = root.at("range").at(0);
const auto& upper = root.at("range").at(1);
const auto& val = root.at("val");
const auto err = toml::make_error_info("val not in range",
lower, "lower limit is defined here",
upper, "upper limit is defined here",
val, "this is not in the range",
"Hint: upper limit is inclusive"
);
CHECK_EQ(err.title(), "val not in range");
CHECK_EQ(err.locations().size(), 3);
CHECK_EQ(err.locations().at(0).second, "lower limit is defined here");
CHECK_EQ(err.locations().at(1).second, "upper limit is defined here");
CHECK_EQ(err.locations().at(2).second, "this is not in the range" );
}
TEST_CASE("testing custom error message using source_location and value")
{
const toml::value root = toml::parse_str(R"(
range = [0, 42]
val = 54
)");
const auto& lower = root.at("range").at(0);
const auto& upper = root.at("range").at(1);
const auto& val = root.at("val");
const auto err = toml::make_error_info("val not in range",
lower, "lower limit is defined here",
upper, "upper limit is defined here",
val.location(), "this is not in the range",
"Hint: upper limit is inclusive"
);
CHECK_EQ(err.title(), "val not in range");
CHECK_EQ(err.locations().size(), 3);
CHECK_EQ(err.locations().at(0).second, "lower limit is defined here");
CHECK_EQ(err.locations().at(1).second, "upper limit is defined here");
CHECK_EQ(err.locations().at(2).second, "this is not in the range" );
}

150
tests/test_serialize.cpp Normal file
View File

@ -0,0 +1,150 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
#include <toml.hpp>
#include <clocale>
TEST_CASE("testing serialization")
{
using namespace toml::literals::toml_literals;
const auto spec_example = R"(# This is a TOML document
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }
[servers]
[servers.alpha]
ip = "10.0.0.1"
role = "frontend"
[servers.beta]
ip = "10.0.0.2"
role = "backend")"_toml;
// format and parse
const auto v = toml::parse_str(toml::format(spec_example));
CHECK_EQ(v, spec_example);
}
TEST_CASE("testing serialization with complicated keys")
{
using namespace toml::literals::toml_literals;
const auto spec_example = R"(
[keys]
key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value"
"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value"
"" = "blank"
fruits.apple.skin = "thin"
fruits.apple.color = "red"
fruits.orange.skin = "thick"
fruits.orange.color = "orange"
site."google.com" = true
3.14159 = "pi"
)"_toml;
// format and parse
const auto v = toml::parse_str(toml::format(spec_example));
CHECK_EQ(v, spec_example);
}
TEST_CASE("testing serialization with array of tables")
{
using namespace toml::literals::toml_literals;
const auto spec_example = R"(
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]
[[products]]
name = "Hammer"
sku = 738594937
[[products]] # empty table within the array
[[products]]
name = "Nail"
sku = 284758393
color = "gray"
[[fruits]]
name = "apple"
[fruits.physical] # subtable
color = "red"
shape = "round"
[[fruits.varieties]] # nested array of tables
name = "red delicious"
[[fruits.varieties]]
name = "granny smith"
[[fruits]]
name = "banana"
[[fruits.varieties]]
name = "plantain"
)"_toml;
// format and parse
const auto v = toml::parse_str(toml::format(spec_example));
CHECK_EQ(v, spec_example);
}
TEST_CASE("testing serialization with locale")
{
std::string current_locale = std::setlocale(LC_ALL, nullptr);
// fr_FR is a one of locales that uses `,` as a decimal separator.
if(const char* try_hyphen = std::setlocale(LC_ALL, "fr_FR.UTF-8"))
{
current_locale = std::string(try_hyphen);
}
else if(const char* try_nohyphen = std::setlocale(LC_ALL, "fr_FR.utf8"))
{
current_locale = std::string(try_nohyphen);
}
MESSAGE("current_locale = ", current_locale);
const auto v1 = toml::parse_str(R"(
pi = 3.1415_9265
large_int = 123_456_789
)");
const auto v2 = toml::parse_str(toml::format(v1));
// actually, it checkl if v1 is serialized correctly under FR locale
// where 3.1415 -> 3,1415
CHECK_EQ(v1, v2);
}