From 4cf77c52bc060a5d5568130a22e87f9f791e5969 Mon Sep 17 00:00:00 2001 From: polar Date: Tue, 26 Mar 2024 14:34:37 +0000 Subject: [PATCH 1/3] moved toml11 to subprojects --- {src => subprojects}/toml11/LICENSE | 0 {src => subprojects}/toml11/README.md | 0 {src => subprojects}/toml11/toml.hpp | 0 {src => subprojects}/toml11/toml/color.hpp | 0 {src => subprojects}/toml11/toml/combinator.hpp | 0 {src => subprojects}/toml11/toml/comments.hpp | 0 {src => subprojects}/toml11/toml/datetime.hpp | 0 {src => subprojects}/toml11/toml/exception.hpp | 0 {src => subprojects}/toml11/toml/from.hpp | 0 {src => subprojects}/toml11/toml/get.hpp | 0 {src => subprojects}/toml11/toml/into.hpp | 0 {src => subprojects}/toml11/toml/lexer.hpp | 0 {src => subprojects}/toml11/toml/literal.hpp | 0 {src => subprojects}/toml11/toml/macros.hpp | 0 {src => subprojects}/toml11/toml/parser.hpp | 0 {src => subprojects}/toml11/toml/region.hpp | 0 {src => subprojects}/toml11/toml/result.hpp | 0 {src => subprojects}/toml11/toml/serializer.hpp | 0 {src => subprojects}/toml11/toml/source_location.hpp | 0 {src => subprojects}/toml11/toml/storage.hpp | 0 {src => subprojects}/toml11/toml/string.hpp | 0 {src => subprojects}/toml11/toml/traits.hpp | 0 {src => subprojects}/toml11/toml/types.hpp | 0 {src => subprojects}/toml11/toml/utility.hpp | 0 {src => subprojects}/toml11/toml/value.hpp | 0 25 files changed, 0 insertions(+), 0 deletions(-) rename {src => subprojects}/toml11/LICENSE (100%) rename {src => subprojects}/toml11/README.md (100%) rename {src => subprojects}/toml11/toml.hpp (100%) rename {src => subprojects}/toml11/toml/color.hpp (100%) rename {src => subprojects}/toml11/toml/combinator.hpp (100%) rename {src => subprojects}/toml11/toml/comments.hpp (100%) rename {src => subprojects}/toml11/toml/datetime.hpp (100%) rename {src => subprojects}/toml11/toml/exception.hpp (100%) rename {src => subprojects}/toml11/toml/from.hpp (100%) rename {src => subprojects}/toml11/toml/get.hpp (100%) rename {src => subprojects}/toml11/toml/into.hpp (100%) rename {src => subprojects}/toml11/toml/lexer.hpp (100%) rename {src => subprojects}/toml11/toml/literal.hpp (100%) rename {src => subprojects}/toml11/toml/macros.hpp (100%) rename {src => subprojects}/toml11/toml/parser.hpp (100%) rename {src => subprojects}/toml11/toml/region.hpp (100%) rename {src => subprojects}/toml11/toml/result.hpp (100%) rename {src => subprojects}/toml11/toml/serializer.hpp (100%) rename {src => subprojects}/toml11/toml/source_location.hpp (100%) rename {src => subprojects}/toml11/toml/storage.hpp (100%) rename {src => subprojects}/toml11/toml/string.hpp (100%) rename {src => subprojects}/toml11/toml/traits.hpp (100%) rename {src => subprojects}/toml11/toml/types.hpp (100%) rename {src => subprojects}/toml11/toml/utility.hpp (100%) rename {src => subprojects}/toml11/toml/value.hpp (100%) diff --git a/src/toml11/LICENSE b/subprojects/toml11/LICENSE similarity index 100% rename from src/toml11/LICENSE rename to subprojects/toml11/LICENSE diff --git a/src/toml11/README.md b/subprojects/toml11/README.md similarity index 100% rename from src/toml11/README.md rename to subprojects/toml11/README.md diff --git a/src/toml11/toml.hpp b/subprojects/toml11/toml.hpp similarity index 100% rename from src/toml11/toml.hpp rename to subprojects/toml11/toml.hpp diff --git a/src/toml11/toml/color.hpp b/subprojects/toml11/toml/color.hpp similarity index 100% rename from src/toml11/toml/color.hpp rename to subprojects/toml11/toml/color.hpp diff --git a/src/toml11/toml/combinator.hpp b/subprojects/toml11/toml/combinator.hpp similarity index 100% rename from src/toml11/toml/combinator.hpp rename to subprojects/toml11/toml/combinator.hpp diff --git a/src/toml11/toml/comments.hpp b/subprojects/toml11/toml/comments.hpp similarity index 100% rename from src/toml11/toml/comments.hpp rename to subprojects/toml11/toml/comments.hpp diff --git a/src/toml11/toml/datetime.hpp b/subprojects/toml11/toml/datetime.hpp similarity index 100% rename from src/toml11/toml/datetime.hpp rename to subprojects/toml11/toml/datetime.hpp diff --git a/src/toml11/toml/exception.hpp b/subprojects/toml11/toml/exception.hpp similarity index 100% rename from src/toml11/toml/exception.hpp rename to subprojects/toml11/toml/exception.hpp diff --git a/src/toml11/toml/from.hpp b/subprojects/toml11/toml/from.hpp similarity index 100% rename from src/toml11/toml/from.hpp rename to subprojects/toml11/toml/from.hpp diff --git a/src/toml11/toml/get.hpp b/subprojects/toml11/toml/get.hpp similarity index 100% rename from src/toml11/toml/get.hpp rename to subprojects/toml11/toml/get.hpp diff --git a/src/toml11/toml/into.hpp b/subprojects/toml11/toml/into.hpp similarity index 100% rename from src/toml11/toml/into.hpp rename to subprojects/toml11/toml/into.hpp diff --git a/src/toml11/toml/lexer.hpp b/subprojects/toml11/toml/lexer.hpp similarity index 100% rename from src/toml11/toml/lexer.hpp rename to subprojects/toml11/toml/lexer.hpp diff --git a/src/toml11/toml/literal.hpp b/subprojects/toml11/toml/literal.hpp similarity index 100% rename from src/toml11/toml/literal.hpp rename to subprojects/toml11/toml/literal.hpp diff --git a/src/toml11/toml/macros.hpp b/subprojects/toml11/toml/macros.hpp similarity index 100% rename from src/toml11/toml/macros.hpp rename to subprojects/toml11/toml/macros.hpp diff --git a/src/toml11/toml/parser.hpp b/subprojects/toml11/toml/parser.hpp similarity index 100% rename from src/toml11/toml/parser.hpp rename to subprojects/toml11/toml/parser.hpp diff --git a/src/toml11/toml/region.hpp b/subprojects/toml11/toml/region.hpp similarity index 100% rename from src/toml11/toml/region.hpp rename to subprojects/toml11/toml/region.hpp diff --git a/src/toml11/toml/result.hpp b/subprojects/toml11/toml/result.hpp similarity index 100% rename from src/toml11/toml/result.hpp rename to subprojects/toml11/toml/result.hpp diff --git a/src/toml11/toml/serializer.hpp b/subprojects/toml11/toml/serializer.hpp similarity index 100% rename from src/toml11/toml/serializer.hpp rename to subprojects/toml11/toml/serializer.hpp diff --git a/src/toml11/toml/source_location.hpp b/subprojects/toml11/toml/source_location.hpp similarity index 100% rename from src/toml11/toml/source_location.hpp rename to subprojects/toml11/toml/source_location.hpp diff --git a/src/toml11/toml/storage.hpp b/subprojects/toml11/toml/storage.hpp similarity index 100% rename from src/toml11/toml/storage.hpp rename to subprojects/toml11/toml/storage.hpp diff --git a/src/toml11/toml/string.hpp b/subprojects/toml11/toml/string.hpp similarity index 100% rename from src/toml11/toml/string.hpp rename to subprojects/toml11/toml/string.hpp diff --git a/src/toml11/toml/traits.hpp b/subprojects/toml11/toml/traits.hpp similarity index 100% rename from src/toml11/toml/traits.hpp rename to subprojects/toml11/toml/traits.hpp diff --git a/src/toml11/toml/types.hpp b/subprojects/toml11/toml/types.hpp similarity index 100% rename from src/toml11/toml/types.hpp rename to subprojects/toml11/toml/types.hpp diff --git a/src/toml11/toml/utility.hpp b/subprojects/toml11/toml/utility.hpp similarity index 100% rename from src/toml11/toml/utility.hpp rename to subprojects/toml11/toml/utility.hpp diff --git a/src/toml11/toml/value.hpp b/subprojects/toml11/toml/value.hpp similarity index 100% rename from src/toml11/toml/value.hpp rename to subprojects/toml11/toml/value.hpp From 45ce879aa5a4c9f7596d66794a8f205e30f88e2a Mon Sep 17 00:00:00 2001 From: polar Date: Tue, 26 Mar 2024 15:43:54 +0000 Subject: [PATCH 2/3] updated toml --- subprojects/toml11/.circleci/config.yml | 88 ++ .../toml11/.clusterfuzzlite/Dockerfile | 6 + subprojects/toml11/.clusterfuzzlite/README.md | 3 + subprojects/toml11/.clusterfuzzlite/build.sh | 6 + .../toml11/.clusterfuzzlite/parse_fuzzer.cpp | 16 + .../toml11/.clusterfuzzlite/project.yaml | 1 + subprojects/toml11/.editorconfig | 13 + .../toml11/.github/workflows/cflite_pr.yml | 30 + subprojects/toml11/.github/workflows/main.yml | 280 +++++ subprojects/toml11/.gitignore | 1 + subprojects/toml11/CMakeLists.txt | 121 ++ subprojects/toml11/README.md | 158 ++- subprojects/toml11/appveyor.yml | 25 + .../toml11/cmake/toml11Config.cmake.in | 2 + subprojects/toml11/tests/CMakeLists.txt | 291 +++++ subprojects/toml11/tests/check.cpp | 42 + .../toml11/tests/check_serialization.cpp | 114 ++ subprojects/toml11/tests/check_toml_test.cpp | 139 +++ subprojects/toml11/tests/test_comments.cpp | 545 +++++++++ subprojects/toml11/tests/test_datetime.cpp | 117 ++ .../toml11/tests/test_error_detection.cpp | 97 ++ subprojects/toml11/tests/test_expect.cpp | 26 + .../tests/test_extended_conversions.cpp | 627 ++++++++++ subprojects/toml11/tests/test_find.cpp | 827 ++++++++++++++ subprojects/toml11/tests/test_find_or.cpp | 538 +++++++++ .../toml11/tests/test_find_or_recursive.cpp | 393 +++++++ .../toml11/tests/test_format_error.cpp | 72 ++ subprojects/toml11/tests/test_get.cpp | 505 ++++++++ subprojects/toml11/tests/test_get_or.cpp | 449 ++++++++ subprojects/toml11/tests/test_lex_aux.hpp | 36 + subprojects/toml11/tests/test_lex_boolean.cpp | 23 + .../toml11/tests/test_lex_datetime.cpp | 57 + .../toml11/tests/test_lex_floating.cpp | 107 ++ subprojects/toml11/tests/test_lex_integer.cpp | 101 ++ .../toml11/tests/test_lex_key_comment.cpp | 52 + subprojects/toml11/tests/test_lex_string.cpp | 108 ++ subprojects/toml11/tests/test_literals.cpp | 336 ++++++ .../test_multiple_translation_unit_1.cpp | 11 + .../test_multiple_translation_unit_2.cpp | 6 + subprojects/toml11/tests/test_parse_array.cpp | 288 +++++ subprojects/toml11/tests/test_parse_aux.hpp | 54 + .../toml11/tests/test_parse_boolean.cpp | 19 + .../toml11/tests/test_parse_datetime.cpp | 246 ++++ subprojects/toml11/tests/test_parse_file.cpp | 1009 ++++++++++++++++ .../toml11/tests/test_parse_floating.cpp | 181 +++ .../toml11/tests/test_parse_inline_table.cpp | 59 + .../toml11/tests/test_parse_integer.cpp | 116 ++ subprojects/toml11/tests/test_parse_key.cpp | 58 + .../toml11/tests/test_parse_string.cpp | 245 ++++ subprojects/toml11/tests/test_parse_table.cpp | 45 + .../toml11/tests/test_parse_table_key.cpp | 112 ++ .../toml11/tests/test_parse_unicode.cpp | 37 + subprojects/toml11/tests/test_result.cpp | 440 +++++++ .../toml11/tests/test_serialize_file.cpp | 405 +++++++ subprojects/toml11/tests/test_string.cpp | 153 +++ subprojects/toml11/tests/test_traits.cpp | 79 ++ subprojects/toml11/tests/test_utility.cpp | 45 + subprojects/toml11/tests/test_value.cpp | 1015 +++++++++++++++++ subprojects/toml11/tests/test_windows.cpp | 12 + subprojects/toml11/tests/unit_test.hpp | 23 + subprojects/toml11/toml.hpp | 12 +- subprojects/toml11/toml/color.hpp | 45 + subprojects/toml11/toml/comments.hpp | 24 +- subprojects/toml11/toml/datetime.hpp | 52 +- subprojects/toml11/toml/exception.hpp | 20 +- subprojects/toml11/toml/get.hpp | 37 + subprojects/toml11/toml/lexer.hpp | 27 +- subprojects/toml11/toml/literal.hpp | 2 +- subprojects/toml11/toml/parser.hpp | 353 +++++- subprojects/toml11/toml/region.hpp | 7 +- subprojects/toml11/toml/serializer.hpp | 76 +- subprojects/toml11/toml/source_location.hpp | 12 +- subprojects/toml11/toml/string.hpp | 5 +- subprojects/toml11/toml/traits.hpp | 17 +- subprojects/toml11/toml/utility.hpp | 9 +- subprojects/toml11/toml/value.hpp | 8 +- subprojects/toml11/toml/version.hpp | 42 + 77 files changed, 11602 insertions(+), 156 deletions(-) create mode 100644 subprojects/toml11/.circleci/config.yml create mode 100644 subprojects/toml11/.clusterfuzzlite/Dockerfile create mode 100644 subprojects/toml11/.clusterfuzzlite/README.md create mode 100644 subprojects/toml11/.clusterfuzzlite/build.sh create mode 100644 subprojects/toml11/.clusterfuzzlite/parse_fuzzer.cpp create mode 100644 subprojects/toml11/.clusterfuzzlite/project.yaml create mode 100644 subprojects/toml11/.editorconfig create mode 100644 subprojects/toml11/.github/workflows/cflite_pr.yml create mode 100644 subprojects/toml11/.github/workflows/main.yml create mode 100644 subprojects/toml11/.gitignore create mode 100644 subprojects/toml11/CMakeLists.txt create mode 100644 subprojects/toml11/appveyor.yml create mode 100644 subprojects/toml11/cmake/toml11Config.cmake.in create mode 100644 subprojects/toml11/tests/CMakeLists.txt create mode 100644 subprojects/toml11/tests/check.cpp create mode 100644 subprojects/toml11/tests/check_serialization.cpp create mode 100644 subprojects/toml11/tests/check_toml_test.cpp create mode 100644 subprojects/toml11/tests/test_comments.cpp create mode 100644 subprojects/toml11/tests/test_datetime.cpp create mode 100644 subprojects/toml11/tests/test_error_detection.cpp create mode 100644 subprojects/toml11/tests/test_expect.cpp create mode 100644 subprojects/toml11/tests/test_extended_conversions.cpp create mode 100644 subprojects/toml11/tests/test_find.cpp create mode 100644 subprojects/toml11/tests/test_find_or.cpp create mode 100644 subprojects/toml11/tests/test_find_or_recursive.cpp create mode 100644 subprojects/toml11/tests/test_format_error.cpp create mode 100644 subprojects/toml11/tests/test_get.cpp create mode 100644 subprojects/toml11/tests/test_get_or.cpp create mode 100644 subprojects/toml11/tests/test_lex_aux.hpp create mode 100644 subprojects/toml11/tests/test_lex_boolean.cpp create mode 100644 subprojects/toml11/tests/test_lex_datetime.cpp create mode 100644 subprojects/toml11/tests/test_lex_floating.cpp create mode 100644 subprojects/toml11/tests/test_lex_integer.cpp create mode 100644 subprojects/toml11/tests/test_lex_key_comment.cpp create mode 100644 subprojects/toml11/tests/test_lex_string.cpp create mode 100644 subprojects/toml11/tests/test_literals.cpp create mode 100644 subprojects/toml11/tests/test_multiple_translation_unit_1.cpp create mode 100644 subprojects/toml11/tests/test_multiple_translation_unit_2.cpp create mode 100644 subprojects/toml11/tests/test_parse_array.cpp create mode 100644 subprojects/toml11/tests/test_parse_aux.hpp create mode 100644 subprojects/toml11/tests/test_parse_boolean.cpp create mode 100644 subprojects/toml11/tests/test_parse_datetime.cpp create mode 100644 subprojects/toml11/tests/test_parse_file.cpp create mode 100644 subprojects/toml11/tests/test_parse_floating.cpp create mode 100644 subprojects/toml11/tests/test_parse_inline_table.cpp create mode 100644 subprojects/toml11/tests/test_parse_integer.cpp create mode 100644 subprojects/toml11/tests/test_parse_key.cpp create mode 100644 subprojects/toml11/tests/test_parse_string.cpp create mode 100644 subprojects/toml11/tests/test_parse_table.cpp create mode 100644 subprojects/toml11/tests/test_parse_table_key.cpp create mode 100644 subprojects/toml11/tests/test_parse_unicode.cpp create mode 100644 subprojects/toml11/tests/test_result.cpp create mode 100644 subprojects/toml11/tests/test_serialize_file.cpp create mode 100644 subprojects/toml11/tests/test_string.cpp create mode 100644 subprojects/toml11/tests/test_traits.cpp create mode 100644 subprojects/toml11/tests/test_utility.cpp create mode 100644 subprojects/toml11/tests/test_value.cpp create mode 100644 subprojects/toml11/tests/test_windows.cpp create mode 100644 subprojects/toml11/tests/unit_test.hpp create mode 100644 subprojects/toml11/toml/version.hpp diff --git a/subprojects/toml11/.circleci/config.yml b/subprojects/toml11/.circleci/config.yml new file mode 100644 index 00000000000..cd773921b0b --- /dev/null +++ b/subprojects/toml11/.circleci/config.yml @@ -0,0 +1,88 @@ +version: 2.1 + +jobs: + test_suite: + docker: + - image: cimg/go:1.16 + steps: + - checkout + - run: + command: | + g++ --version + cd tests/ + g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test + export PATH=$(pwd):${PATH} + git clone --depth 1 --branch v1.3.0 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 + steps: + - checkout + - run: + command: | + g++ --version + cd tests/ + 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 + cd toml-test/tests/invalid + for f in $(ls ./*.toml); + do echo "==> ${f}"; + cat ${f}; + echo "---------------------------------------"; + ./check ${f} invalid; + if [ $? -ne 0 ] ; then + exit 1 + fi + echo "======================================="; + done + cd ../valid + for f in $(ls ./*.toml); + do echo "==> ${f}"; + cat ${f}; + echo "---------------------------------------"; + ./check ${f} valid; + if [ $? -ne 0 ] ; then + exit 1 + fi + echo "======================================="; + done + +workflows: + version: 2.1 + test: + jobs: + - test_suite + - test_serialization + - output_result diff --git a/subprojects/toml11/.clusterfuzzlite/Dockerfile b/subprojects/toml11/.clusterfuzzlite/Dockerfile new file mode 100644 index 00000000000..4206e0197cd --- /dev/null +++ b/subprojects/toml11/.clusterfuzzlite/Dockerfile @@ -0,0 +1,6 @@ +FROM gcr.io/oss-fuzz-base/base-builder +RUN apt-get update && apt-get install -y make autoconf automake libtool + +COPY . $SRC/toml11 +COPY .clusterfuzzlite/build.sh $SRC/build.sh +WORKDIR $SRC/toml11 diff --git a/subprojects/toml11/.clusterfuzzlite/README.md b/subprojects/toml11/.clusterfuzzlite/README.md new file mode 100644 index 00000000000..4ee95c0dd7c --- /dev/null +++ b/subprojects/toml11/.clusterfuzzlite/README.md @@ -0,0 +1,3 @@ +# ClusterFuzzLite set up + +This folder contains a fuzzing set for [ClusterFuzzLite](https://google.github.io/clusterfuzzlite). diff --git a/subprojects/toml11/.clusterfuzzlite/build.sh b/subprojects/toml11/.clusterfuzzlite/build.sh new file mode 100644 index 00000000000..c6d57fd457a --- /dev/null +++ b/subprojects/toml11/.clusterfuzzlite/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash -eu +# Copy fuzzer executable to $OUT/ +$CXX $CFLAGS $LIB_FUZZING_ENGINE \ + $SRC/toml11/.clusterfuzzlite/parse_fuzzer.cpp \ + -o $OUT/parse_fuzzer \ + -I$SRC/toml11/ diff --git a/subprojects/toml11/.clusterfuzzlite/parse_fuzzer.cpp b/subprojects/toml11/.clusterfuzzlite/parse_fuzzer.cpp new file mode 100644 index 00000000000..23bda4d10c3 --- /dev/null +++ b/subprojects/toml11/.clusterfuzzlite/parse_fuzzer.cpp @@ -0,0 +1,16 @@ + +#include + +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + std::string s(reinterpret_cast(data), size); + std::istringstream iss(s); + try { + const auto ref = toml::parse(iss); + } catch (...) { + } + + return 0; +} diff --git a/subprojects/toml11/.clusterfuzzlite/project.yaml b/subprojects/toml11/.clusterfuzzlite/project.yaml new file mode 100644 index 00000000000..b4788012b10 --- /dev/null +++ b/subprojects/toml11/.clusterfuzzlite/project.yaml @@ -0,0 +1 @@ +language: c++ diff --git a/subprojects/toml11/.editorconfig b/subprojects/toml11/.editorconfig new file mode 100644 index 00000000000..05bbdec3ee2 --- /dev/null +++ b/subprojects/toml11/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +indent_style = space + +[CMakeLists.txt] +indent_size = 4 + +[*.{c,h}*] +indent_size = 4 + +[*.{md,yml}] +indent_size = 2 diff --git a/subprojects/toml11/.github/workflows/cflite_pr.yml b/subprojects/toml11/.github/workflows/cflite_pr.yml new file mode 100644 index 00000000000..541a6cec939 --- /dev/null +++ b/subprojects/toml11/.github/workflows/cflite_pr.yml @@ -0,0 +1,30 @@ +name: ClusterFuzzLite PR fuzzing +on: + workflow_dispatch: + pull_request: + branches: [ master ] +permissions: read-all +jobs: + PR: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sanitizer: [address] + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + sanitizer: ${{ matrix.sanitizer }} + language: c++ + bad-build-check: false + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 240 + mode: 'code-change' + report-unreproducible-crashes: false + sanitizer: ${{ matrix.sanitizer }} diff --git a/subprojects/toml11/.github/workflows/main.yml b/subprojects/toml11/.github/workflows/main.yml new file mode 100644 index 00000000000..41263858471 --- /dev/null +++ b/subprojects/toml11/.github/workflows/main.yml @@ -0,0 +1,280 @@ +name: build + +on: [push, pull_request] + +jobs: + build-linux-gcc: + runs-on: Ubuntu-22.04 + strategy: + matrix: + compiler: ['g++-12', 'g++-11', 'g++-10', 'g++-9'] + standard: ['11', '14', '17', '20'] + unreleased: ['ON', 'OFF'] + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + - name: Install + run: | + sudo apt-add-repository ppa:ubuntu-toolchain-r/test + sudo apt-get update + sudo apt-get install libboost-test-dev + sudo apt-get install language-pack-fr # test serializer w/ locale + sudo apt-get install ${{ matrix.compiler }} + - name: Configure + run: | + mkdir build && cd build + cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + - name: Build + run: | + cd build && cmake --build . + - name: Test + run: | + cd build && ctest --output-on-failure + build-linux-clang: + runs-on: Ubuntu-22.04 + strategy: + matrix: + compiler: ['15', '14', '13', '12', '11'] + standard: ['11', '14', '17', '20'] + unreleased: ['ON', 'OFF'] + exclude: + - {compiler: '14', standard: '20'} # to avoid using gcc-13 libstdc++ + - {compiler: '13', standard: '20'} # with older clang + - {compiler: '12', standard: '20'} + - {compiler: '11', standard: '20'} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + - name: Install + run: | + sudo apt-add-repository ppa:ubuntu-toolchain-r/test + sudo apt-get update + sudo apt-get install libboost-test-dev + sudo apt-get install language-pack-fr # test serializer w/ locale + 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 }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + - name: Build + run: | + cd build && cmake --build . + - name: Test + run: | + cd build && ctest --output-on-failure + + build-linux-old-gcc: + runs-on: Ubuntu-20.04 + strategy: + matrix: + compiler: ['g++-8', 'g++-7'] + standard: ['11', '14', '17', '20'] + unreleased: ['ON', 'OFF'] + exclude: + - {compiler: 'g++-7', standard: '20'} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + - name: Install + run: | + sudo apt-add-repository ppa:ubuntu-toolchain-r/test + sudo apt-get update + sudo apt-get install libboost-test-dev + sudo apt-get install language-pack-fr # test serializer w/ locale + 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 -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + else + cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + fi + - name: Build + run: | + cd build && cmake --build . + - name: Test + run: | + cd build && ctest --output-on-failure + + build-linux-old-clang: + runs-on: Ubuntu-20.04 + strategy: + matrix: + compiler: ['10', '9', '8', '7', '6.0'] + standard: ['11', '14', '17', '20'] + unreleased: ['ON', 'OFF'] + exclude: + - {compiler: '6.0', standard: '20'} + - {compiler: '7', standard: '20'} + - {compiler: '8', standard: '20'} + - {compiler: '9', standard: '20'} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + - name: Install + run: | + sudo apt-add-repository ppa:ubuntu-toolchain-r/test + sudo apt-get update + sudo apt-get install libboost-test-dev + sudo apt-get install language-pack-fr # test serializer w/ locale + 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 }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + - name: Build + run: | + cd build && cmake --build . + - name: Test + run: | + cd build && ctest --output-on-failure + +# build-osx-13-arm64: +# runs-on: macos-13-arm64 +# strategy: +# matrix: +# standard: ['11', '14', '17', '20'] +# unreleased: ['ON', 'OFF'] +# steps: +# - name: Checkout +# uses: actions/checkout@v3 +# 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 }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} +# - name: Build +# run: | +# cd build && cmake --build . +# - name: Test +# run: | +# cd build && ctest --output-on-failure + + build-osx-13: + runs-on: macos-13 + strategy: + matrix: + standard: ['11', '14', '17', '20'] + unreleased: ['ON', 'OFF'] + steps: + - name: Checkout + uses: actions/checkout@v3 + 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 }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + - name: Build + run: | + cd build && cmake --build . + - name: Test + run: | + cd build && ctest --output-on-failure + + build-osx-12: + runs-on: macos-12 + strategy: + matrix: + standard: ['11', '14', '17', '20'] + unreleased: ['ON', 'OFF'] + steps: + - name: Checkout + uses: actions/checkout@v3 + 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 }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + - name: Build + run: | + cd build && cmake --build . + - name: Test + run: | + cd build && ctest --output-on-failure + + + build-osx-11: + runs-on: macos-11 + strategy: + matrix: + standard: ['11', '14', '17', '20'] + unreleased: ['ON', 'OFF'] + steps: + - name: Checkout + uses: actions/checkout@v3 + 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 }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + - name: Build + run: | + cd build && cmake --build . + - name: Test + run: | + cd build && ctest --output-on-failure + + build-windows-msvc: + runs-on: windows-2022 + strategy: + matrix: + standard: ['11', '14', '17', '20'] + config: ['Release', 'Debug'] + unreleased: ['ON', 'OFF'] + steps: + - name: Checkout + uses: actions/checkout@v3 + 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" -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }} + - name: Build + working-directory: ./build + run: | + cmake --build . --config "${{ matrix.config }}" + - name: Test + working-directory: ./build + run: | + 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 diff --git a/subprojects/toml11/.gitignore b/subprojects/toml11/.gitignore new file mode 100644 index 00000000000..a007feab071 --- /dev/null +++ b/subprojects/toml11/.gitignore @@ -0,0 +1 @@ +build/* diff --git a/subprojects/toml11/CMakeLists.txt b/subprojects/toml11/CMakeLists.txt new file mode 100644 index 00000000000..ddaa812d76e --- /dev/null +++ b/subprojects/toml11/CMakeLists.txt @@ -0,0 +1,121 @@ +cmake_minimum_required(VERSION 3.5) +enable_testing() + +project(toml11 VERSION 3.8.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) + +option(TOML11_USE_UNRELEASED_TOML_FEATURES + "use features in toml-lang/toml master while testing" OFF) + +include(CheckCXXCompilerFlag) +if("${CMAKE_VERSION}" VERSION_GREATER 3.1) + set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Boolean specifying whether compiler specific extensions are requested.") + if(NOT DEFINED CMAKE_CXX_STANDARD) + message(FATAL_ERROR "CMAKE_CXX_STANDARD is not defined. \ +The C++ standard whose features are requested to *build* all targets. \ +Remember that toml11 is a header only library that does NOT require compilation to use.") + 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) + CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) + CHECK_CXX_COMPILER_FLAG("-std=gnu++11" COMPILER_SUPPORTS_GNU11) + CHECK_CXX_COMPILER_FLAG("-std=gnu++0x" COMPILER_SUPPORTS_GNU0X) + if(COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + elseif(COMPILER_SUPPORTS_CXXOX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + elseif(COMPILER_SUPPORTS_GNU11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") + elseif(COMPILER_SUPPORTS_GNU0X) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") + else() + if(MSVC) + if(MSVC_VERSION LESS 1900) + message(SEND_ERROR "MSVC < 14.0 is not supported. Please update your compiler or use mingw") + endif() + else() + message(SEND_ERROR "The ${CMAKE_CXX_COMPILER} compiler lacks C++11 support. Use another compiler.") + endif() + endif() +endif() + +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 + $ + $ +) +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 () diff --git a/subprojects/toml11/README.md b/subprojects/toml11/README.md index 62b58630579..fd8b18e9e62 100644 --- a/subprojects/toml11/README.md +++ b/subprojects/toml11/README.md @@ -2,7 +2,6 @@ toml11 ====== [![Build Status on GitHub Actions](https://github.com/ToruNiina/toml11/workflows/build/badge.svg)](https://github.com/ToruNiina/toml11/actions) -[![Build Status on TravisCI](https://travis-ci.org/ToruNiina/toml11.svg?branch=master)](https://travis-ci.org/ToruNiina/toml11) [![Build status on Appveyor](https://ci.appveyor.com/api/projects/status/m2n08a926asvg5mg/branch/master?svg=true)](https://ci.appveyor.com/project/ToruNiina/toml11/branch/master) [![Build status on CircleCI](https://circleci.com/gh/ToruNiina/toml11/tree/master.svg?style=svg)](https://circleci.com/gh/ToruNiina/toml11/tree/master) [![Version](https://img.shields.io/github/release/ToruNiina/toml11.svg?style=flat)](https://github.com/ToruNiina/toml11/releases) @@ -116,6 +115,37 @@ it in your system by CMake. Note for MSVC: We recommend to set `/Zc:__cplusplus` to detect C++ version correctly. +### Example installation + +For local installation build & use the provided install target + +```bash +git clone https://github.com/ToruNiina/toml11.git +mkdir -p toml11/build +cd toml11/build +cmake .. -DCMAKE_CXX_STANDARD=11 +sudo make install +``` + +In case you want to create a `.deb` you can use `checkinstall`. +```bash +sudo checkinstall +[[ .. skipping for clarity ]] +********************************************************************** + + Done. The new package has been installed and saved to + + /home/user/toml11/build/build_20230728-1_amd64.deb + + You can remove it from your system anytime using: + + dpkg -r build + +********************************************************************** +``` + +You should get a package that you can install with `dpkg -i .deb` and remove with `dpkg -r .deb` + ## Decoding a toml file To parse a toml file, the only thing you have to do is @@ -478,11 +508,16 @@ elements. ```cpp const auto data = toml::parse("example.toml"); std::cout << "keys in the top-level table are the following: \n"; -for(const auto& [k, v] : data.as_table()) +for(const auto& kv : data.as_table()) +{ + std::cout << kv.first << '\n'; +} +for(const auto& [k, v] : data.as_table()) // or in C++17 { std::cout << k << '\n'; } + const auto& fruits = toml::find(data, "fruits"); for(const auto& v : fruits.as_array()) { @@ -837,7 +872,7 @@ const auto num = toml::find_or(data, "num", 42); It works recursively if you pass several keys for subtables. In that case, the last argument is considered to be the optional value. -All other arguments between `toml::value` and the optinoal value are considered as keys. +All other arguments between `toml::value` and the optional value are considered as keys. ```cpp // [fruit.physical] @@ -1169,7 +1204,7 @@ add a comma after the first element (like `[1,]`). "[[table]]"_toml; // This is a table that has an array of tables inside. "[[1]]"_toml; // This literal is ambiguous. - // Currently, it becomes a table that has array of table "1". + // Currently, it becomes an empty array of table named "1". "1 = [{}]"_toml; // This is a table that has an array of table named 1. "[[1,]]"_toml; // This is an array of arrays. "[[1],]"_toml; // ditto. @@ -1626,10 +1661,62 @@ std::cerr << toml::format_error("[error] value should be positive", hints, /*colorize = */ true) << std::endl; ``` -Note: It colorize `[error]` in red. That means that it detects `[error]` prefix +Note: It colorizes `[error]` in red. That means that it detects `[error]` prefix at the front of the error message. If there is no `[error]` prefix, `format_error` adds it to the error message. +Compared to the `TOML11_COLORIZE_ERROR_MESSAGE` macro that enables colorization +statically, toml11 provides `toml::color::enable` & `toml::color::disable` +functions to dynamically change the color mode. This feature overwrites +`TOML11_COLORIZE_ERROR_MESSAGE` and the `colorize` argument of +`toml::format_error` when you call `enable`. + +Note: If either `TOML11_COLORIZE_ERROR_MESSAGE` is defined or the `colorize` +argument is used, it takes precedence, meaning that `disable` won't work. +Accordingly, we highly recommend using only one of them. + +```cpp +toml::color::enable(); // enable colorization +toml::color::disable(); // disable colorization +``` + +If you use user-defined error message, you can manage the setting as follows: + +```cpp +toml::color::enable(); +std::cerr << toml::format_error("[error] value should be positive", + data.at("num"), "positive number required", + hints) << std::endl; // colorized + +toml::color::disable(); +std::cerr << toml::format_error("[error] value should be positive", + data.at("num"), "positive number required", + hints) << std::endl; // NOT colorized +``` + +Or you may use toml11 in your application like: + +```cpp +std::vector args(argv + 1, argv + argc); +auto result = std::find(args.begin(), args.end(), "--color"); +if (result != args.end()) { + toml::color::enable(); +} else { + toml::color::disable(); +} + +// use toml11 ... +``` + +## Opting out of the default `[error]` prefix + +toml11 prints error messages with the `[error]` prefix by default. +Defining `TOML11_NO_ERROR_PREFIX` will let toml11 omit the prefix regardless of colorized or not in case you would use a custom prefix, such as `Error:`. + +```cpp +#define TOML11_NO_ERROR_PREFIX +``` + ## Serializing TOML data toml11 enables you to serialize data into toml format. @@ -1764,16 +1851,13 @@ not capable of representing a Local Time independent from a specific day. ## Unreleased TOML features -Since TOML v1.0.0-rc.1 has been released, those features are now activated by -default. We no longer need to define `TOML11_USE_UNRELEASED_FEATURES`. +After TOML v1.0.0 has been released, some features are added to the main branch +of the TOML spec repository. (see: [CHANGELOG.md in toml-lang/toml repository](https://github.com/toml-lang/toml/blob/main/CHANGELOG.md)). + +The following list shows available "unreleased" features that can be activated +by defining a macro named `TOML11_USE_UNRELEASED_FEATURES`. -- Leading zeroes in exponent parts of floats are permitted. - - e.g. `1.0e+01`, `5e+05` - - [toml-lang/toml/PR/656](https://github.com/toml-lang/toml/pull/656) -- Allow raw tab characters in basic strings and multi-line basic strings. - - [toml-lang/toml/PR/627](https://github.com/toml-lang/toml/pull/627) -- Allow heterogeneous arrays - - [toml-lang/toml/PR/676](https://github.com/toml-lang/toml/pull/676) +- Add new `\e` shorthand for the escape character. ## Note about heterogeneous arrays @@ -1911,7 +1995,8 @@ I appreciate the help of the contributors who introduced the great feature to th - Fixed warnings on MSVC - Ivan Shynkarenka (@chronoxor) - Fixed Visual Studio 2019 warnings -- @khoitd1997 + - Fix compilation error in `` with MinGW +- Khoi Dinh Trinh (@khoitd1997) - Fixed warnings while type conversion - @KerstinKeller - Added installation script to CMake @@ -1922,6 +2007,7 @@ I appreciate the help of the contributors who introduced the great feature to th - Suppress warnings in Debug mode - OGAWA Kenichi (@kenichiice) - Suppress warnings on intel compiler + - Fix include path in README - Jordan Williams (@jwillikers) - Fixed clang range-loop-analysis warnings - Fixed feature test macro to suppress -Wundef @@ -1933,12 +2019,8 @@ I appreciate the help of the contributors who introduced the great feature to th - fix "Finding a value in an array" example in README - @maass-tv and @SeverinLeonhardt - Fix MSVC warning C4866 -- OGAWA KenIchi (@kenichiice) - - Fix include path in README - Mohammed Alyousef (@MoAlyousef) - Made testing optional in CMake -- Ivan Shynkarenka (@chronoxor) - - Fix compilation error in `` with MinGW - Alex Merry (@amerry) - Add missing include files - sneakypete81 (@sneakypete81) @@ -1955,12 +2037,46 @@ I appreciate the help of the contributors who introduced the great feature to th - Improve checking standard library feature availability check - Louis Marascio (@marascio) - Fix free-nonheap-object warning - +- Axel Huebl (@ax3l) + - Make installation optional if the library is embedded +- Ken Matsui (@ken-matsui) + - Support user-defined error message prefix + - Support dynamic color mode +- Giel van Schijndel (@muggenhor) + - Remove needless copy in `parse` function +- Lukáš Hrázký (@lukash) + - Add a `parse(FILE *)` interface and improve file-related error messages +- spiderman idog (@spiderman-idog) + - Fix typo in README +- Jajauma's GitHub (@Jajauma) + - Avoid possible lexer truncation warnings +- Moritz Klammler (@ctcmkl) + - Many patches in (#200) including: + - Improve CMake scripts, build process, and test file handling + - Detect error when `discard_comments` is accessed + - And more. +- Chris White (@cxw42) + - Fix address-sanitizer error when parsing literal strings having invalid UTF-8 characters + - Fix function name in error messages +- offa (@offa) + - Update checkout action to v3 + - Update Required CMake version + - Cleanup old CI settings +- Sergey Vidyuk (@VestniK) + - Fix for case when vector iterator is raw pointer +- Kfir Gollan (@kfirgollan) + - Add installation example with checkinstall and cmake +- Martin Tournoij (@arp242) + - Escape control characters in keys +- @DavidKorczynski + - Add fuzzing test based on ClusterFuzzLite +- Esonhugh Skyworship (@Esonhugh) + - Fix function signature of `strerror_r` on macos ## Licensing terms This product is licensed under the terms of the [MIT License](LICENSE). -- Copyright (c) 2017-2021 Toru Niina +- Copyright (c) 2017-2024 Toru Niina All rights reserved. diff --git a/subprojects/toml11/appveyor.yml b/subprojects/toml11/appveyor.yml new file mode 100644 index 00000000000..38715667d03 --- /dev/null +++ b/subprojects/toml11/appveyor.yml @@ -0,0 +1,25 @@ +version: "{build}" +os: Visual Studio 2015 + +environment: + matrix: + - generator: Visual Studio 14 2015 Win64 + - generator: Visual Studio 14 2015 + +configuration: + - Release + - Debug + +clone_depth: 10 +clone_folder: c:\toml11 + +build_script: + - cd C:\toml11 + - mkdir build + - cd build + - cmake -G"%generator%" -DCMAKE_CXX_STANDARD=11 -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 diff --git a/subprojects/toml11/cmake/toml11Config.cmake.in b/subprojects/toml11/cmake/toml11Config.cmake.in new file mode 100644 index 00000000000..edc73f69b48 --- /dev/null +++ b/subprojects/toml11/cmake/toml11Config.cmake.in @@ -0,0 +1,2 @@ +@PACKAGE_INIT@ +include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake") diff --git a/subprojects/toml11/tests/CMakeLists.txt b/subprojects/toml11/tests/CMakeLists.txt new file mode 100644 index 00000000000..332eaa803bf --- /dev/null +++ b/subprojects/toml11/tests/CMakeLists.txt @@ -0,0 +1,291 @@ +include(ExternalProject) + +set(TOML11_LANGSPEC_GIT_REPOSITORY "https://github.com/toml-lang/toml" CACHE STRING + "URL of the TOML language specification repository") + +set(TOML11_LANGSPEC_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/toml" CACHE FILEPATH + "directory for the TOML language specification tree") + +if(NOT EXISTS "${TOML11_LANGSPEC_SOURCE_DIR}/toml.abnf") + ExternalProject_Add(toml + SOURCE_DIR "${TOML11_LANGSPEC_SOURCE_DIR}" + GIT_REPOSITORY "${TOML11_LANGSPEC_GIT_REPOSITORY}" + GIT_TAG "v0.5.0" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "") +endif() + +set(TEST_NAMES + test_datetime + test_string + test_utility + test_result + test_traits + test_value + test_lex_boolean + test_lex_integer + test_lex_floating + test_lex_datetime + test_lex_string + test_lex_key_comment + test_parse_boolean + test_parse_integer + test_parse_floating + test_parse_string + test_parse_datetime + test_parse_array + test_parse_table + test_parse_inline_table + test_parse_key + test_parse_table_key + test_literals + test_comments + test_get + test_get_or + test_find + test_find_or + test_find_or_recursive + test_expect + test_parse_file + test_serialize_file + test_parse_unicode + test_error_detection + test_format_error + test_extended_conversions +) + +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) + +include(CheckCXXSourceCompiles) + +# check which standard library implementation is used. If libstdc++ is used, +# it will fail to compile. It compiles if libc++ is used. +check_cxx_source_compiles(" +#include +#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 . +# 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) + +find_package(Boost COMPONENTS unit_test_framework REQUIRED) + +set(PREVIOUSLY_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}") +set(PREVIOUSLY_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") + +list(APPEND CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIRS}) +list(APPEND CMAKE_REQUIRED_LIBRARIES ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) + +check_cxx_source_compiles(" +#define BOOST_TEST_MODULE \"dummy\" +#undef BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_LIB +#include +BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); } +" TOML11_WITH_BOOST_TEST_HEADER) + +check_cxx_source_compiles(" +#define BOOST_TEST_MODULE \"dummy\" +#undef BOOST_TEST_DYN_LINK +#undef BOOST_TEST_NO_LIB +#include +BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); } +" TOML11_WITH_BOOST_TEST_STATIC) + +check_cxx_source_compiles(" +#define BOOST_TEST_MODULE \"dummy\" +#define BOOST_TEST_DYN_LINK +#undef BOOST_TEST_NO_LIB +#include +BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); } +" TOML11_WITH_BOOST_TEST_DYNAMIC) + +set(CMAKE_REQUIRED_INCLUDES "${PREVIOUSLY_REQUIRED_INCLUDES}") +set(CMAKE_REQUIRED_LIBRARIES "${PREVIOUSLY_REQUIRED_LIBRARIES}") + +unset(PREVIOUSLY_REQUIRED_INCLUDES) +unset(PREVIOUSLY_REQUIRED_LIBRARIES) + +if(TOML11_WITH_BOOST_TEST_DYNAMIC) + add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST -DBOOST_TEST_DYN_LINK) +elseif(TOML11_WITH_BOOST_TEST_STATIC) + add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST) +elseif(TOML11_WITH_BOOST_TEST_HEADER) + add_definitions(-DBOOST_TEST_NO_LIB) +else() + message(FATAL_ERROR "Neither the Boost.Test static or shared library nor the header-only version seem to be usable.") +endif() + +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() + +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) + # conversion from 'double' to 'unsigned int', possible loss of data + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244") + # conversion from 'int' to 'unsigned int', signed/unsigned mismatch + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4365") + # layout of class may have changed from a previous version of the compiler + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4371") + # enumerator in switch of enum is not explicitly handled by a case label + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4061") + # unreferenced inline function has been removed + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4514") + # constructor is not implicitly called + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4582") + # destructor is not implicitly called + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4583") + # pragma warning: there is no warning number + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4619") + # default constructor was implicitly defined as deleted + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4623") + # copy constructor was implicitly defined as deleted + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4625") + # assignment operator was implicitly defined as deleted + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4626") + # move assignment operator was implicitly defined as deleted + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4627") + # is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4668") + # function not inlined + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4710") + # function selected for automatic inlining + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4711") + # bytes padding added after data member + 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() + +set(TEST_ENVIRON "TOMLDIR=${TOML11_LANGSPEC_SOURCE_DIR}") +if(WIN32) + # Set the PATH to be able to find Boost DLL + STRING(REPLACE ";" "\\;" PATH_STRING "$ENV{PATH}") + list(APPEND TEST_ENVIRON "PATH=${PATH_STRING}\;${Boost_LIBRARY_DIRS}") +endif() + +foreach(TEST_NAME ${TEST_NAMES}) + add_executable(${TEST_NAME} ${TEST_NAME}.cpp) + target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11) + target_include_directories(${TEST_NAME} SYSTEM PRIVATE ${Boost_INCLUDE_DIRS}) + target_compile_definitions(${TEST_NAME} PRIVATE "BOOST_TEST_MODULE=\"${TEST_NAME}\"") + + # to compile tests with ... + 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}) + + 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_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${TEST_ENVIRON}") +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() + diff --git a/subprojects/toml11/tests/check.cpp b/subprojects/toml11/tests/check.cpp new file mode 100644 index 00000000000..bf67775c646 --- /dev/null +++ b/subprojects/toml11/tests/check.cpp @@ -0,0 +1,42 @@ +#include + +#include +#include + +int main(int argc, char **argv) +{ + if(argc != 3) + { + std::cerr << "usage: ./check [filename] [valid|invalid]" << std::endl; + return 1; + } + + const std::string file_kind(argv[2]); + + try + { + const auto data = toml::parse(argv[1]); + std::cout << std::setprecision(16) << std::setw(80) << data; + if(file_kind == "valid") + { + return 0; + } + else + { + return 1; + } + } + catch(const toml::syntax_error& err) + { + std::cout << "what(): " << err.what() << std::endl; + if(file_kind == "invalid") + { + return 0; + } + else + { + return 1; + } + } + return 127; +} diff --git a/subprojects/toml11/tests/check_serialization.cpp b/subprojects/toml11/tests/check_serialization.cpp new file mode 100644 index 00000000000..e97d51b1b4c --- /dev/null +++ b/subprojects/toml11/tests/check_serialization.cpp @@ -0,0 +1,114 @@ +#include + +#include +#include + +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(serialized, "nan")) && + !std::signbit (toml::find(serialized, "nan")) && + std::isnan (toml::find(serialized, "nan_plus")) && + !std::signbit (toml::find(serialized, "nan_plus")) && + std::isnan (toml::find(serialized, "nan_neg")) && + std::signbit (toml::find(serialized, "nan_neg")) && + !std::isnan (toml::find(serialized, "infinity")) && + !std::isfinite(toml::find(serialized, "infinity")) && + !std::signbit (toml::find(serialized, "infinity")) && + !std::isnan (toml::find(serialized, "infinity_plus")) && + !std::isfinite(toml::find(serialized, "infinity_plus")) && + !std::signbit (toml::find(serialized, "infinity_plus")) && + !std::isnan (toml::find(serialized, "infinity_neg")) && + !std::isfinite(toml::find(serialized, "infinity_neg")) && + std::signbit (toml::find(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(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(serialized, "nan")) && + !std::signbit (toml::find(serialized, "nan")) && + std::isnan (toml::find(serialized, "nan_plus")) && + !std::signbit (toml::find(serialized, "nan_plus")) && + std::isnan (toml::find(serialized, "nan_neg")) && + std::signbit (toml::find(serialized, "nan_neg")) && + !std::isnan (toml::find(serialized, "infinity")) && + !std::isfinite(toml::find(serialized, "infinity")) && + !std::signbit (toml::find(serialized, "infinity")) && + !std::isnan (toml::find(serialized, "infinity_plus")) && + !std::isfinite(toml::find(serialized, "infinity_plus")) && + !std::signbit (toml::find(serialized, "infinity_plus")) && + !std::isnan (toml::find(serialized, "infinity_neg")) && + !std::isfinite(toml::find(serialized, "infinity_neg")) && + std::signbit (toml::find(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; +} diff --git a/subprojects/toml11/tests/check_toml_test.cpp b/subprojects/toml11/tests/check_toml_test.cpp new file mode 100644 index 00000000000..51404c9e29a --- /dev/null +++ b/subprojects/toml11/tests/check_toml_test.cpp @@ -0,0 +1,139 @@ +#include + +#include +#include + +struct json_serializer +{ + void operator()(toml::boolean v) + { + std::cout << "{\"type\":\"bool\",\"value\":\"" << toml::value(v) << "\"}"; + return ; + } + void operator()(toml::integer v) + { + std::cout << "{\"type\":\"integer\",\"value\":\"" << toml::value(v) << "\"}"; + return ; + } + 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::quiet_NaN(); + } + std::cout << "{\"type\":\"float\",\"value\":\"" << toml::value(v) << "\"}"; + return ; + } + void operator()(const toml::string& v) + { + // 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. + toml::serializer ser(std::numeric_limits::max()); + std::cout << "{\"type\":\"string\",\"value\":" + << ser(v.str) << "}"; + return ; + } + void operator()(const toml::local_time& v) + { + std::cout << "{\"type\":\"time-local\",\"value\":\"" << toml::value(v) << "\"}"; + return ; + } + void operator()(const toml::local_date& v) + { + std::cout << "{\"type\":\"date-local\",\"value\":\"" << toml::value(v) << "\"}"; + return ; + } + void operator()(const toml::local_datetime& v) + { + std::cout << "{\"type\":\"datetime-local\",\"value\":\"" << toml::value(v) << "\"}"; + return ; + } + void operator()(const toml::offset_datetime& v) + { + std::cout << "{\"type\":\"datetime\",\"value\":\"" << toml::value(v) << "\"}"; + return ; + } + void operator()(const toml::array& v) + { + if(!v.empty() && v.front().is_table()) + { + std::cout << '['; + bool is_first = true; + for(const auto& elem : v) + { + if(!is_first) {std::cout << ", ";} + is_first = false; + toml::visit(*this, elem); + } + std::cout << ']'; + } + else + { +// std::cout << "{\"type\":\"array\",\"value\":["; + std::cout << "["; + bool is_first = true; + for(const auto& elem : v) + { + if(!is_first) {std::cout << ", ";} + is_first = false; + toml::visit(*this, elem); + } + std::cout << "]"; + } + return ; + } + void operator()(const toml::table& v) + { + std::cout << '{'; + bool is_first = true; + for(const auto& elem : v) + { + if(!is_first) {std::cout << ", ";} + is_first = false; + 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 ; + } +}; + +int main() +{ + try + { + std::vector buf; + std::cin.peek(); + while(!std::cin.eof()) + { + buf.push_back(std::cin.get()); + std::cin.peek(); + } + std::string bufstr(buf.begin(), buf.end()); + + std::istringstream ss(bufstr); + + const auto data = toml::parse(ss); + std::cout << std::setprecision(std::numeric_limits::max_digits10); + toml::visit(json_serializer(), data); + return 0; + } + catch(const toml::syntax_error& err) + { + std::cout << "what(): " << err.what() << std::endl; + return 1; + } +} diff --git a/subprojects/toml11/tests/test_comments.cpp b/subprojects/toml11/tests/test_comments.cpp new file mode 100644 index 00000000000..2d2b6a67816 --- /dev/null +++ b/subprojects/toml11/tests/test_comments.cpp @@ -0,0 +1,545 @@ +#include + +#include "unit_test.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(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(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(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(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(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(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(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(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; + { + 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(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( + 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 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 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> 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 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; + { + 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; + { + 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"); + } + +} diff --git a/subprojects/toml11/tests/test_datetime.cpp b/subprojects/toml11/tests/test_datetime.cpp new file mode 100644 index 00000000000..bbbcc42843b --- /dev/null +++ b/subprojects/toml11/tests/test_datetime.cpp @@ -0,0 +1,117 @@ +#include + +#include "unit_test.hpp" + +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_TEST(date == date1); + + const std::chrono::system_clock::time_point tp(date); + const toml::local_date date2(tp); + BOOST_TEST(date == date2); + + const toml::local_date date3(2017, toml::month_t::Dec, 31); + BOOST_TEST(date > date3); + + std::ostringstream oss; + oss << date; + 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_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_TEST(dur.count() == ns.count()); + + const toml::local_time time3(12, 15, 45); + BOOST_TEST(time > time3); + + { + std::ostringstream oss; + oss << time; + 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_TEST(oss.str() == std::string("12:30:45.123456")); + } +} + +BOOST_AUTO_TEST_CASE(test_time_offset) +{ + const toml::time_offset time(9, 30); + const toml::time_offset time1(time); + 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_TEST(dur.count() == m.count()); + + const toml::time_offset time2(9, 0); + BOOST_TEST(time2 < time); + + std::ostringstream oss; + oss << time; + BOOST_TEST(oss.str() == std::string("+09:30")); +} + +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_TEST(dt == dt1); + + const std::chrono::system_clock::time_point tp(dt); + const toml::local_datetime dt2(tp); + BOOST_TEST(dt == dt2); + + std::ostringstream oss; + oss << dt; + BOOST_TEST(oss.str() == std::string("2018-01-01T12:30:45")); +} + +BOOST_AUTO_TEST_CASE(test_offset_datetime) +{ + const toml::offset_datetime dt(toml::local_date(2018, toml::month_t::Jan, 1), + toml::local_time(12, 30, 45), + toml::time_offset(9, 30)); + const toml::offset_datetime dt1(dt); + 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); + const bool tp_same = (tp1 == tp2); + BOOST_TEST(tp_same); + + { + std::ostringstream oss; + oss << dt; + BOOST_TEST(oss.str() == std::string("2018-01-01T12:30:45+09:30")); + } + { + const toml::offset_datetime dt3( + toml::local_date(2018, toml::month_t::Jan, 1), + toml::local_time(12, 30, 45), + toml::time_offset(0, 0)); + std::ostringstream oss; + oss << dt3; + BOOST_TEST(oss.str() == std::string("2018-01-01T12:30:45Z")); + } +} diff --git a/subprojects/toml11/tests/test_error_detection.cpp b/subprojects/toml11/tests/test_error_detection.cpp new file mode 100644 index 00000000000..5e39ef6cc2e --- /dev/null +++ b/subprojects/toml11/tests/test_error_detection.cpp @@ -0,0 +1,97 @@ +#include + +#include "unit_test.hpp" + +#include +#include + +BOOST_AUTO_TEST_CASE(test_detect_empty_key) +{ + std::istringstream stream(std::string("= \"value\"")); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); +} + +BOOST_AUTO_TEST_CASE(test_detect_missing_value) +{ + std::istringstream stream(std::string("a =")); + 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\"")); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); +} + +BOOST_AUTO_TEST_CASE(test_detect_duplicate_table) +{ + std::istringstream stream(std::string( + "[table]\n" + "a = 42\n" + "[table]\n" + "b = 42\n" + )); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); +} + +BOOST_AUTO_TEST_CASE(test_detect_conflict_array_table) +{ + std::istringstream stream(std::string( + "[[table]]\n" + "a = 42\n" + "[table]\n" + "b = 42\n" + )); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); +} + +BOOST_AUTO_TEST_CASE(test_detect_conflict_table_array) +{ + std::istringstream stream(std::string( + "[table]\n" + "a = 42\n" + "[[table]]\n" + "b = 42\n" + )); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); +} + +BOOST_AUTO_TEST_CASE(test_detect_duplicate_value) +{ + std::istringstream stream(std::string( + "a = 1\n" + "a = 2\n" + )); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); +} + +BOOST_AUTO_TEST_CASE(test_detect_conflicting_value) +{ + std::istringstream stream(std::string( + "a.b = 1\n" + "a.b.c = 2\n" + )); + 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" + )); + 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) +{ + std::istringstream stream(std::string( + "a = [{b = 1}]\n" + "[[a]]\n" + "b = 2\n" + )); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); +} diff --git a/subprojects/toml11/tests/test_expect.cpp b/subprojects/toml11/tests/test_expect.cpp new file mode 100644 index 00000000000..308d4fba752 --- /dev/null +++ b/subprojects/toml11/tests/test_expect.cpp @@ -0,0 +1,26 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include +#include + +BOOST_AUTO_TEST_CASE(test_expect) +{ + { + toml::value v1(42); + toml::value v2(3.14); + const auto v1_or_0 = toml::expect(v1).unwrap_or(0); + const auto v2_or_0 = toml::expect(v2).unwrap_or(0); + BOOST_TEST(42 == v1_or_0); + BOOST_TEST( 0 == v2_or_0); + + const auto v1_or_none = toml::expect(v1).map([](int i){return std::to_string(i);}).unwrap_or(std::string("none")); + const auto v2_or_none = toml::expect(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); + } +} diff --git a/subprojects/toml11/tests/test_extended_conversions.cpp b/subprojects/toml11/tests/test_extended_conversions.cpp new file mode 100644 index 00000000000..1b21264e5b8 --- /dev/null +++ b/subprojects/toml11/tests/test_extended_conversions.cpp @@ -0,0 +1,627 @@ +#include + +#include "unit_test.hpp" + +#include +#include + +namespace extlib +{ +struct foo +{ + int a; + std::string b; +}; +struct bar +{ + int a; + std::string b; + + void from_toml(const toml::value& v) + { + this->a = toml::find(v, "a"); + this->b = toml::find(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 +{ + // via constructor + explicit foobar(const toml::value& v) + : a(toml::find(v, "a")), b(toml::find(v, "b")) + {} + int a; + std::string b; +}; +} // extlib + +namespace toml +{ +template<> +struct from +{ + static extlib::foo from_toml(const toml::value& v) + { + return extlib::foo{toml::find(v, "a"), toml::find(v, "b")}; + } +}; + +template<> +struct into +{ + static toml::value into_toml(const extlib::foo& f) + { + return toml::value{{"a", f.a}, {"b", f.b}}; + } +}; + +template<> +struct from +{ + static extlib::baz from_toml(const toml::value& v) + { + return extlib::baz{toml::find(v, "a"), toml::find(v, "b")}; + } +}; + +template<> +struct into +{ + 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 class M, template class A> + void from_toml(const toml::basic_value& v) + { + this->a = toml::find(v, "a"); + this->b = toml::find(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 class M, template class A> + explicit foobar(const toml::basic_value& v) + : a(toml::find(v, "a")), b(toml::find(v, "b")) + {} + int a; + std::string b; +}; + +} // extlib2 + +namespace toml +{ +template<> +struct from +{ + template class M, template class A> + static extlib2::foo from_toml(const toml::basic_value& v) + { + return extlib2::foo{toml::find(v, "a"), toml::find(v, "b")}; + } +}; + +template<> +struct into +{ + static toml::table into_toml(const extlib2::foo& f) + { + return toml::table{{"a", f.a}, {"b", f.b}}; + } +}; + +template<> +struct from +{ + template class M, template class A> + static extlib2::baz from_toml(const toml::basic_value& v) + { + return extlib2::baz{toml::find(v, "a"), toml::find(v, "b")}; + } +}; + +template<> +struct into +{ + static toml::basic_value + into_toml(const extlib2::qux& f) + { + return toml::basic_value{ + {"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 auto foo = toml::get(v); + BOOST_TEST(foo.a == 42); + BOOST_TEST(foo.b == "baz"); + + const toml::value v2(foo); + + BOOST_TEST(v == v2); + } + + { + const toml::value v{{"a", 42}, {"b", "baz"}}; + + const auto foo = toml::get(v); + BOOST_TEST(foo.a == 42); + BOOST_TEST(foo.b == "baz"); + + const toml::value v2(foo); + BOOST_TEST(v == v2); + } + + { + const toml::basic_value + v{{"a", 42}, {"b", "baz"}}; + + const auto foo = toml::get(v); + BOOST_TEST(foo.a == 42); + BOOST_TEST(foo.b == "baz"); + + const toml::basic_value + v2(foo); + + BOOST_TEST(v == v2); + } +} + +BOOST_AUTO_TEST_CASE(test_conversion_by_specialization) +{ + { + const toml::value v{{"a", 42}, {"b", "baz"}}; + + const auto bar = toml::get(v); + BOOST_TEST(bar.a == 42); + BOOST_TEST(bar.b == "baz"); + + const toml::value v2(bar); + + BOOST_TEST(v == v2); + } + { + const toml::value v{{"a", 42}, {"b", "baz"}}; + + const auto bar = toml::get(v); + BOOST_TEST(bar.a == 42); + BOOST_TEST(bar.b == "baz"); + + const toml::value v2(bar); + + BOOST_TEST(v == v2); + } + { + const toml::basic_value + v{{"a", 42}, {"b", "baz"}}; + + const auto bar = toml::get(v); + BOOST_TEST(bar.a == 42); + BOOST_TEST(bar.b == "baz"); + + const toml::basic_value + 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(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(v, "a") == 42); + BOOST_TEST(toml::find(v, "b") == "qux"); + } + + { + const toml::basic_value v{ + {"a", 42}, {"b", "baz"} + }; + + const auto baz = toml::get(v); + BOOST_TEST(baz.a == 42); + BOOST_TEST(baz.b == "baz"); + } + { + const extlib::qux q{42, "qux"}; + const toml::basic_value v(q); + + BOOST_TEST(toml::find(v, "a") == 42); + BOOST_TEST(toml::find(v, "b") == "qux"); + } +} + +BOOST_AUTO_TEST_CASE(test_conversion_via_constructor) +{ + { + const toml::value v{{"a", 42}, {"b", "foobar"}}; + + const auto foobar = toml::get(v); + BOOST_TEST(foobar.a == 42); + BOOST_TEST(foobar.b == "foobar"); + } + + { + const toml::basic_value v{ + {"a", 42}, {"b", "foobar"} + }; + + const auto foobar = toml::get(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 auto foos = toml::get>(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>(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>(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>(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 + 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>(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>(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>(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>(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 + 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>(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>(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>(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 + 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>(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"); + } + +} + +// =========================================================================== + +#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(v); + BOOST_TEST(foo.a == 42); + BOOST_TEST(foo.b == "baz"); + + const toml::value v2(foo); + BOOST_TEST(v2 == v); + } + { + const toml::basic_value v{ + {"a", 42}, {"b", "baz"} + }; + + const auto foo = toml::get(v); + BOOST_TEST(foo.a == 42); + BOOST_TEST(foo.b == "baz"); + + const toml::basic_value 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(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 v{ + {"a", 42}, + {"b", "bar.b"}, + {"f", toml::table{{"a", 42}, {"b", "foo.b"}}} + }; + + const auto bar = toml::get(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 v2(bar); + BOOST_TEST(v2 == v); + } +} +#endif // TOML11_WITHOUT_DEFINE_NON_INTRUSIVE diff --git a/subprojects/toml11/tests/test_find.cpp b/subprojects/toml11/tests/test_find.cpp new file mode 100644 index 00000000000..944b8e82a7f --- /dev/null +++ b/subprojects/toml11/tests/test_find.cpp @@ -0,0 +1,827 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include +#include +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L +#include +#endif + +using test_value_types = std::tuple< + toml::basic_value, + toml::basic_value, + toml::basic_value, + toml::basic_value + >; + +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(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(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(v, "different_key"), + std::out_of_range); + } + { + // the positive control. + const toml::value v{{"key", 42}}; + BOOST_TEST(42 == toml::find(v, "key")); + } + + // ----------------------------------------------------------------------- + // reference version + { + // value is not a table + toml::value v(true); + BOOST_CHECK_THROW(toml::find(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(v, "key"), toml::type_error); + } + { + // the value corresponding to the key is not found + toml::value v{{"key", 42}}; + BOOST_CHECK_THROW(toml::find(v, "different_key"), + std::out_of_range); + } + { + // the positive control. + toml::value v{{"key", 42}}; + BOOST_TEST(42 == toml::find(v, "key")); + } + + // ----------------------------------------------------------------------- + // move version + + { + // value is not a table + toml::value v(true); + BOOST_CHECK_THROW(toml::find(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(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(std::move(v), "different_key"), + std::out_of_range); + } + { + // the positive control. + toml::value v{{"key", 42}}; + BOOST_TEST(42 == toml::find(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(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(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(v, 6), std::out_of_range); + } + { + // the positive control. + const toml::value v{1, 2, 3, 4, 5}; + BOOST_TEST(3 == toml::find(v, 2)); + } + + // ----------------------------------------------------------------------- + // non-const reference version + { + // value is not an array + toml::value v(true); + BOOST_CHECK_THROW(toml::find(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(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(v, 6), std::out_of_range); + } + { + // the positive control. + toml::value v{1, 2, 3, 4, 5}; + BOOST_TEST(3 == toml::find(v, 2)); + } + + // ----------------------------------------------------------------------- + // move version + { + // value is not an array + toml::value v(true); + BOOST_CHECK_THROW(toml::find(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(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(std::move(v), 6), std::out_of_range); + } + { + // the positive control. + toml::value v{1, 2, 3, 4, 5}; + BOOST_TEST(3 == toml::find(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(v, "a", "b", "c", "d")); + + // reference that can be used to modify the content + auto& num = toml::find(v, "a", "b", "c", "d"); + num = 54; + BOOST_TEST(54 == toml::find(v, "a", "b", "c", "d")); + + const std::string a("a"), b("b"), c("c"), d("d"); + auto& num2 = toml::find(v, a, b, c, d); + num2 = 42; + BOOST_TEST(42 == toml::find(v, a, b, c, d)); + + auto num3 = toml::find(v, a, "b", c, "d"); + BOOST_TEST(42 == num3); + + auto num4 = toml::find(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(v, 0, 0)); + BOOST_TEST("of" == toml::find(v, 0, 1)); + BOOST_TEST("string" == toml::find(v, 0, 2)); + + BOOST_TEST(1 == toml::find(v, 1, 0, 0)); + BOOST_TEST(2 == toml::find(v, 1, 0, 1)); + BOOST_TEST(3 == toml::find(v, 1, 0, 2)); + + BOOST_TEST(3.14 == toml::find(v, 1, 1, 0)); + BOOST_TEST(2.71 == toml::find(v, 1, 1, 1)); + + // reference that can be used to modify the content + auto& num = toml::find(v, 1, 0, 2); + num = 42; + BOOST_TEST( 1 == toml::find(v, 1, 0, 0)); + BOOST_TEST( 2 == toml::find(v, 1, 0, 1)); + BOOST_TEST(42 == toml::find(v, 1, 0, 2)); + + // move value + auto num2 = toml::find(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(v, "array", 0, 0)); + BOOST_TEST(2 == toml::find(v, "array", 0, 1)); + BOOST_TEST(3 == toml::find(v, "array", 0, 2)); + + BOOST_TEST("bar" == toml::find(v, "array", 1, 0, "foo")); + BOOST_TEST("qux" == toml::find(v, "array", 1, 0, "baz")); + + BOOST_TEST(3.14 == toml::find(v, "array", 1, 1, "pi")); + BOOST_TEST(2.71 == toml::find(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(v, ar, 1, 1, "pi")); + BOOST_TEST(3.14 == toml::find(v, ar, 1, 1, pi)); + BOOST_TEST(3.14 == toml::find(v, ar, 1, 1, pi_c)); + + BOOST_TEST(3.14 == toml::find(v, ar_c, 1, 1, "pi")); + BOOST_TEST(3.14 == toml::find(v, ar_c, 1, 1, pi)); + BOOST_TEST(3.14 == toml::find(v, ar_c, 1, 1, pi_c)); + + BOOST_TEST(3.14 == toml::find(v, "array", 1, 1, pi)); + BOOST_TEST(3.14 == toml::find(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(v, "key")); + + toml::find(v, "key") = false; + BOOST_TEST(false == toml::find(v, "key")); + + const auto moved = toml::find(std::move(v), "key"); + BOOST_TEST(false == moved); + } + { + value_type v{{"key", 42}}; + BOOST_TEST(toml::integer(42) == toml::find(v, "key")); + + toml::find(v, "key") = 54; + BOOST_TEST(toml::integer(54) == toml::find(v, "key")); + + const auto moved = toml::find(std::move(v), "key"); + BOOST_TEST(toml::integer(54) == moved); + } + { + value_type v{{"key", 3.14}}; + BOOST_TEST(toml::floating(3.14) == toml::find(v, "key")); + + toml::find(v, "key") = 2.71; + BOOST_TEST(toml::floating(2.71) == toml::find(v, "key")); + + const auto moved = toml::find(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(v, "key")); + + toml::find(v, "key").str += "bar"; + BOOST_TEST(toml::string("foobar", toml::string_t::basic) == + toml::find(v, "key")); + + const auto moved = toml::find(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(v, "key")); + + toml::find(v, "key").str += "bar"; + BOOST_TEST(toml::string("foobar", toml::string_t::literal) == + toml::find(v, "key")); + + const auto moved = toml::find(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(v, "key")); + + toml::find(v, "key").year = 2017; + d.year = 2017; + BOOST_CHECK(d == toml::find(v, "key")); + + const auto moved = toml::find(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(v, "key")); + + toml::find(v, "key").hour = 9; + t.hour = 9; + BOOST_CHECK(t == toml::find(v, "key")); + + const auto moved = toml::find(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(v, "key")); + + toml::find(v, "key").date.year = 2017; + dt.date.year = 2017; + BOOST_CHECK(dt == toml::find(v, "key")); + + const auto moved = toml::find(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(v, "key")); + + toml::find(v, "key").date.year = 2017; + dt.date.year = 2017; + BOOST_CHECK(dt == toml::find(v, "key")); + + const auto moved = toml::find(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(v, "key")); + BOOST_CHECK(result1); + + toml::find(v, "key").push_back(value_type(123)); + vec.push_back(value_type(123)); + + const bool result2 = (vec == toml::find(v, "key")); + BOOST_CHECK(result2); + + const auto moved = toml::find(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(v, "key")); + BOOST_CHECK(result1); + + toml::find(v, "key")["key3"] = value_type(123); + tab["key3"] = value_type(123); + const bool result2 = (tab == toml::find(v, "key")); + BOOST_CHECK(result2); + + const auto moved = toml::find(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(v, "key")); + BOOST_TEST(short(42) == toml::find(v, "key")); + BOOST_TEST(char(42) == toml::find(v, "key")); + BOOST_TEST(unsigned(42) == toml::find(v, "key")); + BOOST_TEST(long(42) == toml::find(v, "key")); + BOOST_TEST(std::int64_t(42) == toml::find(v, "key")); + BOOST_TEST(std::uint64_t(42) == toml::find(v, "key")); + BOOST_TEST(std::int16_t(42) == toml::find(v, "key")); + BOOST_TEST(std::uint16_t(42) == toml::find(v, "key")); + BOOST_TEST(std::uint16_t(42) == toml::find(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(ref) == toml::find(v, "key")); + BOOST_TEST( ref == toml::find(v, "key")); + BOOST_TEST(static_cast(ref) == toml::find(v, "key")); + BOOST_TEST(static_cast(ref) == toml::find(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(v, "key")); + toml::find(v, "key") += "bar"; + BOOST_TEST("foobar" == toml::find(v, "key")); + } + { + value_type v{{"key", toml::string("foo", toml::string_t::literal)}}; + BOOST_TEST("foo" == toml::find(v, "key")); + toml::find(v, "key") += "bar"; + BOOST_TEST("foobar" == toml::find(v, "key")); + } + { + value_type v{{"key", toml::string("foo", toml::string_t::literal)}}; + const auto moved = toml::find(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(v, "key")); + } + { + value_type v{{"key", toml::string("foo", toml::string_t::literal)}}; + BOOST_TEST("foo" == toml::find(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 vec = toml::find>(v, "key"); + const std::list lst = toml::find>(v, "key"); + const std::deque deq = toml::find>(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::const_iterator iter = lst.begin(); + BOOST_TEST(static_cast(42) == *(iter++)); + BOOST_TEST(static_cast(54) == *(iter++)); + BOOST_TEST(static_cast(69) == *(iter++)); + BOOST_TEST(static_cast(72) == *(iter++)); + + BOOST_TEST(static_cast(42) == deq.at(0)); + BOOST_TEST(static_cast(54) == deq.at(1)); + BOOST_TEST(static_cast(69) == deq.at(2)); + BOOST_TEST(static_cast(72) == deq.at(3)); + + std::array ary = toml::find>(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 tpl = + toml::find>(v, "key"); + BOOST_TEST( 42 == std::get<0>(tpl)); + BOOST_TEST(static_cast(54) == std::get<1>(tpl)); + BOOST_TEST(static_cast(69) == std::get<2>(tpl)); + BOOST_TEST(static_cast(72) == std::get<3>(tpl)); + + value_type p{{"key", {3.14, 2.71}}}; + std::pair pr = toml::find >(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 vec = toml::find>(std::move(v1), "key"); + const std::list lst = toml::find>(std::move(v2), "key"); + const std::deque deq = toml::find>(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::const_iterator iter = lst.begin(); + BOOST_TEST(static_cast(42) == *(iter++)); + BOOST_TEST(static_cast(54) == *(iter++)); + BOOST_TEST(static_cast(69) == *(iter++)); + BOOST_TEST(static_cast(72) == *(iter++)); + + BOOST_TEST(static_cast(42) == deq.at(0)); + BOOST_TEST(static_cast(54) == deq.at(1)); + BOOST_TEST(static_cast(69) == deq.at(2)); + BOOST_TEST(static_cast(72) == deq.at(3)); + + std::array ary = toml::find>(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 tpl = + toml::find>(std::move(v5), "key"); + BOOST_TEST( 42 == std::get<0>(tpl)); + BOOST_TEST(static_cast(54) == std::get<1>(tpl)); + BOOST_TEST(static_cast(69) == std::get<2>(tpl)); + BOOST_TEST(static_cast(72) == std::get<3>(tpl)); + + value_type p{{"key", {3.14, 2.71}}}; + std::pair pr = toml::find >(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> p = + toml::find, std::vector>>(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> t = + toml::find, std::vector>>(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> p = + toml::find, std::vector>>(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> t = + toml::find, std::vector>>(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>(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::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(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::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(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::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(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::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(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(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::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); + } +} diff --git a/subprojects/toml11/tests/test_find_or.cpp b/subprojects/toml11/tests/test_find_or.cpp new file mode 100644 index 00000000000..8348f2f18a5 --- /dev/null +++ b/subprojects/toml11/tests/test_find_or.cpp @@ -0,0 +1,538 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include +#include +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L +#include +#endif + +using test_value_types = std::tuple< + toml::basic_value, + toml::basic_value, + toml::basic_value, + toml::basic_value +>; + +namespace test +{ +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::vector& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::deque& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::list& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const std::map& v) +{ + os << "[ "; + for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const std::unordered_map& 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(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(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(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(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(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; + { + 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(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"}}} + }; + 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(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"); + } +} diff --git a/subprojects/toml11/tests/test_find_or_recursive.cpp b/subprojects/toml11/tests/test_find_or_recursive.cpp new file mode 100644 index 00000000000..1f2f4800646 --- /dev/null +++ b/subprojects/toml11/tests/test_find_or_recursive.cpp @@ -0,0 +1,393 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include +#include +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L +#include +#endif + +using test_value_types = std::tuple< + toml::basic_value, + toml::basic_value, + toml::basic_value, + toml::basic_value +>; + +namespace test +{ +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::vector& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::deque& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::list& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const std::map& v) +{ + os << "[ "; + for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const std::unordered_map& 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(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(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(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(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))); + } +} diff --git a/subprojects/toml11/tests/test_format_error.cpp b/subprojects/toml11/tests/test_format_error.cpp new file mode 100644 index 00000000000..c00f8455190 --- /dev/null +++ b/subprojects/toml11/tests/test_format_error.cpp @@ -0,0 +1,72 @@ +#include + +#include "unit_test.hpp" + +#include + +// to check it successfully compiles. it does not check the formatted string. + +BOOST_AUTO_TEST_CASE(test_1_value) +{ + toml::value val(42); + + { + const std::string pretty_error = + toml::format_error("[error] test error", val, "this is a value"); + std::cout << pretty_error << std::endl; + } + + { + const std::string pretty_error = + toml::format_error("[error] test error", val, "this is a value", + {"this is a hint"}); + std::cout << pretty_error << std::endl; + } +} + +BOOST_AUTO_TEST_CASE(test_2_values) +{ + toml::value v1(42); + toml::value v2(3.14); + { + const std::string pretty_error = + toml::format_error("[error] test error with two values", + v1, "this is the answer", + v2, "this is the pi"); + std::cout << pretty_error << std::endl; + } + + { + const std::string pretty_error = + toml::format_error("[error] test error with two values", + v1, "this is the answer", + v2, "this is the pi", + {"hint"}); + std::cout << pretty_error << std::endl; + } +} + +BOOST_AUTO_TEST_CASE(test_3_values) +{ + toml::value v1(42); + toml::value v2(3.14); + toml::value v3("foo"); + { + const std::string pretty_error = + toml::format_error("[error] test error with two values", + v1, "this is the answer", + v2, "this is the pi", + v3, "this is a meta-syntactic variable"); + std::cout << pretty_error << std::endl; + } + + { + const std::string pretty_error = + toml::format_error("[error] test error with two values", + v1, "this is the answer", + v2, "this is the pi", + v3, "this is a meta-syntactic variable", + {"hint 1", "hint 2"}); + std::cout << pretty_error << std::endl; + } +} diff --git a/subprojects/toml11/tests/test_get.cpp b/subprojects/toml11/tests/test_get.cpp new file mode 100644 index 00000000000..4a16e34827a --- /dev/null +++ b/subprojects/toml11/tests/test_get.cpp @@ -0,0 +1,505 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include +#include +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L +#include +#endif + +using test_value_types = std::tuple< + toml::basic_value, + toml::basic_value, + toml::basic_value, + toml::basic_value +>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types) +{ + { + value_type v(true); + BOOST_TEST(true == toml::get(v)); + + toml::get(v) = false; + BOOST_TEST(false == toml::get(v)); + + toml::boolean x = toml::get(std::move(v)); + BOOST_TEST(false == x); + } + { + value_type v(42); + BOOST_TEST(toml::integer(42) == toml::get(v)); + + toml::get(v) = 54; + BOOST_TEST(toml::integer(54) == toml::get(v)); + + toml::integer x = toml::get(std::move(v)); + BOOST_TEST(toml::integer(54) == x); + } + { + value_type v(3.14); + BOOST_TEST(toml::floating(3.14) == toml::get(v)); + + toml::get(v) = 2.71; + BOOST_TEST(toml::floating(2.71) == toml::get(v)); + + toml::floating x = toml::get(std::move(v)); + BOOST_TEST(toml::floating(2.71) == x); + } + { + value_type v("foo"); + BOOST_TEST(toml::string("foo", toml::string_t::basic) == + toml::get(v)); + + toml::get(v).str += "bar"; + BOOST_TEST(toml::string("foobar", toml::string_t::basic) == + toml::get(v)); + + toml::string x = toml::get(std::move(v)); + BOOST_TEST(toml::string("foobar") == x); + } + { + value_type v("foo", toml::string_t::literal); + BOOST_TEST(toml::string("foo", toml::string_t::literal) == + toml::get(v)); + + toml::get(v).str += "bar"; + BOOST_TEST(toml::string("foobar", toml::string_t::literal) == + toml::get(v)); + + toml::string x = toml::get(std::move(v)); + BOOST_TEST(toml::string("foobar", toml::string_t::literal) == x); + } + { + toml::local_date d(2018, toml::month_t::Apr, 22); + value_type v(d); + BOOST_TEST(d == toml::get(v)); + + toml::get(v).year = 2017; + d.year = 2017; + BOOST_TEST(d == toml::get(v)); + + toml::local_date x = toml::get(std::move(v)); + BOOST_TEST(d == x); + } + { + toml::local_time t(12, 30, 45); + value_type v(t); + BOOST_TEST(t == toml::get(v)); + + toml::get(v).hour = 9; + t.hour = 9; + BOOST_TEST(t == toml::get(v)); + + toml::local_time x = toml::get(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)); + value_type v(dt); + BOOST_TEST(dt == toml::get(v)); + + toml::get(v).date.year = 2017; + dt.date.year = 2017; + BOOST_TEST(dt == toml::get(v)); + + toml::local_datetime x = toml::get(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)); + value_type v(dt); + BOOST_TEST(dt == toml::get(v)); + + toml::get(v).date.year = 2017; + dt.date.year = 2017; + BOOST_TEST(dt == toml::get(v)); + + toml::offset_datetime x = toml::get(std::move(v)); + BOOST_TEST(dt == x); + } + { + 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(v)); + + toml::get(v).push_back(value_type(123)); + vec.push_back(value_type(123)); + BOOST_TEST(vec == toml::get(v)); + + array_type x = toml::get(std::move(v)); + BOOST_TEST(vec == x); + } + { + 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(v)); + + toml::get(v)["key3"] = value_type(123); + tab["key3"] = value_type(123); + BOOST_TEST(tab == toml::get(v)); + + table_type x = toml::get(std::move(v)); + BOOST_TEST(tab == x); + } + { + value_type v1(42); + BOOST_TEST(v1 == toml::get(v1)); + + value_type v2(54); + toml::get(v1) = v2; + BOOST_TEST(v2 == toml::get(v1)); + + value_type x = toml::get(std::move(v1)); + BOOST_TEST(v2 == x); + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_integer_type, value_type, test_value_types) +{ + { + value_type v(42); + BOOST_TEST(int(42) == toml::get(v)); + BOOST_TEST(short(42) == toml::get(v)); + BOOST_TEST(char(42) == toml::get(v)); + BOOST_TEST(unsigned(42) == toml::get(v)); + BOOST_TEST(long(42) == toml::get(v)); + BOOST_TEST(std::int64_t(42) == toml::get(v)); + BOOST_TEST(std::uint64_t(42) == toml::get(v)); + BOOST_TEST(std::int16_t(42) == toml::get(v)); + BOOST_TEST(std::uint16_t(42) == toml::get(v)); + + BOOST_TEST(std::uint16_t(42) == toml::get(std::move(v))); + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_floating_type, value_type, test_value_types) +{ + { + value_type v(3.14); + const double ref(3.14); + BOOST_TEST(static_cast(ref) == toml::get(v)); + BOOST_TEST( ref == toml::get(v)); + BOOST_TEST(static_cast(ref) == toml::get(v)); + BOOST_TEST(static_cast(ref) == toml::get(std::move(v))); + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_string_type, value_type, test_value_types) +{ + { + value_type v("foo", toml::string_t::basic); + BOOST_TEST("foo" == toml::get(v)); + toml::get(v) += "bar"; + BOOST_TEST("foobar" == toml::get(v)); + + const auto x = toml::get(std::move(v)); + BOOST_TEST("foobar" == x); + } + { + value_type v("foo", toml::string_t::literal); + BOOST_TEST("foo" == toml::get(v)); + toml::get(v) += "bar"; + BOOST_TEST("foobar" == toml::get(v)); + + const auto x = toml::get(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(v)); + } + { + value_type v("foo", toml::string_t::literal); + BOOST_TEST("foo" == toml::get(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 vec = toml::get>(v); + const std::list lst = toml::get>(v); + const std::deque deq = toml::get>(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::const_iterator iter = lst.begin(); + BOOST_TEST(static_cast(42) == *(iter++)); + BOOST_TEST(static_cast(54) == *(iter++)); + BOOST_TEST(static_cast(69) == *(iter++)); + BOOST_TEST(static_cast(72) == *(iter++)); + + BOOST_TEST(static_cast(42) == deq.at(0)); + BOOST_TEST(static_cast(54) == deq.at(1)); + BOOST_TEST(static_cast(69) == deq.at(2)); + BOOST_TEST(static_cast(72) == deq.at(3)); + + std::array ary = toml::get>(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 tpl = + toml::get>(v); + BOOST_TEST( 42 == std::get<0>(tpl)); + BOOST_TEST(static_cast(54) == std::get<1>(tpl)); + BOOST_TEST(static_cast(69) == std::get<2>(tpl)); + BOOST_TEST(static_cast(72) == std::get<3>(tpl)); + + const value_type p{3.14, 2.71}; + std::pair pr = toml::get >(p); + BOOST_TEST(3.14 == pr.first); + BOOST_TEST(2.71 == pr.second); + } + + { + value_type v{42, 54, 69, 72}; + const std::vector vec = toml::get>(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 deq = toml::get>(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 lst = toml::get>(std::move(v)); + std::list::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 ary = toml::get>(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 tpl = + toml::get>(std::move(v)); + BOOST_TEST( 42 == std::get<0>(tpl)); + BOOST_TEST(static_cast(54) == std::get<1>(tpl)); + BOOST_TEST(static_cast(69) == std::get<2>(tpl)); + BOOST_TEST(static_cast(72) == std::get<3>(tpl)); + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array_of_array, value_type, test_value_types) +{ + { + const value_type v1{42, 54, 69, 72}; + const value_type v2{"foo", "bar", "baz"}; + const value_type v{v1, v2}; + + std::pair, std::vector> p = + toml::get, std::vector>>(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"); + + std::tuple, std::vector> t = + toml::get, std::vector>>(v); + + 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"); + } + { + const value_type v1{42, 54, 69, 72}; + const value_type v2{"foo", "bar", "baz"}; + value_type v{v1, v2}; + + std::pair, std::vector> p = + toml::get, std::vector>>(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_TEMPLATE(test_get_toml_table, value_type, test_value_types) +{ + { + const value_type v1{ + {"key1", 1}, + {"key2", 2}, + {"key3", 3}, + {"key4", 4} + }; + + const auto v = toml::get>(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::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); + } + +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_local_date, value_type, test_value_types) +{ + value_type v1(toml::local_date{2018, toml::month_t::Apr, 1}); + const auto date = std::chrono::system_clock::to_time_t( + toml::get(v1)); + + 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_get_toml_local_time, value_type, test_value_types) +{ + value_type v1(toml::local_time{12, 30, 45}); + const auto time = toml::get(v1); + const bool result = time == std::chrono::hours(12) + + std::chrono::minutes(30) + + std::chrono::seconds(45); + BOOST_TEST(result); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_local_datetime, value_type, test_value_types) +{ + value_type v1(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::get(v1)); + 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(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::get(v1); + 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_TEST(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(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::get(v1); + 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_TEST(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); + } +} diff --git a/subprojects/toml11/tests/test_get_or.cpp b/subprojects/toml11/tests/test_get_or.cpp new file mode 100644 index 00000000000..9ecb36e9ccb --- /dev/null +++ b/subprojects/toml11/tests/test_get_or.cpp @@ -0,0 +1,449 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include +#include +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L +#include +#endif + +using test_value_types = std::tuple< + toml::basic_value, + toml::basic_value, + toml::basic_value, + toml::basic_value +>; + +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< +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::vector& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::deque& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::list& v) +{ + os << "[ "; + for(const auto& i : v) {os << i << ' ';} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const std::map& v) +{ + os << "[ "; + for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";} + os << ']'; + return os; +} +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const std::unordered_map& 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(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(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(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(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(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)); + } + +} diff --git a/subprojects/toml11/tests/test_lex_aux.hpp b/subprojects/toml11/tests/test_lex_aux.hpp new file mode 100644 index 00000000000..77f2a9b5189 --- /dev/null +++ b/subprojects/toml11/tests/test_lex_aux.hpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include + +#define TOML11_TEST_LEX_ACCEPT(lxr, tkn, expct) \ +do { \ + const std::string token (tkn); \ + const std::string expected(expct); \ + toml::detail::location loc("test", token); \ + const auto result = lxr::invoke(loc); \ + BOOST_TEST(result.is_ok()); \ + if(result.is_ok()){ \ + const auto region = result.unwrap(); \ + BOOST_TEST(region.str() == expected); \ + BOOST_TEST(region.str().size() == expected.size()); \ + BOOST_TEST(static_cast(std::distance( \ + loc.begin(), loc.iter())) == region.size()); \ + } else { \ + std::cerr << "lexer failed with input `"; \ + std::cerr << token << "`. expected `" << expected << "`\n"; \ + std::cerr << "reason: " << result.unwrap_err() << '\n'; \ + } \ +} while(false); \ +/**/ + +#define TOML11_TEST_LEX_REJECT(lxr, tkn) \ +do { \ + const std::string token (tkn); \ + toml::detail::location loc("test", token); \ + const auto result = lxr::invoke(loc); \ + BOOST_TEST(result.is_err()); \ + const bool loc_same = (loc.begin() == loc.iter()); \ + BOOST_TEST(loc_same); \ +} while(false); /**/ diff --git a/subprojects/toml11/tests/test_lex_boolean.cpp b/subprojects/toml11/tests/test_lex_boolean.cpp new file mode 100644 index 00000000000..deecffefe29 --- /dev/null +++ b/subprojects/toml11/tests/test_lex_boolean.cpp @@ -0,0 +1,23 @@ +#include + +#include "unit_test.hpp" +#include "test_lex_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_correct) +{ + TOML11_TEST_LEX_ACCEPT(lex_boolean, "true", "true"); + TOML11_TEST_LEX_ACCEPT(lex_boolean, "false", "false"); + TOML11_TEST_LEX_ACCEPT(lex_boolean, "true # trailing", "true"); + TOML11_TEST_LEX_ACCEPT(lex_boolean, "false # trailing", "false"); +} + +BOOST_AUTO_TEST_CASE(test_invalid) +{ + TOML11_TEST_LEX_REJECT(lex_boolean, "TRUE"); + TOML11_TEST_LEX_REJECT(lex_boolean, "FALSE"); + TOML11_TEST_LEX_REJECT(lex_boolean, "True"); + TOML11_TEST_LEX_REJECT(lex_boolean, "False"); +} diff --git a/subprojects/toml11/tests/test_lex_datetime.cpp b/subprojects/toml11/tests/test_lex_datetime.cpp new file mode 100644 index 00000000000..8e33d384c4c --- /dev/null +++ b/subprojects/toml11/tests/test_lex_datetime.cpp @@ -0,0 +1,57 @@ +#include + +#include "unit_test.hpp" +#include "test_lex_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_offset_datetime) +{ + TOML11_TEST_LEX_ACCEPT(lex_offset_date_time, + "1979-05-27T07:32:00Z", + "1979-05-27T07:32:00Z"); + TOML11_TEST_LEX_ACCEPT(lex_offset_date_time, + "1979-05-27T07:32:00-07:00", + "1979-05-27T07:32:00-07:00"); + TOML11_TEST_LEX_ACCEPT(lex_offset_date_time, + "1979-05-27T07:32:00.999999-07:00", + "1979-05-27T07:32:00.999999-07:00"); + + TOML11_TEST_LEX_ACCEPT(lex_offset_date_time, + "1979-05-27 07:32:00Z", + "1979-05-27 07:32:00Z"); + TOML11_TEST_LEX_ACCEPT(lex_offset_date_time, + "1979-05-27 07:32:00-07:00", + "1979-05-27 07:32:00-07:00"); + TOML11_TEST_LEX_ACCEPT(lex_offset_date_time, + "1979-05-27 07:32:00.999999-07:00", + "1979-05-27 07:32:00.999999-07:00"); +} + +BOOST_AUTO_TEST_CASE(test_local_datetime) +{ + TOML11_TEST_LEX_ACCEPT(lex_local_date_time, + "1979-05-27T07:32:00", + "1979-05-27T07:32:00"); + TOML11_TEST_LEX_ACCEPT(lex_local_date_time, + "1979-05-27T07:32:00.999999", + "1979-05-27T07:32:00.999999"); + + TOML11_TEST_LEX_ACCEPT(lex_local_date_time, + "1979-05-27 07:32:00", + "1979-05-27 07:32:00"); + TOML11_TEST_LEX_ACCEPT(lex_local_date_time, + "1979-05-27 07:32:00.999999", + "1979-05-27 07:32:00.999999"); +} + +BOOST_AUTO_TEST_CASE(test_local_date) +{ + TOML11_TEST_LEX_ACCEPT(lex_local_date, "1979-05-27", "1979-05-27"); +} +BOOST_AUTO_TEST_CASE(test_local_time) +{ + TOML11_TEST_LEX_ACCEPT(lex_local_time, "07:32:00", "07:32:00"); + TOML11_TEST_LEX_ACCEPT(lex_local_time, "07:32:00.999999", "07:32:00.999999"); +} diff --git a/subprojects/toml11/tests/test_lex_floating.cpp b/subprojects/toml11/tests/test_lex_floating.cpp new file mode 100644 index 00000000000..8c9cd2008d0 --- /dev/null +++ b/subprojects/toml11/tests/test_lex_floating.cpp @@ -0,0 +1,107 @@ +#include + +#include "unit_test.hpp" +#include "test_lex_aux.hpp" + +#include + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_fractional_valid) +{ + TOML11_TEST_LEX_ACCEPT(lex_float, "1.0", "1.0" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "0.1", "0.1" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "0.001", "0.001" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "0.100", "0.100" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "+3.14", "+3.14" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "-3.14", "-3.14" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "3.1415_9265_3589", "3.1415_9265_3589" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "+3.1415_9265_3589", "+3.1415_9265_3589"); + TOML11_TEST_LEX_ACCEPT(lex_float, "-3.1415_9265_3589", "-3.1415_9265_3589"); + TOML11_TEST_LEX_ACCEPT(lex_float, "123_456.789", "123_456.789" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "+123_456.789", "+123_456.789" ); + TOML11_TEST_LEX_ACCEPT(lex_float, "-123_456.789", "-123_456.789" ); +} + +BOOST_AUTO_TEST_CASE(test_fractional_invalid) +{ + TOML11_TEST_LEX_REJECT(lex_float, "0."); + TOML11_TEST_LEX_REJECT(lex_float, ".0"); + TOML11_TEST_LEX_REJECT(lex_float, "01.0"); + TOML11_TEST_LEX_REJECT(lex_float, "3,14"); + TOML11_TEST_LEX_REJECT(lex_float, "+-1.0"); + TOML11_TEST_LEX_REJECT(lex_float, "1._0"); +} + +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, "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) +{ + // accept partially + TOML11_TEST_LEX_ACCEPT(lex_float, "1e1E0", "1e1"); + TOML11_TEST_LEX_ACCEPT(lex_float, "1E1e0", "1E1"); +} + +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_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) +{ + TOML11_TEST_LEX_ACCEPT(lex_float, "inf", "inf"); + TOML11_TEST_LEX_ACCEPT(lex_float, "+inf", "+inf"); + TOML11_TEST_LEX_ACCEPT(lex_float, "-inf", "-inf"); + + TOML11_TEST_LEX_ACCEPT(lex_float, "nan", "nan"); + TOML11_TEST_LEX_ACCEPT(lex_float, "+nan", "+nan"); + TOML11_TEST_LEX_ACCEPT(lex_float, "-nan", "-nan"); +} diff --git a/subprojects/toml11/tests/test_lex_integer.cpp b/subprojects/toml11/tests/test_lex_integer.cpp new file mode 100644 index 00000000000..50b9178fe5b --- /dev/null +++ b/subprojects/toml11/tests/test_lex_integer.cpp @@ -0,0 +1,101 @@ +#include + +#include "unit_test.hpp" +#include "test_lex_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_decimal_correct) +{ + TOML11_TEST_LEX_ACCEPT(lex_integer, "1234", "1234" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "+1234", "+1234" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "-1234", "-1234" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0", "0" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "1_2_3_4", "1_2_3_4" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "+1_2_3_4", "+1_2_3_4" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "-1_2_3_4", "-1_2_3_4" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "123_456_789", "123_456_789"); +} + +BOOST_AUTO_TEST_CASE(test_decimal_invalid) +{ + TOML11_TEST_LEX_ACCEPT(lex_integer, "123+45", "123"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "123-45", "123"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "01234", "0"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "123__45", "123"); + + TOML11_TEST_LEX_REJECT(lex_integer, "_1234"); +} + +BOOST_AUTO_TEST_CASE(test_hex_correct) +{ + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xDEADBEEF", "0xDEADBEEF" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xdeadbeef", "0xdeadbeef" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xDEADbeef", "0xDEADbeef" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xDEAD_BEEF", "0xDEAD_BEEF"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xdead_beef", "0xdead_beef"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xdead_BEEF", "0xdead_BEEF"); + + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xFF", "0xFF" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0x00FF", "0x00FF" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0x0000FF", "0x0000FF"); +} + +BOOST_AUTO_TEST_CASE(test_hex_invalid) +{ + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xAPPLE", "0xA"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xDEAD+BEEF", "0xDEAD"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0xDEAD__BEEF", "0xDEAD"); + + TOML11_TEST_LEX_REJECT(lex_hex_int, "0x_DEADBEEF"); + TOML11_TEST_LEX_REJECT(lex_hex_int, "0x+DEADBEEF"); + TOML11_TEST_LEX_REJECT(lex_hex_int, "-0xFF" ); + TOML11_TEST_LEX_REJECT(lex_hex_int, "-0x00FF" ); + + TOML11_TEST_LEX_ACCEPT(lex_integer, "0x_DEADBEEF", "0" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0x+DEADBEEF", "0" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "-0xFF" , "-0" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "-0x00FF" , "-0" ); +} + +BOOST_AUTO_TEST_CASE(test_oct_correct) +{ + TOML11_TEST_LEX_ACCEPT(lex_integer, "0o777", "0o777" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0o7_7_7", "0o7_7_7"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0o007", "0o007" ); + +} + +BOOST_AUTO_TEST_CASE(test_oct_invalid) +{ + TOML11_TEST_LEX_ACCEPT(lex_integer, "0o77+7", "0o77"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0o1__0", "0o1"); + + TOML11_TEST_LEX_REJECT(lex_oct_int, "0o800" ); + TOML11_TEST_LEX_REJECT(lex_oct_int, "-0o777"); + TOML11_TEST_LEX_REJECT(lex_oct_int, "0o+777"); + TOML11_TEST_LEX_REJECT(lex_oct_int, "0o_10" ); + + TOML11_TEST_LEX_ACCEPT(lex_integer, "0o800", "0"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "-0o777", "-0"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0o+777", "0"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0o_10", "0"); +} + +BOOST_AUTO_TEST_CASE(test_bin_correct) +{ + TOML11_TEST_LEX_ACCEPT(lex_integer, "0b10000", "0b10000" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0b010000", "0b010000" ); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0b01_00_00", "0b01_00_00"); + TOML11_TEST_LEX_ACCEPT(lex_integer, "0b111111", "0b111111" ); +} + +BOOST_AUTO_TEST_CASE(test_bin_invalid) +{ + TOML11_TEST_LEX_ACCEPT(lex_bin_int, "0b11__11", "0b11"); + TOML11_TEST_LEX_ACCEPT(lex_bin_int, "0b11+11" , "0b11"); + + TOML11_TEST_LEX_REJECT(lex_bin_int, "-0b10000"); + TOML11_TEST_LEX_REJECT(lex_bin_int, "0b_1111" ); +} diff --git a/subprojects/toml11/tests/test_lex_key_comment.cpp b/subprojects/toml11/tests/test_lex_key_comment.cpp new file mode 100644 index 00000000000..da123a42ea0 --- /dev/null +++ b/subprojects/toml11/tests/test_lex_key_comment.cpp @@ -0,0 +1,52 @@ +#include + +#include "unit_test.hpp" +#include "test_lex_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_bare_key) +{ + TOML11_TEST_LEX_ACCEPT(lex_key, "barekey", "barekey"); + TOML11_TEST_LEX_ACCEPT(lex_key, "bare-key", "bare-key"); + TOML11_TEST_LEX_ACCEPT(lex_key, "bare_key", "bare_key"); + TOML11_TEST_LEX_ACCEPT(lex_key, "1234", "1234"); +} + +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\""); + + // 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\""); + + TOML11_TEST_LEX_ACCEPT(lex_key, "'key2'", "'key2'"); + TOML11_TEST_LEX_ACCEPT(lex_key, "'quoted \"value\"'", "'quoted \"value\"'"); +} + +BOOST_AUTO_TEST_CASE(test_dotted_key) +{ + TOML11_TEST_LEX_ACCEPT(lex_key, "physical.color", "physical.color"); + TOML11_TEST_LEX_ACCEPT(lex_key, "physical.shape", "physical.shape"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x.y", "x.y"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x . y", "x . y"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x.y.z", "x.y.z"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x. y .z", "x. y .z"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x .y. z", "x .y. z"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x . y . z", "x . y . z"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x.y.z.w", "x.y.z.w"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x. y .z. w", "x. y .z. w"); + TOML11_TEST_LEX_ACCEPT(lex_key, "x . y . z . w", "x . y . z . w"); + TOML11_TEST_LEX_ACCEPT(lex_key, "site.\"google.com\"", "site.\"google.com\""); +} + +BOOST_AUTO_TEST_CASE(test_comment) +{ + TOML11_TEST_LEX_ACCEPT(lex_comment, "# hoge", "# hoge"); + TOML11_TEST_LEX_ACCEPT(lex_comment, "# \n", "# "); + TOML11_TEST_LEX_ACCEPT(lex_comment, "# \r\n", "# "); + TOML11_TEST_LEX_ACCEPT(lex_comment, "# # \n", "# # "); +} diff --git a/subprojects/toml11/tests/test_lex_string.cpp b/subprojects/toml11/tests/test_lex_string.cpp new file mode 100644 index 00000000000..f8f24243830 --- /dev/null +++ b/subprojects/toml11/tests/test_lex_string.cpp @@ -0,0 +1,108 @@ +#include + +#include "unit_test.hpp" +#include "test_lex_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_string) +{ + TOML11_TEST_LEX_ACCEPT(lex_string, + "\"The quick brown fox jumps over the lazy dog\"", + "\"The quick brown fox jumps over the lazy dog\""); + TOML11_TEST_LEX_ACCEPT(lex_string, + "\'The quick brown fox jumps over the lazy dog\'", + "\'The quick brown fox jumps over the lazy dog\'"); + TOML11_TEST_LEX_ACCEPT(lex_ml_basic_string, + "\"\"\"The quick brown fox \\\njumps over the lazy dog\"\"\"", + "\"\"\"The quick brown fox \\\njumps over the lazy dog\"\"\""); + TOML11_TEST_LEX_ACCEPT(lex_ml_literal_string, + "'''The quick brown fox \njumps over the lazy dog'''", + "'''The quick brown fox \njumps over the lazy dog'''"); +} + +BOOST_AUTO_TEST_CASE(test_basic_string) +{ + TOML11_TEST_LEX_ACCEPT(lex_string, + "\"GitHub Cofounder & CEO\\nLikes tater tots and beer.\"", + "\"GitHub Cofounder & CEO\\nLikes tater tots and beer.\""); + TOML11_TEST_LEX_ACCEPT(lex_string, + "\"192.168.1.1\"", + "\"192.168.1.1\""); + + TOML11_TEST_LEX_ACCEPT(lex_string, + "\"\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 - #\"", + "\"You'll hate me after this - #\""); + TOML11_TEST_LEX_ACCEPT(lex_string, + "\" And when \\\"'s are in the string, along with # \\\"\"", + "\" And when \\\"'s are in the string, along with # \\\"\""); +} + +BOOST_AUTO_TEST_CASE(test_ml_basic_string) +{ + TOML11_TEST_LEX_ACCEPT(lex_string, + "\"\"\"\nThe quick brown \\\n\n fox jumps over \\\n the lazy dog.\"\"\"", + "\"\"\"\nThe quick brown \\\n\n fox jumps over \\\n the lazy dog.\"\"\""); + 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) +{ + TOML11_TEST_LEX_ACCEPT(lex_string, + "'C:\\Users\\nodejs\\templates'", + "'C:\\Users\\nodejs\\templates'"); + TOML11_TEST_LEX_ACCEPT(lex_string, + "'\\\\ServerX\\admin$\\system32\\'", + "'\\\\ServerX\\admin$\\system32\\'"); + TOML11_TEST_LEX_ACCEPT(lex_string, + "'Tom \"Dubs\" Preston-Werner'", + "'Tom \"Dubs\" Preston-Werner'"); + TOML11_TEST_LEX_ACCEPT(lex_string, + "'<\\i\\c*\\s*>'", + "'<\\i\\c*\\s*>'"); +} + +BOOST_AUTO_TEST_CASE(test_ml_literal_string) +{ + TOML11_TEST_LEX_ACCEPT(lex_string, + "'''I [dw]on't need \\d{2} apples'''", + "'''I [dw]on't need \\d{2} apples'''"); + 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.''''"); +} diff --git a/subprojects/toml11/tests/test_literals.cpp b/subprojects/toml11/tests/test_literals.cpp new file mode 100644 index 00000000000..de81f39b17f --- /dev/null +++ b/subprojects/toml11/tests/test_literals.cpp @@ -0,0 +1,336 @@ +#include + +#include "unit_test.hpp" + +#include + +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(v1)); + BOOST_TEST(!toml::get(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(v1) == 123456); + BOOST_TEST(toml::get(v2) == 2); + BOOST_TEST(toml::get(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(v1) == 3.1415, boost::test_tools::tolerance(0.00001)); + BOOST_TEST(toml::get(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(v1) == "foo"); + BOOST_TEST(toml::get(v2) == "foo"); + BOOST_TEST(toml::get(v3) == "foo"); + BOOST_TEST(toml::get(v4) == "foo"); + } + { + { + const toml::value v1 = R"([1,2,3])"_toml; + BOOST_TEST(v1.is_array()); + const bool result = (toml::get>(v1) == std::vector{1,2,3}); + BOOST_TEST(result); + } + { + const toml::value v2 = R"([1,])"_toml; + BOOST_TEST(v2.is_array()); + const bool result = (toml::get>(v2) == std::vector{1}); + BOOST_TEST(result); + } + { + const toml::value v3 = R"([[1,]])"_toml; + BOOST_TEST(v3.is_array()); + const bool result = (toml::get>(toml::get(v3).front()) == std::vector{1}); + BOOST_TEST(result); + } + { + const toml::value v4 = R"([[1],])"_toml; + BOOST_TEST(v4.is_array()); + const bool result = (toml::get>(toml::get(v4).front()) == std::vector{1}); + BOOST_TEST(result); + } + } + { + const toml::value v1 = R"({a = 42})"_toml; + + BOOST_TEST(v1.is_table()); + const bool result = toml::get>(v1) == + std::map{{"a", 42}}; + BOOST_TEST(result); + } + { + const toml::value v1 = "1979-05-27"_toml; + + BOOST_TEST(v1.is_local_date()); + BOOST_TEST(toml::get(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(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(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(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"( + 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 = u8R"( + 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 = 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_u8_literal) +{ + using namespace toml::literals::toml_literals; + + { + const toml::value v1 = u8"true"_toml; + const toml::value v2 = u8"false"_toml; + + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v2.is_boolean()); + BOOST_TEST(toml::get(v1)); + BOOST_TEST(!toml::get(v2)); + } + { + const toml::value v1 = u8"123_456"_toml; + const toml::value v2 = u8"0b0010"_toml; + const toml::value v3 = u8"0xDEADBEEF"_toml; + + BOOST_TEST(v1.is_integer()); + BOOST_TEST(v2.is_integer()); + BOOST_TEST(v3.is_integer()); + BOOST_TEST(toml::get(v1) == 123456); + BOOST_TEST(toml::get(v2) == 2); + BOOST_TEST(toml::get(v3) == 0xDEADBEEF); + } + { + const toml::value v1 = u8"3.1415"_toml; + const toml::value v2 = u8"6.02e+23"_toml; + + BOOST_TEST(v1.is_floating()); + BOOST_TEST(v2.is_floating()); + BOOST_TEST(toml::get(v1) == 3.1415, boost::test_tools::tolerance(0.00001)); + BOOST_TEST(toml::get(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_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(v1) == "foo"); + BOOST_TEST(toml::get(v2) == "foo"); + BOOST_TEST(toml::get(v3) == "foo"); + BOOST_TEST(toml::get(v4) == "foo"); + BOOST_TEST(toml::get(v5) == "\xE3\x81\xB2\xE3\x82\x89\xE3\x81\x8C\xE3\x81\xAA"); + } + { + { + const toml::value v1 = u8R"([1,2,3])"_toml; + BOOST_TEST(v1.is_array()); + const bool result = (toml::get>(v1) == std::vector{1,2,3}); + BOOST_TEST(result); + } + { + const toml::value v2 = u8R"([1,])"_toml; + BOOST_TEST(v2.is_array()); + const bool result = (toml::get>(v2) == std::vector{1}); + BOOST_TEST(result); + } + { + const toml::value v3 = u8R"([[1,]])"_toml; + BOOST_TEST(v3.is_array()); + const bool result = (toml::get>(toml::get(v3).front()) == std::vector{1}); + BOOST_TEST(result); + } + { + const toml::value v4 = u8R"([[1],])"_toml; + BOOST_TEST(v4.is_array()); + const bool result = (toml::get>(toml::get(v4).front()) == std::vector{1}); + BOOST_TEST(result); + } + } + { + const toml::value v1 = u8R"({a = 42})"_toml; + + BOOST_TEST(v1.is_table()); + const bool result = toml::get>(v1) == + std::map{{"a", 42}}; + BOOST_TEST(result); + } + { + const toml::value v1 = u8"1979-05-27"_toml; + + BOOST_TEST(v1.is_local_date()); + BOOST_TEST(toml::get(v1) == + toml::local_date(1979, toml::month_t::May, 27)); + } + { + const toml::value v1 = u8"12:00:00"_toml; + + BOOST_TEST(v1.is_local_time()); + const bool result = toml::get(v1) == std::chrono::hours(12); + BOOST_TEST(result); + } + { + const toml::value v1 = u8"1979-05-27T07:32:00"_toml; + BOOST_TEST(v1.is_local_datetime()); + BOOST_TEST(toml::get(v1) == + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), + toml::local_time(7, 32, 0))); + } + { + const toml::value v1 = u8"1979-05-27T07:32:00Z"_toml; + BOOST_TEST(v1.is_offset_datetime()); + BOOST_TEST(toml::get(v1) == + toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27), + toml::local_time(7, 32, 0), toml::time_offset(0, 0))); + } +} diff --git a/subprojects/toml11/tests/test_multiple_translation_unit_1.cpp b/subprojects/toml11/tests/test_multiple_translation_unit_1.cpp new file mode 100644 index 00000000000..08a4f9846cd --- /dev/null +++ b/subprojects/toml11/tests/test_multiple_translation_unit_1.cpp @@ -0,0 +1,11 @@ +#include + +int read_a(const toml::table&); + +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(toml::get(data)); +} diff --git a/subprojects/toml11/tests/test_multiple_translation_unit_2.cpp b/subprojects/toml11/tests/test_multiple_translation_unit_2.cpp new file mode 100644 index 00000000000..2a4cc329857 --- /dev/null +++ b/subprojects/toml11/tests/test_multiple_translation_unit_2.cpp @@ -0,0 +1,6 @@ +#include + +int read_a(const toml::table& t) +{ + return toml::get(t.at("a")); +} diff --git a/subprojects/toml11/tests/test_parse_array.cpp b/subprojects/toml11/tests/test_parse_array.cpp new file mode 100644 index 00000000000..2d118c29af0 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_array.cpp @@ -0,0 +1,288 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_oneline_array) +{ + TOML11_TEST_PARSE_EQUAL_VAT(parse_array, "[]", 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_VAT(parse_array, "[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_VAT(parse_array, "[\"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_VAT(parse_array, "[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_VAT(parse_array, "[\"foo\", \"bar\", \"baz\",]", a); + } +} + +BOOST_AUTO_TEST_CASE(test_oneline_array_value) +{ + TOML11_TEST_PARSE_EQUAL_VALUE(parse_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)); + } + { + 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)); + } + { + 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)); + } + { + 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)); + } +} + +BOOST_AUTO_TEST_CASE(test_multiline_array) +{ + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[\n#comment\n]", typename basic_value< discard_comments>::array_type()); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[\n#comment\n]", typename basic_value::array_type()); + + { + typename basic_value::array_type a(5); + a[0] = basic_value(3); + a[1] = basic_value(1); + a[2] = basic_value(4); + a[3] = basic_value(1); + a[4] = basic_value(5); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[3,\n1,\n4,\n1,\n5]", a); + } + { + typename basic_value::array_type a(5); + a[0] = basic_value(3); + a[1] = basic_value(1); + a[2] = basic_value(4); + a[3] = basic_value(1); + a[4] = basic_value(5); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[3,\n1,\n4,\n1,\n5]", a); + } + + { + typename basic_value::array_type a(5); + a[0] = basic_value(3); + a[1] = basic_value(1); + a[2] = basic_value(4); + a[3] = basic_value(1); + a[4] = basic_value(5); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", a); + } + { + typename basic_value::array_type a(5); + a[0] = basic_value(3, {"comment"}); + a[1] = basic_value(1, {"comment"}); + a[2] = basic_value(4, {"comment"}); + a[3] = basic_value(1, {"comment"}); + a[4] = basic_value(5, {"comment"}); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", a); + } + + + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo"); + a[1] = basic_value("bar"); + a[2] = basic_value("baz"); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[\"foo\",\n\"bar\",\n\"baz\"]", a); + } + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo"); + a[1] = basic_value("bar"); + a[2] = basic_value("baz"); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[\"foo\",\n\"bar\",\n\"baz\"]", a); + } + + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo"); + a[1] = basic_value("b#r"); + a[2] = basic_value("b#z"); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a); + } + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo", {"comment"}); + a[1] = basic_value("b#r", {"comment"}); + a[2] = basic_value("b#z", {"comment"}); + TOML11_TEST_PARSE_EQUAL_VAT(parse_array>, "[\"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]", basic_value< discard_comments>(typename basic_value< discard_comments>::array_type())); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[\n#comment\n]", basic_value(typename basic_value::array_type())); + + { + typename basic_value::array_type a(5); + a[0] = basic_value(3); + a[1] = basic_value(1); + a[2] = basic_value(4); + a[3] = basic_value(1); + a[4] = basic_value(5); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[3,\n1,\n4,\n1,\n5]", basic_value(a)); + } + { + typename basic_value::array_type a(5); + a[0] = basic_value(3); + a[1] = basic_value(1); + a[2] = basic_value(4); + a[3] = basic_value(1); + a[4] = basic_value(5); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[3,\n1,\n4,\n1,\n5]", basic_value(a)); + } + + { + typename basic_value::array_type a(5); + a[0] = basic_value(3); + a[1] = basic_value(1); + a[2] = basic_value(4); + a[3] = basic_value(1); + a[4] = basic_value(5); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", basic_value(a)); + } + { + typename basic_value::array_type a(5); + a[0] = basic_value(3, {"comment"}); + a[1] = basic_value(1, {"comment"}); + a[2] = basic_value(4, {"comment"}); + a[3] = basic_value(1, {"comment"}); + a[4] = basic_value(5, {"comment"}); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", basic_value(a)); + } + + + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo"); + a[1] = basic_value("bar"); + a[2] = basic_value("baz"); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[\"foo\",\n\"bar\",\n\"baz\"]", basic_value(a)); + } + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo"); + a[1] = basic_value("bar"); + a[2] = basic_value("baz"); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[\"foo\",\n\"bar\",\n\"baz\"]", basic_value(a)); + } + + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo"); + a[1] = basic_value("b#r"); + a[2] = basic_value("b#z"); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", basic_value(a)); + } + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo", {"comment"}); + a[1] = basic_value("b#r", {"comment"}); + a[2] = basic_value("b#z", {"comment"}); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", basic_value(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, "[\"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, "[\"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, "[\"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, "[\"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::array_type a(3); + a[0] = basic_value("foo"); + a[1] = basic_value("bar"); + a[2] = basic_value("baz"); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, + "[ \"foo\" # comment\n" + ", \"bar\" # comment\n" + ", \"baz\" # comment\n" + "]", basic_value(a)); + } + + { + typename basic_value::array_type a(3); + a[0] = basic_value("foo", {" comment"}); + a[1] = basic_value("bar", {" comment"}); + a[2] = basic_value("baz", {" comment"}); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value>, + "[ \"foo\" # comment\n" + ", \"bar\" # comment\n" + ", \"baz\" # comment\n" + "]", basic_value(a)); + } + +} diff --git a/subprojects/toml11/tests/test_parse_aux.hpp b/subprojects/toml11/tests/test_parse_aux.hpp new file mode 100644 index 00000000000..331d4c8f0da --- /dev/null +++ b/subprojects/toml11/tests/test_parse_aux.hpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +// 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 loc("test", token); \ + const auto result = psr(loc); \ + BOOST_TEST(result.is_ok()); \ + if(result.is_ok()){ \ + 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'; \ + } \ +} while(false); \ +/**/ + +#define TOML11_TEST_PARSE_EQUAL_VAT(psr, tkn, expct) \ +do { \ + const std::string token(tkn); \ + toml::detail::location loc("test", token); \ + const auto result = psr(loc, 0); \ + BOOST_TEST(result.is_ok()); \ + if(result.is_ok()){ \ + 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'; \ + } \ +} while(false); \ +/**/ + +#define TOML11_TEST_PARSE_EQUAL_VALUE(psr, tkn, expct) \ +do { \ + const std::string token(tkn); \ + toml::detail::location loc("test", token); \ + const auto result = psr(loc, 0); \ + BOOST_TEST(result.is_ok()); \ + if(result.is_ok()){ \ + BOOST_TEST(result.unwrap() == expct); \ + } else { \ + std::cerr << "parse_value failed with input `"; \ + std::cerr << token << "`.\n"; \ + std::cerr << "reason: " << result.unwrap_err() << '\n'; \ + } \ +} while(false); \ +/**/ + diff --git a/subprojects/toml11/tests/test_parse_boolean.cpp b/subprojects/toml11/tests/test_parse_boolean.cpp new file mode 100644 index 00000000000..5ed128c2087 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_boolean.cpp @@ -0,0 +1,19 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_boolean) +{ + TOML11_TEST_PARSE_EQUAL(parse_boolean, "true", true); + TOML11_TEST_PARSE_EQUAL(parse_boolean, "false", false); +} + +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)); +} diff --git a/subprojects/toml11/tests/test_parse_datetime.cpp b/subprojects/toml11/tests/test_parse_datetime.cpp new file mode 100644 index 00000000000..46bd78c940e --- /dev/null +++ b/subprojects/toml11/tests/test_parse_datetime.cpp @@ -0,0 +1,246 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_time) +{ + TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00", toml::local_time(7, 32, 0)); + 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, "00:00:00.000000", toml::value(toml::local_time( 0, 0, 0, 0, 0))); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_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, "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))); +} + +BOOST_AUTO_TEST_CASE(test_datetime) +{ + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27T07:32:00", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0))); + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27T07:32:00.99", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 990, 0))); + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27T07:32:00.999999", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 999, 999))); + + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27t07:32:00", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0))); + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27t07:32:00.99", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 990, 0))); + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27t07:32:00.999999", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 999, 999))); + + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27 07:32:00", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0))); + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27 07:32:00.99", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 990, 0))); + TOML11_TEST_PARSE_EQUAL(parse_local_datetime, "1979-05-27 07:32:00.999999", + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 999, 999))); +} + +BOOST_AUTO_TEST_CASE(test_datetime_value) +{ + TOML11_TEST_PARSE_EQUAL_VALUE(parse_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", + 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", + 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", + 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", + 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", + 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", + 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", + 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", + toml::value(toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), toml::local_time(7, 32, 0, 999, 999)))); +} + +BOOST_AUTO_TEST_CASE(test_offset_datetime) +{ + TOML11_TEST_PARSE_EQUAL(parse_offset_datetime, "1979-05-27T07:32:00Z", + 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(parse_offset_datetime, "1979-05-27T07:32:00.99Z", + 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(parse_offset_datetime, "1979-05-27T07:32:00.999999Z", + 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(parse_offset_datetime, "1979-05-27T07:32:00+09:00", + 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(parse_offset_datetime, "1979-05-27T07:32:00.99+09:00", + 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(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", + 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", + 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", + 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", + 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", + 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", + 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)))); +} diff --git a/subprojects/toml11/tests/test_parse_file.cpp b/subprojects/toml11/tests/test_parse_file.cpp new file mode 100644 index 00000000000..2c456708644 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_file.cpp @@ -0,0 +1,1009 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include + +BOOST_AUTO_TEST_CASE(test_example) +{ + const auto data = toml::parse(testinput("example.toml")); + + BOOST_TEST(toml::find(data, "title") == "TOML Example"); + const auto& owner = toml::find(data, "owner"); + { + BOOST_TEST(toml::find(owner, "name") == "Tom Preston-Werner"); + BOOST_TEST(toml::find(owner, "organization") == "GitHub"); + BOOST_TEST(toml::find(owner, "bio") == + "GitHub Cofounder & CEO\nLikes tater tots and beer."); + BOOST_TEST(toml::find(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))); + } + + const auto& database = toml::find(data, "database"); + { + BOOST_TEST(toml::find(database, "server") == "192.168.1.1"); + const std::vector expected_ports{8001, 8001, 8002}; + BOOST_CHECK(toml::find>(database, "ports") == expected_ports); + BOOST_TEST(toml::find(database, "connection_max") == 5000); + BOOST_TEST(toml::find(database, "enabled") == true); + } + + const auto& servers = toml::find(data, "servers"); + { + toml::table alpha = toml::find(servers, "alpha"); + BOOST_TEST(toml::get(alpha.at("ip")) == "10.0.0.1"); + BOOST_TEST(toml::get(alpha.at("dc")) == "eqdc10"); + + toml::table beta = toml::find(servers, "beta"); + BOOST_TEST(toml::get(beta.at("ip")) == "10.0.0.2"); + BOOST_TEST(toml::get(beta.at("dc")) == "eqdc10"); + BOOST_TEST(toml::get(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD"); + } + + const auto& clients = toml::find(data, "clients"); + { + toml::array clients_data = toml::find(clients, "data"); + + std::vector expected_name{"gamma", "delta"}; + BOOST_CHECK(toml::get>(clients_data.at(0)) == expected_name); + + std::vector expected_number{1, 2}; + BOOST_CHECK(toml::get>(clients_data.at(1)) == expected_number); + + std::vector expected_hosts{"alpha", "omega"}; + BOOST_CHECK(toml::find>(clients, "hosts") == expected_hosts); + } + + std::vector products = + toml::find>(data, "products"); + { + BOOST_TEST(toml::get(products.at(0).at("name")) == "Hammer"); + BOOST_TEST(toml::get(products.at(0).at("sku")) == 738594937); + + BOOST_TEST(toml::get(products.at(1).at("name")) == "Nail"); + BOOST_TEST(toml::get(products.at(1).at("sku")) == 284758393); + BOOST_TEST(toml::get(products.at(1).at("color")) == "gray"); + } +} + +BOOST_AUTO_TEST_CASE(test_example_stream) +{ + std::ifstream ifs(testinput("example.toml"), std::ios::binary); + const auto data = toml::parse(ifs); + + BOOST_TEST(toml::find(data, "title") == "TOML Example"); + const auto& owner = toml::find(data, "owner"); + { + BOOST_TEST(toml::find(owner, "name") == "Tom Preston-Werner"); + BOOST_TEST(toml::find(owner, "organization") == "GitHub"); + BOOST_TEST(toml::find(owner, "bio") == + "GitHub Cofounder & CEO\nLikes tater tots and beer."); + BOOST_TEST(toml::find(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))); + } + + const auto& database = toml::find(data, "database"); + { + BOOST_TEST(toml::find(database, "server") == "192.168.1.1"); + const std::vector expected_ports{8001, 8001, 8002}; + BOOST_CHECK(toml::find>(database, "ports") == expected_ports); + BOOST_TEST(toml::find(database, "connection_max") == 5000); + BOOST_TEST(toml::find(database, "enabled") == true); + } + + const auto& servers = toml::find(data, "servers"); + { + toml::table alpha = toml::find(servers, "alpha"); + BOOST_TEST(toml::get(alpha.at("ip")) == "10.0.0.1"); + BOOST_TEST(toml::get(alpha.at("dc")) == "eqdc10"); + + toml::table beta = toml::find(servers, "beta"); + BOOST_TEST(toml::get(beta.at("ip")) == "10.0.0.2"); + BOOST_TEST(toml::get(beta.at("dc")) == "eqdc10"); + BOOST_TEST(toml::get(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD"); + } + + const auto& clients = toml::find(data, "clients"); + { + toml::array clients_data = toml::find(clients, "data"); + std::vector expected_name{"gamma", "delta"}; + BOOST_CHECK(toml::get>(clients_data.at(0)) == expected_name); + + std::vector expected_number{1, 2}; + BOOST_CHECK(toml::get>(clients_data.at(1)) == expected_number); + + std::vector expected_hosts{"alpha", "omega"}; + BOOST_CHECK(toml::find>(clients, "hosts") == expected_hosts); + } + + std::vector products = + toml::find>(data, "products"); + { + BOOST_TEST(toml::get(products.at(0).at("name")) == + "Hammer"); + BOOST_TEST(toml::get(products.at(0).at("sku")) == + 738594937); + + BOOST_TEST(toml::get(products.at(1).at("name")) == + "Nail"); + BOOST_TEST(toml::get(products.at(1).at("sku")) == + 284758393); + BOOST_TEST(toml::get(products.at(1).at("color")) == + "gray"); + } +} + +BOOST_AUTO_TEST_CASE(test_example_file_pointer) +{ + FILE * file = fopen(testinput("example.toml").c_str(), "rb"); + const auto data = toml::parse(file, "toml/tests/example.toml"); + fclose(file); + + BOOST_TEST(toml::find(data, "title") == "TOML Example"); + const auto& owner = toml::find(data, "owner"); + { + BOOST_TEST(toml::find(owner, "name") == "Tom Preston-Werner"); + BOOST_TEST(toml::find(owner, "organization") == "GitHub"); + BOOST_TEST(toml::find(owner, "bio") == + "GitHub Cofounder & CEO\nLikes tater tots and beer."); + BOOST_TEST(toml::find(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))); + } + + const auto& database = toml::find(data, "database"); + { + BOOST_TEST(toml::find(database, "server") == "192.168.1.1"); + const std::vector expected_ports{8001, 8001, 8002}; + BOOST_CHECK(toml::find>(database, "ports") == expected_ports); + BOOST_TEST(toml::find(database, "connection_max") == 5000); + BOOST_TEST(toml::find(database, "enabled") == true); + } + + const auto& servers = toml::find(data, "servers"); + { + toml::table alpha = toml::find(servers, "alpha"); + BOOST_TEST(toml::get(alpha.at("ip")) == "10.0.0.1"); + BOOST_TEST(toml::get(alpha.at("dc")) == "eqdc10"); + + toml::table beta = toml::find(servers, "beta"); + BOOST_TEST(toml::get(beta.at("ip")) == "10.0.0.2"); + BOOST_TEST(toml::get(beta.at("dc")) == "eqdc10"); + BOOST_TEST(toml::get(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD"); + } + + const auto& clients = toml::find(data, "clients"); + { + toml::array clients_data = toml::find(clients, "data"); + std::vector expected_name{"gamma", "delta"}; + BOOST_CHECK(toml::get>(clients_data.at(0)) == expected_name); + + std::vector expected_number{1, 2}; + BOOST_CHECK(toml::get>(clients_data.at(1)) == expected_number); + + std::vector expected_hosts{"alpha", "omega"}; + BOOST_CHECK(toml::find>(clients, "hosts") == expected_hosts); + } + + std::vector products = + toml::find>(data, "products"); + { + BOOST_TEST(toml::get(products.at(0).at("name")) == + "Hammer"); + BOOST_TEST(toml::get(products.at(0).at("sku")) == + 738594937); + + BOOST_TEST(toml::get(products.at(1).at("name")) == + "Nail"); + BOOST_TEST(toml::get(products.at(1).at("sku")) == + 284758393); + BOOST_TEST(toml::get(products.at(1).at("color")) == + "gray"); + } +} + +BOOST_AUTO_TEST_CASE(test_fruit) +{ + const auto data = toml::parse(testinput("fruit.toml")); + const auto blah = toml::find(toml::find(data, "fruit"), "blah"); + BOOST_TEST(toml::find(blah.at(0), "name") == "apple"); + BOOST_TEST(toml::find(blah.at(1), "name") == "banana"); + { + const auto physical = toml::find(blah.at(0), "physical"); + BOOST_TEST(toml::find(physical, "color") == "red"); + BOOST_TEST(toml::find(physical, "shape") == "round"); + } + { + const auto physical = toml::find(blah.at(1), "physical"); + BOOST_TEST(toml::find(physical, "color") == "yellow"); + BOOST_TEST(toml::find(physical, "shape") == "bent"); + } +} + +BOOST_AUTO_TEST_CASE(test_hard_example) +{ + const auto data = toml::parse(testinput("hard_example.toml")); + const auto the = toml::find(data, "the"); + BOOST_TEST(toml::find(the, "test_string") == + "You'll hate me after this - #"); + + const auto hard = toml::find(the, "hard"); + const std::vector expected_the_hard_test_array{"] ", " # "}; + BOOST_CHECK(toml::find>(hard, "test_array") == + expected_the_hard_test_array); + const std::vector expected_the_hard_test_array2{ + "Test #11 ]proved that", "Experiment #9 was a success"}; + BOOST_CHECK(toml::find>(hard, "test_array2") == + expected_the_hard_test_array2); + BOOST_TEST(toml::find(hard, "another_test_string") == + " Same thing, but with a string #"); + BOOST_TEST(toml::find(hard, "harder_test_string") == + " And when \"'s are in the string, along with # \""); + + const auto bit = toml::find(hard, "bit#"); + BOOST_TEST(toml::find(bit, "what?") == + "You don't think some user won't do that?"); + const std::vector expected_multi_line_array{"]"}; + BOOST_CHECK(toml::find>(bit, "multi_line_array") == + expected_multi_line_array); +} +BOOST_AUTO_TEST_CASE(test_hard_example_comment) +{ + const auto data = toml::parse(testinput("hard_example.toml")); + const auto the = toml::find(data, "the"); + BOOST_TEST(toml::find(the, "test_string") == + "You'll hate me after this - #"); + + const auto hard = toml::find(the, "hard"); + const std::vector expected_the_hard_test_array{"] ", " # "}; + BOOST_CHECK(toml::find>(hard, "test_array") == + expected_the_hard_test_array); + const std::vector expected_the_hard_test_array2{ + "Test #11 ]proved that", "Experiment #9 was a success"}; + BOOST_CHECK(toml::find>(hard, "test_array2") == + expected_the_hard_test_array2); + BOOST_TEST(toml::find(hard, "another_test_string") == + " Same thing, but with a string #"); + BOOST_TEST(toml::find(hard, "harder_test_string") == + " And when \"'s are in the string, along with # \""); + + const auto bit = toml::find(hard, "bit#"); + BOOST_TEST(toml::find(bit, "what?") == + "You don't think some user won't do that?"); + const std::vector expected_multi_line_array{"]"}; + BOOST_CHECK(toml::find>(bit, "multi_line_array") == + expected_multi_line_array); +} + + +BOOST_AUTO_TEST_CASE(test_example_preserve_comment) +{ + const auto data = toml::parse(testinput("example.toml")); + + BOOST_TEST(toml::find(data, "title") == "TOML Example"); + const auto& owner = toml::find(data, "owner"); + { + BOOST_TEST(toml::find(owner, "name") == "Tom Preston-Werner"); + BOOST_TEST(toml::find(owner, "organization") == "GitHub"); + BOOST_TEST(toml::find(owner, "bio") == + "GitHub Cofounder & CEO\nLikes tater tots and beer."); + BOOST_TEST(toml::find(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(database, "server") == "192.168.1.1"); + const std::vector expected_ports{8001, 8001, 8002}; + BOOST_CHECK(toml::find>(database, "ports") == expected_ports); + BOOST_TEST(toml::find(database, "connection_max") == 5000); + BOOST_TEST(toml::find(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(alpha, "ip") == "10.0.0.1"); + BOOST_TEST(toml::find(alpha, "dc") == "eqdc10"); + + const auto& beta = toml::find(servers, "beta"); + BOOST_TEST(toml::find(beta, "ip") == "10.0.0.2"); + BOOST_TEST(toml::find(beta, "dc") == "eqdc10"); + BOOST_TEST(toml::find(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(clients, "data"); + std::vector expected_name{"gamma", "delta"}; + BOOST_CHECK(toml::get>(clients_data.at(0)) == + expected_name); + std::vector expected_number{1, 2}; + BOOST_CHECK(toml::get>(clients_data.at(1)) == + expected_number); + std::vector expected_hosts{"alpha", "omega"}; + BOOST_CHECK(toml::find>(clients, "hosts") == + expected_hosts); + + BOOST_TEST(toml::find(clients, "hosts").comments().at(0) == + " Line breaks are OK when inside arrays"); + } + + std::vector products = + toml::find>(data, "products"); + { + BOOST_TEST(toml::get(products.at(0).at("name")) == + "Hammer"); + BOOST_TEST(toml::get(products.at(0).at("sku")) == + 738594937); + + BOOST_TEST(toml::get(products.at(1).at("name")) == + "Nail"); + BOOST_TEST(toml::get(products.at(1).at("sku")) == + 284758393); + BOOST_TEST(toml::get(products.at(1).at("color")) == + "gray"); + } +} + +BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque) +{ + const auto data = toml::parse( + testinput("example.toml")); + + static_assert(std::is_same::type> + >::value, ""); + static_assert(std::is_same::type> + >::value, ""); + + BOOST_TEST(toml::find(data, "title") == "TOML Example"); + const auto& owner = toml::find(data, "owner"); + { + BOOST_TEST(toml::find(owner, "name") == "Tom Preston-Werner"); + BOOST_TEST(toml::find(owner, "organization") == "GitHub"); + BOOST_TEST(toml::find(owner, "bio") == + "GitHub Cofounder & CEO\nLikes tater tots and beer."); + BOOST_TEST(toml::find(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(database, "server") == "192.168.1.1"); + const std::vector expected_ports{8001, 8001, 8002}; + BOOST_CHECK(toml::find>(database, "ports") == expected_ports); + BOOST_TEST(toml::find(database, "connection_max") == 5000); + BOOST_TEST(toml::find(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(alpha, "ip") == "10.0.0.1"); + BOOST_TEST(toml::find(alpha, "dc") == "eqdc10"); + + const auto& beta = toml::find(servers, "beta"); + BOOST_TEST(toml::find(beta, "ip") == "10.0.0.2"); + BOOST_TEST(toml::find(beta, "dc") == "eqdc10"); + BOOST_TEST(toml::find(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(clients, "data"); + std::vector expected_name{"gamma", "delta"}; + BOOST_CHECK(toml::get>(clients_data.at(0)) == + expected_name); + std::vector expected_number{1, 2}; + BOOST_CHECK(toml::get>(clients_data.at(1)) == + expected_number); + std::vector expected_hosts{"alpha", "omega"}; + BOOST_CHECK(toml::find>(clients, "hosts") == + expected_hosts); + + BOOST_TEST(toml::find(clients, "hosts").comments().at(0) == + " Line breaks are OK when inside arrays"); + } + + std::vector products = + toml::find>(data, "products"); + { + BOOST_TEST(toml::get(products.at(0).at("name")) == + "Hammer"); + BOOST_TEST(toml::get(products.at(0).at("sku")) == + 738594937); + + BOOST_TEST(toml::get(products.at(1).at("name")) == + "Nail"); + BOOST_TEST(toml::get(products.at(1).at("sku")) == + 284758393); + BOOST_TEST(toml::get(products.at(1).at("color")) == + "gray"); + } +} + +// --------------------------------------------------------------------------- +// after here, the test codes generate the content of a file. + +BOOST_AUTO_TEST_CASE(test_file_with_BOM) +{ + { + const std::string table( + "\xEF\xBB\xBF" // BOM + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, "test_file_with_BOM.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "\xEF\xBB\xBF" // BOM + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + ); + { + std::ofstream ofs("tmp.toml"); + ofs << table; + } + const auto data = toml::parse("tmp.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "\xEF\xBB\xBF" // BOM + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, "test_file_with_BOM_CRLF.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "\xEF\xBB\xBF" // BOM + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + ); + { + // with text-mode, "\n" is converted to "\r\n" and the resulting + // 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(), static_cast(table.size())); + } + const auto data = toml::parse("tmp.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } +} + +BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file) +{ + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_file_without_newline_at_the_end_of_file.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_file_without_newline_at_the_end_of_file_CRLF.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\" # comment" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_file_without_newline_at_the_end_of_file_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\" # comment" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_file_without_newline_at_the_end_of_file_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\" \t" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_file_without_newline_at_the_end_of_file_ws.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\" \t" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_file_without_newline_at_the_end_of_file_ws.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } +} + + +BOOST_AUTO_TEST_CASE(test_files_end_with_comment) +{ + // comment w/o newline + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + "# comment" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + "# comment\n" + "# one more comment" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + + // comment w/ newline + + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + "# comment\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + "# comment\n" + "# one more comment\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + + // CRLF version + + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + "# comment" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + "# comment\r\n" + "# one more comment" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + "# comment\r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + "# comment\r\n" + "# one more comment\r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_comment.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } +} + + +BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines) +{ + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + "\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + "\n" + "\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + + // with whitespaces + + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + " \n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + " \n" + " \n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + "\n" + " \n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + " \n" + "\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + + // with whitespaces but no newline + { + const std::string table( + "key = \"value\"\n" + "[table]\n" + "key = \"value\"\n" + " " + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(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(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + + + // CRLF + + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + "\r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + "\r\n" + "\r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + + // with whitespaces + + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + " \r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + "\r\n" + " \r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + " \r\n" + "\r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + " \r\n" + " \r\n" + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } + { + const std::string table( + "key = \"value\"\r\n" + "[table]\r\n" + "key = \"value\"\r\n" + " " + ); + std::istringstream iss(table); + const auto data = toml::parse(iss, + "test_files_end_with_newline.toml"); + + BOOST_TEST(toml::find(data, "key") == "value"); + BOOST_TEST(toml::find(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(data, "key") == "value"); + BOOST_TEST(toml::find(toml::find(data, "table"), "key") == "value"); + } +} + +BOOST_AUTO_TEST_CASE(test_parse_function_compiles) +{ + using result_type = decltype(toml::parse("string literal")); + (void) [](const char* that) -> result_type { return toml::parse(that); }; + (void) [](char* that) -> result_type { return toml::parse(that); }; + (void) [](const std::string& that) -> result_type { return toml::parse(that); }; + (void) [](std::string& that) -> result_type { return toml::parse(that); }; + (void) [](std::string&& that) -> result_type { return toml::parse(that); }; +#ifdef TOML11_HAS_STD_FILESYSTEM + (void) [](const std::filesystem::path& that) -> result_type { return toml::parse(that); }; + (void) [](std::filesystem::path& that) -> result_type { return toml::parse(that); }; + (void) [](std::filesystem::path&& that) -> result_type { return toml::parse(that); }; +#endif + (void) [](std::FILE* that) -> result_type { return toml::parse(that, "mandatory.toml"); }; +} + +BOOST_AUTO_TEST_CASE(test_parse_nonexistent_file) +{ + BOOST_CHECK_THROW(toml::parse("nonexistent.toml"), std::ios_base::failure); +} diff --git a/subprojects/toml11/tests/test_parse_floating.cpp b/subprojects/toml11/tests/test_parse_floating.cpp new file mode 100644 index 00000000000..5c05baba728 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_floating.cpp @@ -0,0 +1,181 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +#include + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_fractional) +{ + TOML11_TEST_PARSE_EQUAL(parse_floating, "1.0", 1.0); + TOML11_TEST_PARSE_EQUAL(parse_floating, "0.1", 0.1); + TOML11_TEST_PARSE_EQUAL(parse_floating, "0.001", 0.001); + TOML11_TEST_PARSE_EQUAL(parse_floating, "0.100", 0.1); + TOML11_TEST_PARSE_EQUAL(parse_floating, "+3.14", 3.14); + TOML11_TEST_PARSE_EQUAL(parse_floating, "-3.14", -3.14); + TOML11_TEST_PARSE_EQUAL(parse_floating, "3.1415_9265_3589", 3.141592653589); + TOML11_TEST_PARSE_EQUAL(parse_floating, "+3.1415_9265_3589", 3.141592653589); + TOML11_TEST_PARSE_EQUAL(parse_floating, "-3.1415_9265_3589", -3.141592653589); + TOML11_TEST_PARSE_EQUAL(parse_floating, "123_456.789", 123456.789); + TOML11_TEST_PARSE_EQUAL(parse_floating, "+123_456.789", 123456.789); + TOML11_TEST_PARSE_EQUAL(parse_floating, "-123_456.789", -123456.789); + TOML11_TEST_PARSE_EQUAL(parse_floating, "+0.0", 0.0); + TOML11_TEST_PARSE_EQUAL(parse_floating, "-0.0", -0.0); +} + +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)); +} + +BOOST_AUTO_TEST_CASE(test_exponential) +{ + TOML11_TEST_PARSE_EQUAL(parse_floating, "1e10", 1e10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "1e+10", 1e10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "1e-10", 1e-10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "+1e10", 1e10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "+1e+10", 1e10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "+1e-10", 1e-10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "-1e10", -1e10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "-1e+10", -1e10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "-1e-10", -1e-10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "123e-10", 123e-10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "1E10", 1e10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "1E+10", 1e10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "1E-10", 1e-10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "123E-10", 123e-10); + TOML11_TEST_PARSE_EQUAL(parse_floating, "1_2_3E-10", 123e-10); + 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)); + +#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, "1_2_3E-01", value(123e-1)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "1_2_3E-0_1", value(123e-1)); +#endif +} +BOOST_AUTO_TEST_CASE(test_fe) +{ + TOML11_TEST_PARSE_EQUAL(parse_floating, "6.02e23", 6.02e23); + TOML11_TEST_PARSE_EQUAL(parse_floating, "6.02e+23", 6.02e23); + TOML11_TEST_PARSE_EQUAL(parse_floating, "1.112_650_06e-17", 1.11265006e-17); +} +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)); + +#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, "3.141_5e-01", value(3.1415e-1)); +#endif +} + +BOOST_AUTO_TEST_CASE(test_inf) +{ + { + const std::string token("inf"); + toml::detail::location loc("test", token); + const auto r = parse_floating(loc); + BOOST_CHECK(r.is_ok()); + BOOST_CHECK(std::isinf(r.unwrap().first)); + BOOST_CHECK(r.unwrap().first > 0.0); + } + { + const std::string token("+inf"); + toml::detail::location loc("test", token); + const auto r = parse_floating(loc); + BOOST_CHECK(r.is_ok()); + BOOST_CHECK(std::isinf(r.unwrap().first)); + BOOST_CHECK(r.unwrap().first > 0.0); + } + { + const std::string token("-inf"); + toml::detail::location loc("test", token); + const auto r = parse_floating(loc); + BOOST_CHECK(r.is_ok()); + BOOST_CHECK(std::isinf(r.unwrap().first)); + BOOST_CHECK(r.unwrap().first < 0.0); + } +} + +BOOST_AUTO_TEST_CASE(test_nan) +{ + { + const std::string token("nan"); + 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 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 loc("test", token); + const auto r = parse_floating(loc); + BOOST_CHECK(r.is_ok()); + BOOST_CHECK(std::isnan(r.unwrap().first)); + } +} + +BOOST_AUTO_TEST_CASE(test_overflow) +{ + std::istringstream float_overflow (std::string("float-overflow = 1.0e+1024")); + BOOST_CHECK_THROW(toml::parse(float_overflow ), toml::syntax_error); + // istringstream >> float does not set failbit in case of underflow. +} diff --git a/subprojects/toml11/tests/test_parse_inline_table.cpp b/subprojects/toml11/tests/test_parse_inline_table.cpp new file mode 100644 index 00000000000..a11767ca3e7 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_inline_table.cpp @@ -0,0 +1,59 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_inline_table) +{ + TOML11_TEST_PARSE_EQUAL_VAT(parse_inline_table, "{}", table()); + { + table t; + t["foo"] = toml::value(42); + t["bar"] = toml::value("baz"); + TOML11_TEST_PARSE_EQUAL_VAT(parse_inline_table, "{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_VAT(parse_inline_table, "{type.name = \"pug\"}", t); + } +} + +BOOST_AUTO_TEST_CASE(test_inline_table_value) +{ + TOML11_TEST_PARSE_EQUAL_VALUE(parse_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)); + } + { + 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)); + } +} + +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); + } +} diff --git a/subprojects/toml11/tests/test_parse_integer.cpp b/subprojects/toml11/tests/test_parse_integer.cpp new file mode 100644 index 00000000000..4a862260ee0 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_integer.cpp @@ -0,0 +1,116 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_decimal) +{ + TOML11_TEST_PARSE_EQUAL(parse_integer, "1234", 1234); + TOML11_TEST_PARSE_EQUAL(parse_integer, "+1234", 1234); + TOML11_TEST_PARSE_EQUAL(parse_integer, "-1234", -1234); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0", 0); + TOML11_TEST_PARSE_EQUAL(parse_integer, "1_2_3_4", 1234); + TOML11_TEST_PARSE_EQUAL(parse_integer, "+1_2_3_4", +1234); + TOML11_TEST_PARSE_EQUAL(parse_integer, "-1_2_3_4", -1234); + TOML11_TEST_PARSE_EQUAL(parse_integer, "123_456_789", 123456789); +} + +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)); +} + +BOOST_AUTO_TEST_CASE(test_hex) +{ + TOML11_TEST_PARSE_EQUAL(parse_integer, "0xDEADBEEF", 0xDEADBEEF); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0xdeadbeef", 0xDEADBEEF); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0xDEADbeef", 0xDEADBEEF); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0xDEAD_BEEF", 0xDEADBEEF); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0xdead_beef", 0xDEADBEEF); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0xdead_BEEF", 0xDEADBEEF); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0xFF", 0xFF); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0x00FF", 0xFF); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0x0000FF", 0xFF); +} + +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)); +} + +BOOST_AUTO_TEST_CASE(test_oct) +{ + TOML11_TEST_PARSE_EQUAL(parse_integer, "0o777", 64*7+8*7+7); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0o7_7_7", 64*7+8*7+7); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0o007", 7); +} + +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)); +} + +BOOST_AUTO_TEST_CASE(test_bin) +{ + TOML11_TEST_PARSE_EQUAL(parse_integer, "0b10000", 16); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0b010000", 16); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0b01_00_00", 16); + TOML11_TEST_PARSE_EQUAL(parse_integer, "0b111111", 63); +} + +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, + "0b1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000", + // 1 0 0 0 + // 0 C 8 4 + value(0x0888888888888888)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "0b01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111", + // 1 0 0 0 + // 0 C 8 4 + value(0x7FFFFFFFFFFFFFFF)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "0b00000000_01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111", + // 1 0 0 0 + // 0 C 8 4 + value(0x7FFFFFFFFFFFFFFF)); +} + +BOOST_AUTO_TEST_CASE(test_integer_overflow) +{ + std::istringstream dec_overflow(std::string("dec-overflow = 9223372036854775808")); + std::istringstream hex_overflow(std::string("hex-overflow = 0x1_00000000_00000000")); + std::istringstream oct_overflow(std::string("oct-overflow = 0o1_000_000_000_000_000_000_000")); + // 64 56 48 40 32 24 16 8 + std::istringstream bin_overflow(std::string("bin-overflow = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000")); + BOOST_CHECK_THROW(toml::parse(dec_overflow), toml::syntax_error); + BOOST_CHECK_THROW(toml::parse(hex_overflow), toml::syntax_error); + BOOST_CHECK_THROW(toml::parse(oct_overflow), toml::syntax_error); + BOOST_CHECK_THROW(toml::parse(bin_overflow), toml::syntax_error); +} diff --git a/subprojects/toml11/tests/test_parse_key.cpp b/subprojects/toml11/tests/test_parse_key.cpp new file mode 100644 index 00000000000..3af0eaa3373 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_key.cpp @@ -0,0 +1,58 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_bare_key) +{ + TOML11_TEST_PARSE_EQUAL(parse_key, "barekey", std::vector(1, "barekey")); + TOML11_TEST_PARSE_EQUAL(parse_key, "bare-key", std::vector(1, "bare-key")); + TOML11_TEST_PARSE_EQUAL(parse_key, "bare_key", std::vector(1, "bare_key")); + TOML11_TEST_PARSE_EQUAL(parse_key, "1234", std::vector(1, "1234")); +} + +BOOST_AUTO_TEST_CASE(test_quoted_key) +{ + TOML11_TEST_PARSE_EQUAL(parse_key, "\"127.0.0.1\"", std::vector(1, "127.0.0.1" )); + TOML11_TEST_PARSE_EQUAL(parse_key, "\"character encoding\"", std::vector(1, "character encoding")); +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) + TOML11_TEST_PARSE_EQUAL(parse_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"", std::vector(1, "\xCA\x8E\xC7\x9D\xCA\x9E")); +#else + TOML11_TEST_PARSE_EQUAL(parse_key, "\"ʎǝʞ\"", std::vector(1, "ʎǝʞ" )); +#endif + TOML11_TEST_PARSE_EQUAL(parse_key, "'key2'", std::vector(1, "key2" )); + TOML11_TEST_PARSE_EQUAL(parse_key, "'quoted \"value\"'", std::vector(1, "quoted \"value\"" )); +} + +BOOST_AUTO_TEST_CASE(test_dotted_key) +{ + { + std::vector keys(2); + keys[0] = "physical"; + keys[1] = "color"; + TOML11_TEST_PARSE_EQUAL(parse_key, "physical.color", keys); + } + { + std::vector keys(2); + keys[0] = "physical"; + keys[1] = "shape"; + TOML11_TEST_PARSE_EQUAL(parse_key, "physical.shape", keys); + } + { + std::vector keys(4); + keys[0] = "x"; + keys[1] = "y"; + keys[2] = "z"; + keys[3] = "w"; + TOML11_TEST_PARSE_EQUAL(parse_key, "x.y.z.w", keys); + } + { + std::vector keys(2); + keys[0] = "site"; + keys[1] = "google.com"; + TOML11_TEST_PARSE_EQUAL(parse_key, "site.\"google.com\"", keys); + } +} diff --git a/subprojects/toml11/tests/test_parse_string.cpp b/subprojects/toml11/tests/test_parse_string.cpp new file mode 100644 index 00000000000..bf381e35ebb --- /dev/null +++ b/subprojects/toml11/tests/test_parse_string.cpp @@ -0,0 +1,245 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_string) +{ + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"The quick brown fox jumps over the lazy dog\"", + string("The quick brown fox jumps over the lazy dog", string_t::basic)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "\'The quick brown fox jumps over the lazy dog\'", + string("The quick brown fox jumps over the lazy dog", string_t::literal)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"\"\"The quick brown fox \\\njumps over the lazy dog\"\"\"", + string("The quick brown fox jumps over the lazy dog", string_t::basic)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "'''The quick brown fox \njumps over the lazy dog'''", + string("The quick brown fox \njumps over the lazy dog", string_t::literal)); +} + +BOOST_AUTO_TEST_CASE(test_string_value) +{ + TOML11_TEST_PARSE_EQUAL_VALUE(parse_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, + "\'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, + "\"\"\"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, + "'''The quick brown fox \njumps over the lazy dog'''", + toml::value("The quick brown fox \njumps over the lazy dog", string_t::literal)); +} + + +BOOST_AUTO_TEST_CASE(test_basic_string) +{ + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"GitHub Cofounder & CEO\\nLikes tater tots and beer.\"", + string("GitHub Cofounder & CEO\nLikes tater tots and beer.", string_t::basic)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"192.168.1.1\"", + string("192.168.1.1", string_t::basic)); + +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"\xE4\xB8\xAD\xE5\x9B\xBD\"", + string("\xE4\xB8\xAD\xE5\x9B\xBD", string_t::basic)); +#else + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"中国\"", + string("中国", string_t::basic)); +#endif + + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"You'll hate me after this - #\"", + string("You'll hate me after this - #", string_t::basic)); + 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, + "\"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, + "\"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, + "\"\xE4\xB8\xAD\xE5\x9B\xBD\"", + value("\xE4\xB8\xAD\xE5\x9B\xBD", string_t::basic)); +#else + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "\"中国\"", + value("中国", string_t::basic)); +#endif + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "\"You'll hate me after this - #\"", + value("You'll hate me after this - #", string_t::basic)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_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, + "\"Here are fifteen apostrophes: '''''''''''''''\"", + value("Here are fifteen apostrophes: '''''''''''''''", string_t::basic)); +} + +BOOST_AUTO_TEST_CASE(test_ml_basic_string) +{ + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"\"\"\nThe quick brown \\\n\n fox jumps over \\\n the lazy dog.\"\"\"", + string("The quick brown fox jumps over the lazy dog.", string_t::basic)); + 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, + "\"\"\"\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, + "\"\"\"\\\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, + "\"\"\"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, + "\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"", + value("Here are three quotation marks: \"\"\".", string_t::basic)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"", + value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_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) +{ + TOML11_TEST_PARSE_EQUAL(parse_string, + "'C:\\Users\\nodejs\\templates'", + string("C:\\Users\\nodejs\\templates", string_t::literal)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "'\\\\ServerX\\admin$\\system32\\'", + string("\\\\ServerX\\admin$\\system32\\", string_t::literal)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "'Tom \"Dubs\" Preston-Werner'", + string("Tom \"Dubs\" Preston-Werner", string_t::literal)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "'<\\i\\c*\\s*>'", + string("<\\i\\c*\\s*>", string_t::literal)); +} + +BOOST_AUTO_TEST_CASE(test_literal_string_value) +{ + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "'C:\\Users\\nodejs\\templates'", + value("C:\\Users\\nodejs\\templates", string_t::literal)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "'\\\\ServerX\\admin$\\system32\\'", + value("\\\\ServerX\\admin$\\system32\\", string_t::literal)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "'Tom \"Dubs\" Preston-Werner'", + value("Tom \"Dubs\" Preston-Werner", string_t::literal)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "'<\\i\\c*\\s*>'", + value("<\\i\\c*\\s*>", string_t::literal)); +} + +BOOST_AUTO_TEST_CASE(test_ml_literal_string) +{ + TOML11_TEST_PARSE_EQUAL(parse_string, + "'''I [dw]on't need \\d{2} apples'''", + string("I [dw]on't need \\d{2} apples", string_t::literal)); + 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, + "'''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, + "'''\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, + "''''That's still pointless', she said.'''", + value("'That's still pointless', she said.", string_t::literal)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''", + value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_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_simple_excape_sequences) +{ + TOML11_TEST_PARSE_EQUAL(parse_string, + R"("\"\\\b\f\n\r\t")", + string("\"\\\b\f\n\r\t", string_t::basic)); +#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES + TOML11_TEST_PARSE_EQUAL(parse_string, + R"("\e")", + string("\x1b", string_t::basic)); +#endif +} + + +BOOST_AUTO_TEST_CASE(test_unicode_escape_sequence) +{ +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"\\u03B1\\u03B2\\u03B3\"", + string("\xCE\xB1\xCE\xB2\xCE\xB3", string_t::basic)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"\\U0001D7AA\"", + string("\xF0\x9D\x9E\xAA", string_t::basic)); +#else + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"\\u03B1\\u03B2\\u03B3\"", + string("αβγ", string_t::basic)); + TOML11_TEST_PARSE_EQUAL(parse_string, + "\"\\U0001D7AA\"", + string("𝞪", string_t::basic)); +#endif +} diff --git a/subprojects/toml11/tests/test_parse_table.cpp b/subprojects/toml11/tests/test_parse_table.cpp new file mode 100644 index 00000000000..0fd54c7fe55 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_table.cpp @@ -0,0 +1,45 @@ +#include +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_normal_table) +{ + std::string table( + "key1 = \"value\"\n" + "key2 = 42\n" + "key3 = 3.14\n" + ); + location loc("test", table); + + const auto result = toml::detail::parse_ml_table(loc); + BOOST_TEST(result.is_ok()); + const auto data = result.unwrap(); + + BOOST_TEST(toml::get(data.at("key1")) == "value"); + BOOST_TEST(toml::get(data.at("key2")) == 42); + BOOST_TEST(toml::get(data.at("key3")) == 3.14); +} + +BOOST_AUTO_TEST_CASE(test_nested_table) +{ + std::string table( + "a.b = \"value\"\n" + "a.c.d = 42\n" + ); + location loc("test", table); + + const auto result = toml::detail::parse_ml_table(loc); + BOOST_TEST(result.is_ok()); + const auto data = result.unwrap(); + + const auto a = toml::get(data.at("a")); + const auto c = toml::get(a.at("c")); + + BOOST_TEST(toml::get(a.at("b")) == "value"); + BOOST_TEST(toml::get(c.at("d")) == 42); +} diff --git a/subprojects/toml11/tests/test_parse_table_key.cpp b/subprojects/toml11/tests/test_parse_table_key.cpp new file mode 100644 index 00000000000..a921c96945e --- /dev/null +++ b/subprojects/toml11/tests/test_parse_table_key.cpp @@ -0,0 +1,112 @@ +#include + +#include "unit_test.hpp" +#include "test_parse_aux.hpp" + +using namespace toml; +using namespace detail; + +BOOST_AUTO_TEST_CASE(test_table_bare_key) +{ + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[barekey]", std::vector(1, "barekey")); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[bare-key]", std::vector(1, "bare-key")); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[bare_key]", std::vector(1, "bare_key")); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[1234]", std::vector(1, "1234")); +} + +BOOST_AUTO_TEST_CASE(test_table_quoted_key) +{ + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[\"127.0.0.1\"]", std::vector(1, "127.0.0.1" )); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[\"character encoding\"]", std::vector(1, "character encoding")); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[\"ʎǝʞ\"]", std::vector(1, "ʎǝʞ" )); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "['key2']", std::vector(1, "key2" )); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "['quoted \"value\"']", std::vector(1, "quoted \"value\"" )); +} + +BOOST_AUTO_TEST_CASE(test_table_dotted_key) +{ + { + std::vector keys(2); + keys[0] = "physical"; + keys[1] = "color"; + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[physical.color]", keys); + } + { + std::vector keys(2); + keys[0] = "physical"; + keys[1] = "shape"; + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[physical.shape]", keys); + } + { + std::vector keys(4); + keys[0] = "x"; + keys[1] = "y"; + keys[2] = "z"; + keys[3] = "w"; + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[x.y.z.w]", keys); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[x . y . z . w]", keys); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[x. y .z. w]", keys); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[x .y. z .w]", keys); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[ x. y .z . w ]", keys); + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[ x . y . z . w ]", keys); + } + { + std::vector keys(2); + keys[0] = "site"; + keys[1] = "google.com"; + TOML11_TEST_PARSE_EQUAL(parse_table_key, "[site.\"google.com\"]", keys); + } +} + +BOOST_AUTO_TEST_CASE(test_array_of_table_bare_key) +{ + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[barekey]]", std::vector(1, "barekey")); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[bare-key]]", std::vector(1, "bare-key")); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[bare_key]]", std::vector(1, "bare_key")); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[1234]]", std::vector(1, "1234")); +} + +BOOST_AUTO_TEST_CASE(test_array_of_table_quoted_key) +{ + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[\"127.0.0.1\"]]", std::vector(1, "127.0.0.1" )); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[\"character encoding\"]]", std::vector(1, "character encoding")); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[\"ʎǝʞ\"]]", std::vector(1, "ʎǝʞ" )); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[['key2']]", std::vector(1, "key2" )); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[['quoted \"value\"']]", std::vector(1, "quoted \"value\"" )); +} + +BOOST_AUTO_TEST_CASE(test_array_of_table_dotted_key) +{ + { + std::vector keys(2); + keys[0] = "physical"; + keys[1] = "color"; + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[physical.color]]", keys); + } + { + std::vector keys(2); + keys[0] = "physical"; + keys[1] = "shape"; + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[physical.shape]]", keys); + } + { + std::vector keys(4); + keys[0] = "x"; + keys[1] = "y"; + keys[2] = "z"; + keys[3] = "w"; + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[x.y.z.w]]", keys); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[x . y . z . w]]", keys); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[x. y .z. w]]", keys); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[x .y. z .w]]", keys); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[ x. y .z . w ]]", keys); + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[ x . y . z . w ]]", keys); + + } + { + std::vector keys(2); + keys[0] = "site"; + keys[1] = "google.com"; + TOML11_TEST_PARSE_EQUAL(parse_array_table_key, "[[site.\"google.com\"]]", keys); + } +} diff --git a/subprojects/toml11/tests/test_parse_unicode.cpp b/subprojects/toml11/tests/test_parse_unicode.cpp new file mode 100644 index 00000000000..8bc42539a00 --- /dev/null +++ b/subprojects/toml11/tests/test_parse_unicode.cpp @@ -0,0 +1,37 @@ +#include + +#include "unit_test.hpp" + +#include +#include + +BOOST_AUTO_TEST_CASE(test_hard_example_unicode) +{ + const auto data = toml::parse(testinput("hard_example_unicode.toml")); + + const auto the = toml::find(data, "the"); + BOOST_TEST(toml::get(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(the.at("hard")); + const std::vector expected_the_hard_test_array{"] ", " # "}; + BOOST_CHECK(toml::get>(hard.at("test_array")) == + expected_the_hard_test_array); + const std::vector expected_the_hard_test_array2{ + std::string("\x54\xC3\xA8\xC6\xA8\xC6\xAD\x20\x23\x31\x31\x20\x5D\xC6\xA5\xC5\x99\xC3\xB4\xC6\xB2\xC3\xA8\xCE\xB4\x20\xC6\xAD\xCE\xBB\xC3\xA1\xC6\xAD"), + std::string("\xC3\x89\xD0\xB6\xC6\xA5\xC3\xA8\xC5\x99\xC3\xAF\xE2\x82\xA5\xC3\xA8\xC3\xB1\xC6\xAD\x20\x23\x39\x20\xCF\x89\xC3\xA1\xC6\xA8\x20\xC3\xA1\x20\xC6\xA8\xC3\xBA\xC3\xA7\xC3\xA7\xC3\xA8\xC6\xA8\xC6\xA8") + }; + BOOST_CHECK(toml::get>(hard.at("test_array2")) == + expected_the_hard_test_array2); + BOOST_TEST(toml::get(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_TEST(toml::get(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(hard.at(std::string("\xCE\xB2\xC3\xAF\xC6\xAD\x23"))); + BOOST_TEST(toml::get(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 expected_multi_line_array{"]"}; + BOOST_CHECK(toml::get>(bit.at("multi_line_array")) == + expected_multi_line_array); +} diff --git a/subprojects/toml11/tests/test_result.cpp b/subprojects/toml11/tests/test_result.cpp new file mode 100644 index 00000000000..ad5084ca012 --- /dev/null +++ b/subprojects/toml11/tests/test_result.cpp @@ -0,0 +1,440 @@ +#include + +#include "unit_test.hpp" + +#include + +BOOST_AUTO_TEST_CASE(test_construct) +{ + { + auto s = toml::ok(42); + toml::result result(s); + 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 result(s); + BOOST_TEST(!!result); + BOOST_TEST(result.is_ok()); + BOOST_TEST(!result.is_err()); + BOOST_TEST(result.unwrap() == 42); + } + { + toml::result result(toml::ok(42)); + BOOST_TEST(!!result); + BOOST_TEST(result.is_ok()); + BOOST_TEST(!result.is_err()); + BOOST_TEST(result.unwrap() == 42); + } + + { + auto f = toml::err("foobar"); + toml::result result(f); + BOOST_TEST(!result); + BOOST_TEST(!result.is_ok()); + BOOST_TEST(result.is_err()); + BOOST_TEST(result.unwrap_err() == "foobar"); + } + { + const auto f = toml::err("foobar"); + toml::result result(f); + BOOST_TEST(!result); + BOOST_TEST(!result.is_ok()); + BOOST_TEST(result.is_err()); + BOOST_TEST(result.unwrap_err() == "foobar"); + } + { + toml::result result(toml::err("foobar")); + BOOST_TEST(!result); + BOOST_TEST(!result.is_ok()); + BOOST_TEST(result.is_err()); + BOOST_TEST(result.unwrap_err() == "foobar"); + } +} + +BOOST_AUTO_TEST_CASE(test_assignment) +{ + { + toml::result result(toml::err("foobar")); + result = toml::ok(42); + BOOST_TEST(!!result); + BOOST_TEST(result.is_ok()); + BOOST_TEST(!result.is_err()); + BOOST_TEST(result.unwrap() == 42); + } + { + toml::result result(toml::err("foobar")); + auto s = toml::ok(42); + result = s; + BOOST_TEST(!!result); + BOOST_TEST(result.is_ok()); + BOOST_TEST(!result.is_err()); + BOOST_TEST(result.unwrap() == 42); + } + { + toml::result result(toml::err("foobar")); + const auto s = toml::ok(42); + result = s; + BOOST_TEST(!!result); + BOOST_TEST(result.is_ok()); + BOOST_TEST(!result.is_err()); + BOOST_TEST(result.unwrap() == 42); + } + { + toml::result result(toml::err("foobar")); + result = toml::err("hoge"); + BOOST_TEST(!result); + BOOST_TEST(!result.is_ok()); + BOOST_TEST(result.is_err()); + BOOST_TEST(result.unwrap_err() == "hoge"); + } + { + toml::result result(toml::err("foobar")); + auto f = toml::err("hoge"); + result = f; + BOOST_TEST(!result); + BOOST_TEST(!result.is_ok()); + BOOST_TEST(result.is_err()); + BOOST_TEST(result.unwrap_err() == "hoge"); + } + { + toml::result result(toml::err("foobar")); + const auto f = toml::err("hoge"); + result = f; + BOOST_TEST(!result); + BOOST_TEST(!result.is_ok()); + BOOST_TEST(result.is_err()); + BOOST_TEST(result.unwrap_err() == "hoge"); + } +} + +BOOST_AUTO_TEST_CASE(test_map) +{ + { + const toml::result result(toml::ok(42)); + const auto mapped = result.map( + [](const int i) -> int { + return i * 2; + }); + + BOOST_TEST(!!mapped); + BOOST_TEST(mapped.is_ok()); + BOOST_TEST(!mapped.is_err()); + BOOST_TEST(mapped.unwrap() == 42 * 2); + } + { + toml::result, std::string> + result(toml::ok(std::unique_ptr(new int(42)))); + const auto mapped = std::move(result).map( + [](std::unique_ptr i) -> int { + return *i; + }); + + BOOST_TEST(!!mapped); + BOOST_TEST(mapped.is_ok()); + BOOST_TEST(!mapped.is_err()); + BOOST_TEST(mapped.unwrap() == 42); + } + { + const toml::result result(toml::err("hoge")); + const auto mapped = result.map( + [](const int i) -> int { + return i * 2; + }); + + BOOST_TEST(!mapped); + BOOST_TEST(!mapped.is_ok()); + BOOST_TEST(mapped.is_err()); + BOOST_TEST(mapped.unwrap_err() == "hoge"); + } + { + toml::result, std::string> + result(toml::err("hoge")); + const auto mapped = std::move(result).map( + [](std::unique_ptr i) -> int { + return *i; + }); + + BOOST_TEST(!mapped); + BOOST_TEST(!mapped.is_ok()); + BOOST_TEST(mapped.is_err()); + BOOST_TEST(mapped.unwrap_err() == "hoge"); + } +} + +BOOST_AUTO_TEST_CASE(test_map_err) +{ + { + const toml::result result(toml::ok(42)); + const auto mapped = result.map_err( + [](const std::string s) -> std::string { + return s + s; + }); + + BOOST_TEST(!!mapped); + BOOST_TEST(mapped.is_ok()); + BOOST_TEST(!mapped.is_err()); + BOOST_TEST(mapped.unwrap() == 42); + } + { + toml::result, std::string> + result(toml::ok(std::unique_ptr(new int(42)))); + const auto mapped = std::move(result).map_err( + [](const std::string s) -> std::string { + return s + s; + }); + + BOOST_TEST(!!mapped); + BOOST_TEST(mapped.is_ok()); + BOOST_TEST(!mapped.is_err()); + BOOST_TEST(*(mapped.unwrap()) == 42); + } + { + const toml::result result(toml::err("hoge")); + const auto mapped = result.map_err( + [](const std::string s) -> std::string { + return s + s; + }); + BOOST_TEST(!mapped); + BOOST_TEST(!mapped.is_ok()); + BOOST_TEST(mapped.is_err()); + BOOST_TEST(mapped.unwrap_err() == "hogehoge"); + } + { + toml::result> + result(toml::err(std::unique_ptr(new std::string("hoge")))); + const auto mapped = std::move(result).map_err( + [](std::unique_ptr p) -> std::string { + return *p; + }); + + BOOST_TEST(!mapped); + BOOST_TEST(!mapped.is_ok()); + BOOST_TEST(mapped.is_err()); + BOOST_TEST(mapped.unwrap_err() == "hoge"); + } +} + +BOOST_AUTO_TEST_CASE(test_map_or_else) +{ + { + const toml::result result(toml::ok(42)); + const auto mapped = result.map_or_else( + [](const int i) -> int { + return i * 2; + }, 54); + + BOOST_TEST(mapped == 42 * 2); + } + { + toml::result, std::string> + result(toml::ok(std::unique_ptr(new int(42)))); + const auto mapped = std::move(result).map_or_else( + [](std::unique_ptr i) -> int { + return *i; + }, 54); + + BOOST_TEST(mapped == 42); + } + { + const toml::result result(toml::err("hoge")); + const auto mapped = result.map_or_else( + [](const int i) -> int { + return i * 2; + }, 54); + + BOOST_TEST(mapped == 54); + } + { + toml::result, std::string> + result(toml::err("hoge")); + const auto mapped = std::move(result).map_or_else( + [](std::unique_ptr i) -> int { + return *i; + }, 54); + + BOOST_TEST(mapped == 54); + } +} + +BOOST_AUTO_TEST_CASE(test_map_err_or_else) +{ + { + const toml::result result(toml::ok(42)); + const auto mapped = result.map_err_or_else( + [](const std::string i) -> std::string { + return i + i; + }, "foobar"); + + BOOST_TEST(mapped == "foobar"); + } + { + toml::result, std::string> + result(toml::ok(std::unique_ptr(new int(42)))); + const auto mapped = std::move(result).map_err_or_else( + [](const std::string i) -> std::string { + return i + i; + }, "foobar"); + + BOOST_TEST(mapped == "foobar"); + } + { + const toml::result result(toml::err("hoge")); + const auto mapped = result.map_err_or_else( + [](const std::string i) -> std::string { + return i + i; + }, "foobar"); + + BOOST_TEST(mapped == "hogehoge"); + } + { + toml::result, std::string> + result(toml::err("hoge")); + const auto mapped = result.map_err_or_else( + [](const std::string i) -> std::string { + return i + i; + }, "foobar"); + + BOOST_TEST(mapped == "hogehoge"); + } +} + + +BOOST_AUTO_TEST_CASE(test_and_then) +{ + { + const toml::result result(toml::ok(42)); + const auto mapped = result.and_then( + [](const int i) -> toml::result { + return toml::ok(i * 2); + }); + + BOOST_TEST(!!mapped); + BOOST_TEST(mapped.is_ok()); + BOOST_TEST(!mapped.is_err()); + BOOST_TEST(mapped.unwrap() == 42 * 2); + } + { + toml::result, std::string> + result(toml::ok(std::unique_ptr(new int(42)))); + const auto mapped = std::move(result).and_then( + [](std::unique_ptr i) -> toml::result { + return toml::ok(*i); + }); + + BOOST_TEST(!!mapped); + BOOST_TEST(mapped.is_ok()); + BOOST_TEST(!mapped.is_err()); + BOOST_TEST(mapped.unwrap() == 42); + } + { + const toml::result result(toml::err("hoge")); + const auto mapped = result.and_then( + [](const int i) -> toml::result { + return toml::ok(i * 2); + }); + + BOOST_TEST(!mapped); + BOOST_TEST(!mapped.is_ok()); + BOOST_TEST(mapped.is_err()); + BOOST_TEST(mapped.unwrap_err() == "hoge"); + } + { + toml::result, std::string> + result(toml::err("hoge")); + const auto mapped = std::move(result).and_then( + [](std::unique_ptr i) -> toml::result { + return toml::ok(*i); + }); + + BOOST_TEST(!mapped); + BOOST_TEST(!mapped.is_ok()); + BOOST_TEST(mapped.is_err()); + BOOST_TEST(mapped.unwrap_err() == "hoge"); + } +} + +BOOST_AUTO_TEST_CASE(test_or_else) +{ + { + const toml::result result(toml::ok(42)); + const auto mapped = result.or_else( + [](const std::string& s) -> toml::result { + return toml::err(s + s); + }); + + BOOST_TEST(!!mapped); + BOOST_TEST(mapped.is_ok()); + BOOST_TEST(!mapped.is_err()); + BOOST_TEST(mapped.unwrap() == 42); + } + { + toml::result, std::string> + result(toml::ok(std::unique_ptr(new int(42)))); + const auto mapped = std::move(result).or_else( + [](const std::string& s) -> toml::result, std::string> { + return toml::err(s + s); + }); + + BOOST_TEST(!!mapped); + BOOST_TEST(mapped.is_ok()); + BOOST_TEST(!mapped.is_err()); + BOOST_TEST(*mapped.unwrap() == 42); + } + { + const toml::result result(toml::err("hoge")); + const auto mapped = result.or_else( + [](const std::string& s) -> toml::result { + return toml::err(s + s); + }); + + BOOST_TEST(!mapped); + BOOST_TEST(!mapped.is_ok()); + BOOST_TEST(mapped.is_err()); + BOOST_TEST(mapped.unwrap_err() == "hogehoge"); + } + { + toml::result, std::string> + result(toml::err("hoge")); + const auto mapped = std::move(result).or_else( + [](const std::string& s) -> toml::result, std::string> { + return toml::err(s + s); + }); + + BOOST_TEST(!mapped); + BOOST_TEST(!mapped.is_ok()); + BOOST_TEST(mapped.is_err()); + BOOST_TEST(mapped.unwrap_err() == "hogehoge"); + } +} + +BOOST_AUTO_TEST_CASE(test_and_or_other) +{ + { + const toml::result r1(toml::ok(42)); + const toml::result r2(toml::err("foo")); + + 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 { + return toml::ok(42); + }; + auto r2_gen = []() -> toml::result { + return toml::err("foo"); + }; + const auto r3 = r1_gen(); + const auto r4 = r2_gen(); + + 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()); + } +} diff --git a/subprojects/toml11/tests/test_serialize_file.cpp b/subprojects/toml11/tests/test_serialize_file.cpp new file mode 100644 index 00000000000..40cb484eaec --- /dev/null +++ b/subprojects/toml11/tests/test_serialize_file.cpp @@ -0,0 +1,405 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include +#include + +#include + +template class Table, + template class Array> +bool has_comment_inside(const toml::basic_value& 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) +{ + const auto data = toml::parse(testinput("example.toml")); + { + std::ofstream ofs("tmp1.toml"); + ofs << std::setw(80) << data; + } + + auto serialized = toml::parse("tmp1.toml"); + { + auto& owner = toml::find(serialized, "owner"); + auto& bio = toml::find(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_map_dq) +{ + const auto data = toml::parse( + testinput("example.toml")); + { + std::ofstream ofs("tmp1_map_dq.toml"); + ofs << std::setw(80) << data; + } + + auto serialized = toml::parse( + "tmp1_map_dq.toml"); + { + auto& owner = toml::find(serialized, "owner"); + auto& bio = toml::find(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(testinput("example.toml")); + { + std::ofstream ofs("tmp1_com.toml"); + ofs << std::setw(80) << data; + } + + auto serialized = toml::parse("tmp1_com.toml"); + { + auto& owner = toml::find(serialized, "owner"); + auto& bio = toml::find(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(testinput("example.toml")); + { + std::ofstream ofs("tmp1_com_nocomment.toml"); + ofs << std::setw(80) << toml::nocomment << data; + } + const auto serialized = toml::parse("tmp1_com_nocomment.toml"); + // check no comment exist + BOOST_TEST(!has_comment_inside(serialized)); + } + { + const auto data_nocomment = toml::parse(testinput("example.toml")); + auto serialized = toml::parse("tmp1_com_nocomment.toml"); + { + auto& owner = toml::find(serialized, "owner"); + auto& bio = toml::find(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( + testinput("example.toml")); + { + std::ofstream ofs("tmp1_com_map_dq.toml"); + ofs << std::setw(80) << data; + } + + auto serialized = toml::parse( + "tmp1_com_map_dq.toml"); + { + auto& owner = toml::find(serialized, "owner"); + auto& bio = toml::find(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(testinput("example.toml")); + { + std::ofstream ofs("tmp1_com_map_dq_nocomment.toml"); + ofs << std::setw(80) << toml::nocomment << data; + } + const auto serialized = toml::parse("tmp1_com_map_dq_nocomment.toml"); + BOOST_TEST(!has_comment_inside(serialized)); + } + { + const auto data_nocomment = toml::parse(testinput("example.toml")); + auto serialized = toml::parse("tmp1_com_map_dq_nocomment.toml"); + { + auto& owner = toml::find(serialized, "owner"); + auto& bio = toml::find(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) +{ + const auto data = toml::parse(testinput("fruit.toml")); + { + std::ofstream ofs("tmp2.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse("tmp2.toml"); + BOOST_TEST(data == serialized); +} + +BOOST_AUTO_TEST_CASE(test_fruit_map_dq) +{ + const auto data = toml::parse( + testinput("fruit.toml")); + { + std::ofstream ofs("tmp2.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse( + "tmp2.toml"); + BOOST_TEST(data == serialized); +} + +BOOST_AUTO_TEST_CASE(test_fruit_with_comments) +{ + const auto data = toml::parse(testinput("fruit.toml")); + { + std::ofstream ofs("tmp2_com.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse("tmp2_com.toml"); + BOOST_TEST(data == serialized); +} + +BOOST_AUTO_TEST_CASE(test_fruit_with_comments_map_dq) +{ + const auto data = toml::parse( + testinput("fruit.toml")); + { + std::ofstream ofs("tmp2_com.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse("tmp2_com.toml"); + BOOST_TEST(data == serialized); +} + +BOOST_AUTO_TEST_CASE(test_hard_example) +{ + const auto data = toml::parse(testinput("hard_example.toml")); + { + std::ofstream ofs("tmp3.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse("tmp3.toml"); + BOOST_TEST(data == serialized); +} + +BOOST_AUTO_TEST_CASE(test_hard_example_map_dq) +{ + const auto data = toml::parse( + testinput("hard_example.toml")); + { + std::ofstream ofs("tmp3.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse( + "tmp3.toml"); + BOOST_TEST(data == serialized); +} + +BOOST_AUTO_TEST_CASE(test_hard_example_with_comment) +{ + const auto data = toml::parse( + testinput("hard_example.toml")); + { + std::ofstream ofs("tmp3_com.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse( + "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(iss); + const auto serialized = toml::format(data, /*width = */ 0); + + std::istringstream reparse(serialized); + const auto parsed = toml::parse(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)"); +} + + +BOOST_AUTO_TEST_CASE(test_serialize_under_locale) +{ + // avoid null init (setlocale returns null when it failed) + std::string setloc(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")) + { + setloc = std::string(try_hyphen); + } + else if(const char* try_nohyphen = std::setlocale(LC_ALL, "fr_FR.utf8")) + { + setloc = std::string(try_nohyphen); + } + // In some envs, fr_FR locale has not been installed. Tests must work even in such a case. +// else +// { +// BOOST_TEST(false); +// } + BOOST_TEST_MESSAGE("current locale at the beginning of the test = " << setloc); + + const std::string str = R"( +pi = 3.14159 +large_int = 1234567890 +)"; + std::istringstream iss(str); + const auto ref = toml::parse(iss); + const auto serialized_str = toml::format(ref, /*width = */ 80); + + BOOST_TEST_MESSAGE("serialized = " << serialized_str); + + std::istringstream serialized_iss(serialized_str); + const auto serialized_ref = toml::parse(serialized_iss); + + BOOST_TEST(serialized_ref.at("pi").as_floating() == ref.at("pi").as_floating()); + BOOST_TEST(serialized_ref.at("large_int").as_integer() == ref.at("large_int").as_integer()); + + const std::string endloc(std::setlocale(LC_ALL, nullptr)); + BOOST_TEST_MESSAGE("current locale at the end of the test = " << endloc); + // check if serializer change global locale + BOOST_TEST(setloc == endloc); +} diff --git a/subprojects/toml11/tests/test_string.cpp b/subprojects/toml11/tests/test_string.cpp new file mode 100644 index 00000000000..e3f093a19be --- /dev/null +++ b/subprojects/toml11/tests/test_string.cpp @@ -0,0 +1,153 @@ +#include + +#include "unit_test.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"); + } + + +} diff --git a/subprojects/toml11/tests/test_traits.cpp b/subprojects/toml11/tests/test_traits.cpp new file mode 100644 index 00000000000..4d5e3e227a1 --- /dev/null +++ b/subprojects/toml11/tests/test_traits.cpp @@ -0,0 +1,79 @@ +#include + +#include "unit_test.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct dummy_type{}; + +template +struct dummy_container +{ + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef value_type const* const_pointer; + typedef value_type const& const_reference; + typedef pointer iterator; + typedef const_pointer const_iterator; +}; + +typedef std::array std_array_type; +typedef std::map std_map_type; +typedef std::unordered_map std_unordered_map_type; + +BOOST_AUTO_TEST_CASE(test_has_xxx) +{ + BOOST_TEST(toml::detail::has_iterator>::value); + BOOST_TEST(toml::detail::has_iterator>::value); + BOOST_TEST(toml::detail::has_iterator>::value); + BOOST_TEST(toml::detail::has_iterator>::value); + BOOST_TEST(toml::detail::has_iterator>::value); + BOOST_TEST(toml::detail::has_iterator>::value); + BOOST_TEST(toml::detail::has_iterator::value); + BOOST_TEST(toml::detail::has_iterator::value); + BOOST_TEST(toml::detail::has_iterator::value); + BOOST_TEST(toml::detail::has_iterator>::value); + + BOOST_TEST(toml::detail::has_value_type>::value); + BOOST_TEST(toml::detail::has_value_type>::value); + BOOST_TEST(toml::detail::has_value_type>::value); + BOOST_TEST(toml::detail::has_value_type>::value); + BOOST_TEST(toml::detail::has_value_type::value); + BOOST_TEST(toml::detail::has_value_type>::value); + BOOST_TEST(toml::detail::has_value_type>::value); + BOOST_TEST(toml::detail::has_value_type::value); + BOOST_TEST(toml::detail::has_value_type::value); + BOOST_TEST(toml::detail::has_value_type>::value); + + BOOST_TEST(toml::detail::has_key_type::value); + BOOST_TEST(toml::detail::has_key_type::value); + BOOST_TEST(toml::detail::has_mapped_type::value); + BOOST_TEST(toml::detail::has_mapped_type::value); +} + +BOOST_AUTO_TEST_CASE(test_is_xxx) +{ + BOOST_TEST(toml::detail::is_container>::value); + BOOST_TEST(toml::detail::is_container>::value); + BOOST_TEST(toml::detail::is_container>::value); + BOOST_TEST(toml::detail::is_container>::value); + BOOST_TEST(toml::detail::is_container::value); + BOOST_TEST(toml::detail::is_container>::value); + BOOST_TEST(toml::detail::is_container>::value); + BOOST_TEST(toml::detail::is_container>::value); + + BOOST_TEST(!toml::detail::is_container::value); + BOOST_TEST(!toml::detail::is_container::value); + + BOOST_TEST(toml::detail::is_map::value); + BOOST_TEST(toml::detail::is_map::value); +} diff --git a/subprojects/toml11/tests/test_utility.cpp b/subprojects/toml11/tests/test_utility.cpp new file mode 100644 index 00000000000..c67e3b84766 --- /dev/null +++ b/subprojects/toml11/tests/test_utility.cpp @@ -0,0 +1,45 @@ +#include + +#include "unit_test.hpp" + +#include +#include + +BOOST_AUTO_TEST_CASE(test_try_reserve) +{ + { + // since BOOST_TEST is a macro, it cannot handle commas correctly. + // When toml::detail::has_reserve_method>::value + // is passed to a macro, C preprocessor considers + // toml::detail::has_reserve_method>::value as the second argument. We need an alias to avoid + // this problem. + using reservable_type = std::vector ; + using nonreservable_type = std::array; + BOOST_TEST( toml::detail::has_reserve_method::value); + BOOST_TEST(!toml::detail::has_reserve_method::value); + } + { + std::vector v; + 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_TEST(cat == "foobar42"); +} + +BOOST_AUTO_TEST_CASE(test_from_string) +{ + { + const std::string str("123"); + BOOST_TEST(toml::from_string(str, 0) == 123); + } + { + const std::string str("01"); + BOOST_TEST(toml::from_string(str, 0) == 1); + } +} diff --git a/subprojects/toml11/tests/test_value.cpp b/subprojects/toml11/tests/test_value.cpp new file mode 100644 index 00000000000..296d34396ee --- /dev/null +++ b/subprojects/toml11/tests/test_value.cpp @@ -0,0 +1,1015 @@ +#include + +#include "unit_test.hpp" + +#include +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L +#include +#endif + + +BOOST_AUTO_TEST_CASE(test_value_boolean) +{ + toml::value v1(true); + toml::value v2(false); + + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v2.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v2.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v2.is_boolean()); + + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v2.cast() == false); + BOOST_TEST(v1.as_boolean() == true); + BOOST_TEST(v2.as_boolean() == false); + BOOST_TEST(v1.as_boolean(std::nothrow) == true); + BOOST_TEST(v2.as_boolean(std::nothrow) == false); + + v1 = false; + v2 = true; + + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v2.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v2.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v2.is_boolean()); + + BOOST_TEST(v1.cast() == false); + BOOST_TEST(v2.cast() == true); + BOOST_TEST(v1.as_boolean() == false); + BOOST_TEST(v2.as_boolean() == true); + + toml::value v3(v1); + toml::value v4(v2); + BOOST_TEST(v3 == v1); + BOOST_TEST(v4 == v2); + + BOOST_TEST(v3.type() == toml::value_t::boolean); + BOOST_TEST(v4.type() == toml::value_t::boolean); + BOOST_TEST(v3.is(toml::value_t::boolean)); + BOOST_TEST(v4.is(toml::value_t::boolean)); + BOOST_TEST(v3.is()); + BOOST_TEST(v4.is()); + BOOST_TEST(v3.is_boolean()); + BOOST_TEST(v4.is_boolean()); + + BOOST_TEST(v3.cast() == false); + BOOST_TEST(v4.cast() == true); + BOOST_TEST(v3.as_boolean() == false); + BOOST_TEST(v4.as_boolean() == true); + + toml::value v5(std::move(v1)); + toml::value v6(std::move(v2)); + + BOOST_TEST(v5.type() == toml::value_t::boolean); + BOOST_TEST(v6.type() == toml::value_t::boolean); + BOOST_TEST(v5.is(toml::value_t::boolean)); + BOOST_TEST(v6.is(toml::value_t::boolean)); + BOOST_TEST(v5.is()); + BOOST_TEST(v6.is()); + BOOST_TEST(v3.is_boolean()); + BOOST_TEST(v4.is_boolean()); + + BOOST_TEST(v5.cast() == false); + BOOST_TEST(v6.cast() == true); + BOOST_TEST(v5.as_boolean() == false); + BOOST_TEST(v6.as_boolean() == true); + + v1 = 42; + v2 = 3.14; + + BOOST_TEST(v1.type() == toml::value_t::integer); + BOOST_TEST(v2.type() == toml::value_t::floating); + BOOST_TEST(v1.is(toml::value_t::integer)); + BOOST_TEST(v2.is(toml::value_t::floating)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_integer()); + BOOST_TEST(v2.is_floating()); + + BOOST_TEST(v1.cast() == 42); + BOOST_TEST(v2.cast() == 3.14); + BOOST_TEST(v1.as_integer() == 42); + BOOST_TEST(v2.as_floating() == 3.14); +} + +BOOST_AUTO_TEST_CASE(test_value_integer) +{ + toml::value v1(-42); + toml::value v2(42u); + + BOOST_TEST(v1.type() == toml::value_t::integer); + BOOST_TEST(v2.type() == toml::value_t::integer); + BOOST_TEST(v1.is(toml::value_t::integer)); + BOOST_TEST(v2.is(toml::value_t::integer)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_integer()); + BOOST_TEST(v2.is_integer()); + + BOOST_TEST(v1.cast() == -42); + BOOST_TEST(v2.cast() == 42u); + BOOST_TEST(v1.as_integer() == -42); + BOOST_TEST(v2.as_integer() == 42u); + BOOST_TEST(v1.as_integer(std::nothrow) == -42); + BOOST_TEST(v2.as_integer(std::nothrow) == 42u); + + v1 = 54; + v2 = -54; + + BOOST_TEST(v1.type() == toml::value_t::integer); + BOOST_TEST(v2.type() == toml::value_t::integer); + BOOST_TEST(v1.is(toml::value_t::integer)); + BOOST_TEST(v2.is(toml::value_t::integer)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_integer()); + BOOST_TEST(v2.is_integer()); + + BOOST_TEST(v1.cast() == 54); + BOOST_TEST(v2.cast() == -54); + BOOST_TEST(v1.as_integer() == 54); + BOOST_TEST(v2.as_integer() == -54); + + toml::value v3(v1); + toml::value v4(v2); + BOOST_TEST(v3 == v1); + BOOST_TEST(v4 == v2); + + BOOST_TEST(v3.type() == toml::value_t::integer); + BOOST_TEST(v4.type() == toml::value_t::integer); + BOOST_TEST(v3.is(toml::value_t::integer)); + BOOST_TEST(v4.is(toml::value_t::integer)); + BOOST_TEST(v3.is()); + BOOST_TEST(v4.is()); + BOOST_TEST(v3.is_integer()); + BOOST_TEST(v4.is_integer()); + + BOOST_TEST(v3.cast() == 54); + BOOST_TEST(v4.cast() == -54); + BOOST_TEST(v3.as_integer() == 54); + BOOST_TEST(v4.as_integer() == -54); + + toml::value v5(std::move(v1)); + toml::value v6(std::move(v2)); + + BOOST_TEST(v5.type() == toml::value_t::integer); + BOOST_TEST(v6.type() == toml::value_t::integer); + BOOST_TEST(v5.is(toml::value_t::integer)); + BOOST_TEST(v6.is(toml::value_t::integer)); + BOOST_TEST(v5.is()); + BOOST_TEST(v6.is()); + BOOST_TEST(v5.is_integer()); + BOOST_TEST(v6.is_integer()); + + BOOST_TEST(v5.cast() == 54); + BOOST_TEST(v6.cast() == -54); + BOOST_TEST(v5.as_integer() == 54); + BOOST_TEST(v6.as_integer() == -54); + + v1 = true; + v2 = false; + + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v2.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v2.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v2.is_boolean()); + + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v2.cast() == false); + BOOST_TEST(v1.as_boolean() == true); + BOOST_TEST(v2.as_boolean() == false); +} + +BOOST_AUTO_TEST_CASE(test_value_float) +{ + toml::value v1(3.14); + toml::value v2(3.14f); + + BOOST_TEST(v1.type() == toml::value_t::floating); + BOOST_TEST(v2.type() == toml::value_t::floating); + BOOST_TEST(v1.is(toml::value_t::floating)); + BOOST_TEST(v2.is(toml::value_t::floating)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_floating()); + BOOST_TEST(v2.is_floating()); + + BOOST_TEST(v1.cast() == 3.14); + BOOST_TEST(v2.cast() == 3.14, + boost::test_tools::tolerance(1e-2)); + BOOST_TEST(v1.as_floating() == 3.14); + BOOST_TEST(v2.as_floating() == 3.14, + boost::test_tools::tolerance(1e-2)); + BOOST_TEST(v1.as_floating(std::nothrow) == 3.14); + BOOST_TEST(v2.as_floating(std::nothrow) == 3.14, + boost::test_tools::tolerance(1e-2)); + + v1 = 2.718f; + v2 = 2.718; + + BOOST_TEST(v1.type() == toml::value_t::floating); + BOOST_TEST(v2.type() == toml::value_t::floating); + BOOST_TEST(v1.is(toml::value_t::floating)); + BOOST_TEST(v2.is(toml::value_t::floating)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_floating()); + BOOST_TEST(v2.is_floating()); + + BOOST_TEST(v1.cast() == 2.718, + boost::test_tools::tolerance(1e-3)); + BOOST_TEST(v2.cast() == 2.718); + BOOST_TEST(v1.as_floating() == 2.718, + boost::test_tools::tolerance(1e-3)); + BOOST_TEST(v2.as_floating() == 2.718); + + toml::value v3(v1); + toml::value v4(v2); + BOOST_TEST(v3 == v1); + BOOST_TEST(v4 == v2); + + BOOST_TEST(v3.type() == toml::value_t::floating); + BOOST_TEST(v4.type() == toml::value_t::floating); + BOOST_TEST(v3.is(toml::value_t::floating)); + BOOST_TEST(v4.is(toml::value_t::floating)); + BOOST_TEST(v3.is()); + BOOST_TEST(v4.is()); + BOOST_TEST(v3.is_floating()); + BOOST_TEST(v4.is_floating()); + + BOOST_TEST(v3.cast() == 2.718, + boost::test_tools::tolerance(1e-3)); + BOOST_TEST(v4.cast() == 2.718); + BOOST_TEST(v3.as_floating() == 2.718, + boost::test_tools::tolerance(1e-3)); + BOOST_TEST(v4.as_floating() == 2.718); + + toml::value v5(std::move(v1)); + toml::value v6(std::move(v2)); + + BOOST_TEST(v5.type() == toml::value_t::floating); + BOOST_TEST(v6.type() == toml::value_t::floating); + BOOST_TEST(v5.is(toml::value_t::floating)); + BOOST_TEST(v6.is(toml::value_t::floating)); + BOOST_TEST(v5.is()); + BOOST_TEST(v6.is()); + BOOST_TEST(v5.is_floating()); + BOOST_TEST(v6.is_floating()); + + BOOST_TEST(v5.cast() == 2.718, + boost::test_tools::tolerance(1e-3)); + BOOST_TEST(v6.cast() == 2.718); + BOOST_TEST(v5.as_floating() == 2.718, + boost::test_tools::tolerance(1e-3)); + BOOST_TEST(v6.as_floating() == 2.718); + + v1 = true; + v2 = false; + + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v2.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v2.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v2.is_boolean()); + + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v2.cast() == false); + BOOST_TEST(v1.as_boolean() == true); + BOOST_TEST(v2.as_boolean() == false); +} + +BOOST_AUTO_TEST_CASE(test_value_string) +{ + toml::value v1(std::string("foo")); + toml::value v2(std::string("foo"), toml::string_t::literal); + toml::value v3("foo"); + + BOOST_TEST(v1.type() == toml::value_t::string); + BOOST_TEST(v2.type() == toml::value_t::string); + BOOST_TEST(v3.type() == toml::value_t::string); + BOOST_TEST(v1.is(toml::value_t::string)); + BOOST_TEST(v2.is(toml::value_t::string)); + BOOST_TEST(v3.is(toml::value_t::string)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v3.is()); + BOOST_TEST(v1.is_string()); + BOOST_TEST(v2.is_string()); + BOOST_TEST(v3.is_string()); + + BOOST_TEST(v1.cast() == "foo"); + BOOST_TEST(v2.cast() == "foo"); + BOOST_TEST(v3.cast() == "foo"); + BOOST_TEST(v1.as_string() == "foo"); + BOOST_TEST(v2.as_string() == "foo"); + BOOST_TEST(v3.as_string() == "foo"); + BOOST_TEST(v1.as_string(std::nothrow) == "foo"); + BOOST_TEST(v2.as_string(std::nothrow) == "foo"); + BOOST_TEST(v3.as_string(std::nothrow) == "foo"); + + v1 = "bar"; + v2 = "bar"; + v3 = "bar"; + + BOOST_TEST(v1.type() == toml::value_t::string); + BOOST_TEST(v2.type() == toml::value_t::string); + BOOST_TEST(v3.type() == toml::value_t::string); + BOOST_TEST(v1.is(toml::value_t::string)); + BOOST_TEST(v2.is(toml::value_t::string)); + BOOST_TEST(v3.is(toml::value_t::string)); + BOOST_TEST(v1.is_string()); + BOOST_TEST(v2.is_string()); + BOOST_TEST(v3.is_string()); + + BOOST_TEST(v1.cast() == "bar"); + BOOST_TEST(v2.cast() == "bar"); + BOOST_TEST(v3.cast() == "bar"); + BOOST_TEST(v1.as_string() == "bar"); + BOOST_TEST(v2.as_string() == "bar"); + BOOST_TEST(v3.as_string() == "bar"); + + + toml::value v4(v1); + toml::value v5(v2); + toml::value v6(v3); + BOOST_TEST(v4 == v1); + BOOST_TEST(v5 == v2); + BOOST_TEST(v6 == v3); + + BOOST_TEST(v4.type() == toml::value_t::string); + BOOST_TEST(v5.type() == toml::value_t::string); + BOOST_TEST(v6.type() == toml::value_t::string); + BOOST_TEST(v4.is(toml::value_t::string)); + BOOST_TEST(v5.is(toml::value_t::string)); + BOOST_TEST(v6.is(toml::value_t::string)); + BOOST_TEST(v4.is()); + BOOST_TEST(v5.is()); + BOOST_TEST(v6.is()); + BOOST_TEST(v4.is_string()); + BOOST_TEST(v5.is_string()); + BOOST_TEST(v6.is_string()); + + BOOST_TEST(v4.cast() == "bar"); + BOOST_TEST(v5.cast() == "bar"); + BOOST_TEST(v6.cast() == "bar"); + BOOST_TEST(v4.as_string() == "bar"); + BOOST_TEST(v5.as_string() == "bar"); + BOOST_TEST(v6.as_string() == "bar"); + + + v4.cast().str.at(2) = 'z'; + v5.cast().str.at(2) = 'z'; + v6.cast().str.at(2) = 'z'; + + BOOST_TEST(v4.type() == toml::value_t::string); + BOOST_TEST(v5.type() == toml::value_t::string); + BOOST_TEST(v6.type() == toml::value_t::string); + BOOST_TEST(v4.is(toml::value_t::string)); + BOOST_TEST(v5.is(toml::value_t::string)); + BOOST_TEST(v6.is(toml::value_t::string)); + BOOST_TEST(v4.is()); + BOOST_TEST(v5.is()); + BOOST_TEST(v6.is()); + BOOST_TEST(v4.is_string()); + BOOST_TEST(v5.is_string()); + BOOST_TEST(v6.is_string()); + + BOOST_TEST(v4.as_string() == "baz"); + BOOST_TEST(v5.as_string() == "baz"); + BOOST_TEST(v6.as_string() == "baz"); + + v1 = true; + v2 = true; + v3 = true; + + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v2.type() == toml::value_t::boolean); + BOOST_TEST(v3.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v2.is(toml::value_t::boolean)); + BOOST_TEST(v3.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v3.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v2.is_boolean()); + BOOST_TEST(v3.is_boolean()); + + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v2.cast() == true); + BOOST_TEST(v3.cast() == true); + BOOST_TEST(v1.as_boolean() == true); + BOOST_TEST(v2.as_boolean() == true); + BOOST_TEST(v3.as_boolean() == true); + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L + std::string_view sv = "foo"; + + toml::value v7(sv); + toml::value v8(sv, toml::string_t::literal); + + BOOST_TEST(v7.type() == toml::value_t::string); + BOOST_TEST(v8.type() == toml::value_t::string); + BOOST_TEST(v7.is(toml::value_t::string)); + BOOST_TEST(v8.is(toml::value_t::string)); + BOOST_TEST(v7.is()); + BOOST_TEST(v8.is()); + BOOST_TEST(v7.is_string()); + BOOST_TEST(v8.is_string()); + + BOOST_TEST(v7.cast() == "foo"); + BOOST_TEST(v8.cast() == "foo"); +#endif +} + +BOOST_AUTO_TEST_CASE(test_value_local_date) +{ + toml::value v1(toml::local_date(2018, toml::month_t::Jan, 31)); + + BOOST_TEST(v1.type() == toml::value_t::local_date); + BOOST_TEST(v1.is(toml::value_t::local_date)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_local_date()); + + BOOST_TEST(v1.cast() == + toml::local_date(2018, toml::month_t::Jan, 31)); + BOOST_TEST(v1.as_local_date() == + toml::local_date(2018, toml::month_t::Jan, 31)); + BOOST_TEST(v1.as_local_date(std::nothrow) == + toml::local_date(2018, toml::month_t::Jan, 31)); + + v1 = toml::local_date(2018, toml::month_t::Apr, 1); + + BOOST_TEST(v1.type() == toml::value_t::local_date); + BOOST_TEST(v1.is(toml::value_t::local_date)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_local_date()); + + BOOST_TEST(v1.cast() == + toml::local_date(2018, toml::month_t::Apr, 1)); + BOOST_TEST(v1.as_local_date() == + toml::local_date(2018, toml::month_t::Apr, 1)); + + toml::value v2(v1); + BOOST_TEST(v2 == v1); + + BOOST_TEST(v2.type() == toml::value_t::local_date); + BOOST_TEST(v2.is(toml::value_t::local_date)); + BOOST_TEST(v2.is()); + BOOST_TEST(v2.is_local_date()); + + BOOST_TEST(v2.cast() == + toml::local_date(2018, toml::month_t::Apr, 1)); + BOOST_TEST(v2.as_local_date() == + toml::local_date(2018, toml::month_t::Apr, 1)); + + v1 = true; + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v1.as_boolean() == true); +} + +BOOST_AUTO_TEST_CASE(test_value_local_time) +{ + toml::value v1(toml::local_time(12, 30, 45)); + toml::value v2(std::chrono::hours(12) + std::chrono::minutes(30) + + std::chrono::seconds(45)); + + BOOST_TEST(v1.type() == toml::value_t::local_time); + BOOST_TEST(v2.type() == toml::value_t::local_time); + BOOST_TEST(v1.is(toml::value_t::local_time)); + BOOST_TEST(v2.is(toml::value_t::local_time)); + BOOST_TEST(v1.is()); + BOOST_TEST(v2.is()); + BOOST_TEST(v1.is_local_time()); + BOOST_TEST(v2.is_local_time()); + + BOOST_TEST(v1.cast() == + toml::local_time(12, 30, 45)); + BOOST_TEST(v1.as_local_time() == + toml::local_time(12, 30, 45)); + + BOOST_TEST(v2.cast() == + toml::local_time(12, 30, 45)); + BOOST_TEST(v2.as_local_time() == + toml::local_time(12, 30, 45)); + + BOOST_TEST(v1.cast() == + v2.cast()); + BOOST_TEST(v1.as_local_time() == + v2.as_local_time()); + BOOST_TEST(v1.as_local_time(std::nothrow) == + v2.as_local_time(std::nothrow)); + + v1 = toml::local_time(1, 30, 0, /*ms*/ 100, /*us*/ 0); + + BOOST_TEST(v1.type() == toml::value_t::local_time); + BOOST_TEST(v1.is(toml::value_t::local_time)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_local_time()); + BOOST_TEST(v1.cast() == + toml::local_time(1, 30, 0, 100, 0)); + BOOST_TEST(v1.as_local_time() == + toml::local_time(1, 30, 0, 100, 0)); + + toml::value v3(v1); + BOOST_TEST(v3 == v1); + + BOOST_TEST(v3.type() == toml::value_t::local_time); + BOOST_TEST(v3.is(toml::value_t::local_time)); + BOOST_TEST(v3.is()); + BOOST_TEST(v3.is_local_time()); + + BOOST_TEST(v3.cast() == + toml::local_time(1, 30, 0, 100, 0)); + BOOST_TEST(v3.as_local_time() == + toml::local_time(1, 30, 0, 100, 0)); + + v1 = true; + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v1.as_boolean() == true); +} + +BOOST_AUTO_TEST_CASE(test_value_local_datetime) +{ + toml::value v1(toml::local_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45) + )); + + BOOST_TEST(v1.type() == toml::value_t::local_datetime); + BOOST_TEST(v1.is(toml::value_t::local_datetime)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_local_datetime()); + + BOOST_TEST(v1.cast() == + toml::local_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45))); + BOOST_TEST(v1.as_local_datetime() == + toml::local_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45))); + BOOST_TEST(v1.as_local_datetime(std::nothrow) == + toml::local_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45))); + + + v1 = toml::local_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30)); + + BOOST_TEST(v1.type() == toml::value_t::local_datetime); + BOOST_TEST(v1.is(toml::value_t::local_datetime)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_local_datetime()); + + BOOST_TEST(v1.cast() == + toml::local_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30))); + BOOST_TEST(v1.as_local_datetime() == + toml::local_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30))); + + toml::value v2(v1); + BOOST_TEST(v2 == v1); + + BOOST_TEST(v2.type() == toml::value_t::local_datetime); + BOOST_TEST(v2.is(toml::value_t::local_datetime)); + BOOST_TEST(v2.is()); + BOOST_TEST(v2.is_local_datetime()); + + BOOST_TEST(v2.cast() == + toml::local_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30))); + BOOST_TEST(v2.as_local_datetime() == + toml::local_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30))); + + + v1 = true; + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v1.as_boolean() == true); +} + +BOOST_AUTO_TEST_CASE(test_value_offset_datetime) +{ + toml::value v1(toml::offset_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45), + toml::time_offset(9, 0) + )); + + BOOST_TEST(v1.type() == toml::value_t::offset_datetime); + BOOST_TEST(v1.is(toml::value_t::offset_datetime)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_offset_datetime()); + + BOOST_TEST(v1.cast() == + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45), + toml::time_offset(9, 0) + )); + BOOST_TEST(v1.as_offset_datetime() == + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45), + toml::time_offset(9, 0) + )); + BOOST_TEST(v1.as_offset_datetime(std::nothrow) == + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45), + toml::time_offset(9, 0) + )); + + + v1 = toml::offset_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30), + toml::time_offset(9, 0)); + + BOOST_TEST(v1.type() == toml::value_t::offset_datetime); + BOOST_TEST(v1.is(toml::value_t::offset_datetime)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_offset_datetime()); + + BOOST_TEST(v1.cast() == + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30), + toml::time_offset(9, 0))); + BOOST_TEST(v1.as_offset_datetime() == + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30), + toml::time_offset(9, 0))); + + + toml::value v2(v1); + BOOST_TEST(v2 == v1); + + BOOST_TEST(v2.type() == toml::value_t::offset_datetime); + BOOST_TEST(v2.is(toml::value_t::offset_datetime)); + BOOST_TEST(v2.is()); + BOOST_TEST(v2.is_offset_datetime()); + + BOOST_TEST(v2.cast() == + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30), + toml::time_offset(9, 0))); + BOOST_TEST(v2.as_offset_datetime() == + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30), + toml::time_offset(9, 0))); + + v1 = true; + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v1.as_boolean() == true); +} + +BOOST_AUTO_TEST_CASE(test_value_array) +{ + std::vector v{1,2,3,4,5}; + toml::value v1(v); + toml::value v2{6,7,8,9,0}; + + BOOST_TEST(v1.type() == toml::value_t::array); + BOOST_TEST(v1.is(toml::value_t::array)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_array()); + + BOOST_TEST(v2.type() == toml::value_t::array); + BOOST_TEST(v2.is(toml::value_t::array)); + BOOST_TEST(v2.is()); + BOOST_TEST(v2.is_array()); + + BOOST_TEST(v1.cast().at(0).cast() == 1); + BOOST_TEST(v1.cast().at(1).cast() == 2); + BOOST_TEST(v1.cast().at(2).cast() == 3); + BOOST_TEST(v1.cast().at(3).cast() == 4); + BOOST_TEST(v1.cast().at(4).cast() == 5); + BOOST_TEST(v1.as_array().at(0).as_integer() == 1); + BOOST_TEST(v1.as_array().at(1).as_integer() == 2); + BOOST_TEST(v1.as_array().at(2).as_integer() == 3); + BOOST_TEST(v1.as_array().at(3).as_integer() == 4); + BOOST_TEST(v1.as_array().at(4).as_integer() == 5); + BOOST_TEST(v1.as_array(std::nothrow).at(0).as_integer() == 1); + BOOST_TEST(v1.as_array(std::nothrow).at(1).as_integer() == 2); + BOOST_TEST(v1.as_array(std::nothrow).at(2).as_integer() == 3); + BOOST_TEST(v1.as_array(std::nothrow).at(3).as_integer() == 4); + BOOST_TEST(v1.as_array(std::nothrow).at(4).as_integer() == 5); + + BOOST_TEST(v2.cast().at(0).cast() == 6); + BOOST_TEST(v2.cast().at(1).cast() == 7); + BOOST_TEST(v2.cast().at(2).cast() == 8); + BOOST_TEST(v2.cast().at(3).cast() == 9); + BOOST_TEST(v2.cast().at(4).cast() == 0); + + v1 = {6,7,8,9,0}; + v2 = v; + + BOOST_TEST(v1.type() == toml::value_t::array); + BOOST_TEST(v1.is(toml::value_t::array)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_array()); + + BOOST_TEST(v2.type() == toml::value_t::array); + BOOST_TEST(v2.is(toml::value_t::array)); + BOOST_TEST(v2.is()); + BOOST_TEST(v2.is_array()); + + BOOST_TEST(v1.cast().at(0).cast() == 6); + BOOST_TEST(v1.cast().at(1).cast() == 7); + BOOST_TEST(v1.cast().at(2).cast() == 8); + BOOST_TEST(v1.cast().at(3).cast() == 9); + BOOST_TEST(v1.cast().at(4).cast() == 0); + BOOST_TEST(v1.as_array().at(0).as_integer() == 6); + BOOST_TEST(v1.as_array().at(1).as_integer() == 7); + BOOST_TEST(v1.as_array().at(2).as_integer() == 8); + BOOST_TEST(v1.as_array().at(3).as_integer() == 9); + BOOST_TEST(v1.as_array().at(4).as_integer() == 0); + + + BOOST_TEST(v2.cast().at(0).cast() == 1); + BOOST_TEST(v2.cast().at(1).cast() == 2); + BOOST_TEST(v2.cast().at(2).cast() == 3); + BOOST_TEST(v2.cast().at(3).cast() == 4); + BOOST_TEST(v2.cast().at(4).cast() == 5); + BOOST_TEST(v2.as_array().at(0).as_integer() == 1); + BOOST_TEST(v2.as_array().at(1).as_integer() == 2); + BOOST_TEST(v2.as_array().at(2).as_integer() == 3); + BOOST_TEST(v2.as_array().at(3).as_integer() == 4); + BOOST_TEST(v2.as_array().at(4).as_integer() == 5); + + + toml::value v3(v1); + BOOST_TEST(v3 == v1); + + BOOST_TEST(v3.type() == toml::value_t::array); + BOOST_TEST(v3.is(toml::value_t::array)); + BOOST_TEST(v3.is()); + BOOST_TEST(v3.is_array()); + + BOOST_TEST(v3.cast().at(0).cast() == 6); + BOOST_TEST(v3.cast().at(1).cast() == 7); + BOOST_TEST(v3.cast().at(2).cast() == 8); + BOOST_TEST(v3.cast().at(3).cast() == 9); + BOOST_TEST(v3.cast().at(4).cast() == 0); + BOOST_TEST(v3.as_array().at(0).as_integer() == 6); + BOOST_TEST(v3.as_array().at(1).as_integer() == 7); + BOOST_TEST(v3.as_array().at(2).as_integer() == 8); + BOOST_TEST(v3.as_array().at(3).as_integer() == 9); + BOOST_TEST(v3.as_array().at(4).as_integer() == 0); + + + v1 = true; + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v1.as_boolean() == true); +} + +BOOST_AUTO_TEST_CASE(test_value_table) +{ + toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}}; + + BOOST_TEST(v1.type() == toml::value_t::table); + BOOST_TEST(v1.is(toml::value_t::table)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_table()); + + BOOST_TEST(v1.cast().at("foo").cast() == 42); + BOOST_TEST(v1.cast().at("bar").cast() == 3.14); + BOOST_TEST(v1.cast().at("baz").cast().str == "qux"); + BOOST_TEST(v1.as_table().at("foo").as_integer() == 42); + BOOST_TEST(v1.as_table().at("bar").as_floating() == 3.14); + BOOST_TEST(v1.as_table().at("baz").as_string().str == "qux"); + BOOST_TEST(v1.as_table(std::nothrow).at("foo").as_integer() == 42); + BOOST_TEST(v1.as_table(std::nothrow).at("bar").as_floating() == 3.14); + BOOST_TEST(v1.as_table(std::nothrow).at("baz").as_string().str == "qux"); + + v1 = {{"foo", 2.71}, {"bar", 54}, {"baz", "quux"}}; + + BOOST_TEST(v1.type() == toml::value_t::table); + BOOST_TEST(v1.is(toml::value_t::table)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_table()); + + BOOST_TEST(v1.cast().at("foo").cast() == 2.71); + BOOST_TEST(v1.cast().at("bar").cast() == 54); + BOOST_TEST(v1.cast().at("baz").cast().str == "quux"); + BOOST_TEST(v1.as_table().at("foo").as_floating() == 2.71); + BOOST_TEST(v1.as_table().at("bar").as_integer() == 54); + BOOST_TEST(v1.as_table().at("baz").as_string().str == "quux"); + + v1 = toml::table{{"foo", 2.71}, {"bar", 54}, {"baz", "quux"}}; + + BOOST_TEST(v1.type() == toml::value_t::table); + BOOST_TEST(v1.is(toml::value_t::table)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_table()); + + BOOST_TEST(v1.cast().at("foo").cast() == 2.71); + BOOST_TEST(v1.cast().at("bar").cast() == 54); + BOOST_TEST(v1.cast().at("baz").cast().str == "quux"); + BOOST_TEST(v1.as_table().at("foo").as_floating() == 2.71); + BOOST_TEST(v1.as_table().at("bar").as_integer() == 54); + BOOST_TEST(v1.as_table().at("baz").as_string().str == "quux"); + + toml::value v3(v1); + BOOST_TEST(v3 == v1); + + BOOST_TEST(v3.type() == toml::value_t::table); + BOOST_TEST(v3.is(toml::value_t::table)); + BOOST_TEST(v3.is()); + BOOST_TEST(v3.is_table()); + + BOOST_TEST(v3.cast().at("foo").cast() == 2.71); + BOOST_TEST(v3.cast().at("bar").cast() == 54); + BOOST_TEST(v3.cast().at("baz").cast().str == "quux"); + BOOST_TEST(v3.as_table().at("foo").as_floating() == 2.71); + BOOST_TEST(v3.as_table().at("bar").as_integer() == 54); + BOOST_TEST(v3.as_table().at("baz").as_string().str == "quux"); + + + v1 = true; + BOOST_TEST(v1.type() == toml::value_t::boolean); + BOOST_TEST(v1.is(toml::value_t::boolean)); + BOOST_TEST(v1.is()); + BOOST_TEST(v1.is_boolean()); + BOOST_TEST(v1.cast() == true); + BOOST_TEST(v1.as_boolean() == true); +} + +BOOST_AUTO_TEST_CASE(test_value_empty) +{ + toml::value v1; + BOOST_TEST(v1.is_uninitialized()); + BOOST_TEST(v1.is(toml::value_t::empty)); + + BOOST_CHECK_THROW(v1.as_boolean(), toml::type_error); + BOOST_CHECK_THROW(v1.as_integer(), toml::type_error); + BOOST_CHECK_THROW(v1.as_floating(), toml::type_error); + BOOST_CHECK_THROW(v1.as_string(), toml::type_error); + BOOST_CHECK_THROW(v1.as_offset_datetime(), toml::type_error); + BOOST_CHECK_THROW(v1.as_local_datetime(), toml::type_error); + BOOST_CHECK_THROW(v1.as_local_date(), toml::type_error); + BOOST_CHECK_THROW(v1.as_local_time(), toml::type_error); + BOOST_CHECK_THROW(v1.as_array(), toml::type_error); + BOOST_CHECK_THROW(v1.as_table(), toml::type_error); +} + + +BOOST_AUTO_TEST_CASE(test_value_at) +{ + { + toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}}; + + BOOST_TEST(v1.at("foo").as_integer() == 42); + BOOST_TEST(v1.at("bar").as_floating() == 3.14); + BOOST_TEST(v1.at("baz").as_string() == "qux"); + + BOOST_CHECK_THROW(v1.at(0), toml::type_error); + BOOST_CHECK_THROW(v1.at("quux"), std::out_of_range); + } + + + { + toml::value v1{1,2,3,4,5}; + + BOOST_TEST(v1.at(0).as_integer() == 1); + BOOST_TEST(v1.at(1).as_integer() == 2); + BOOST_TEST(v1.at(2).as_integer() == 3); + BOOST_TEST(v1.at(3).as_integer() == 4); + BOOST_TEST(v1.at(4).as_integer() == 5); + + BOOST_CHECK_THROW(v1.at("foo"), toml::type_error); + BOOST_CHECK_THROW(v1.at(5), std::out_of_range); + } +} + +BOOST_AUTO_TEST_CASE(test_value_bracket) +{ + { + toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}}; + + BOOST_TEST(v1["foo"].as_integer() == 42); + BOOST_TEST(v1["bar"].as_floating() == 3.14); + BOOST_TEST(v1["baz"].as_string() == "qux"); + + v1["qux"] = 54; + BOOST_TEST(v1["qux"].as_integer() == 54); + } + { + toml::value v1; + v1["foo"] = 42; + + BOOST_TEST(v1.is_table()); + BOOST_TEST(v1["foo"].as_integer() == 42); + } + { + toml::value v1{1,2,3,4,5}; + + BOOST_TEST(v1[0].as_integer() == 1); + BOOST_TEST(v1[1].as_integer() == 2); + BOOST_TEST(v1[2].as_integer() == 3); + BOOST_TEST(v1[3].as_integer() == 4); + BOOST_TEST(v1[4].as_integer() == 5); + + BOOST_CHECK_THROW(v1["foo"], toml::type_error); + } +} + +BOOST_AUTO_TEST_CASE(test_value_map_methods) +{ + { + toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}}; + + BOOST_TEST(v1.count("foo") == 1u); + BOOST_TEST(v1.count("bar") == 1u); + BOOST_TEST(v1.count("baz") == 1u); + BOOST_TEST(v1.count("qux") == 0u); + + BOOST_TEST( v1.contains("foo")); + BOOST_TEST( v1.contains("bar")); + BOOST_TEST( v1.contains("baz")); + BOOST_TEST(!v1.contains("qux")); + + BOOST_TEST(v1.size() == 3); + + v1["qux"] = 54; + BOOST_TEST(v1.count("qux") == 1u); + BOOST_TEST(v1.contains("qux")); + BOOST_TEST(v1.size() == 4); + } + { + toml::value v1(42); + BOOST_CHECK_THROW(v1.size() , toml::type_error); + BOOST_CHECK_THROW(v1.count("k") , toml::type_error); + BOOST_CHECK_THROW(v1.contains("k"), toml::type_error); + } +} + +BOOST_AUTO_TEST_CASE(test_value_vector_methods) +{ + { + toml::value v1{1, 2, 3, 4, 5}; + + BOOST_TEST(v1.size() == 5); + + v1.push_back(6); + BOOST_TEST(v1.size() == 6); + + v1.emplace_back(6); + BOOST_TEST(v1.size() == 7); + } + { + toml::value v1(42); + BOOST_CHECK_THROW(v1.size(), toml::type_error); + BOOST_CHECK_THROW(v1.push_back(1), toml::type_error); + BOOST_CHECK_THROW(v1.emplace_back(1), toml::type_error); + } +} diff --git a/subprojects/toml11/tests/test_windows.cpp b/subprojects/toml11/tests/test_windows.cpp new file mode 100644 index 00000000000..b178a26084b --- /dev/null +++ b/subprojects/toml11/tests/test_windows.cpp @@ -0,0 +1,12 @@ +#include +#include +#include + +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(data, "windows") << std::endl; + return 0; +} diff --git a/subprojects/toml11/tests/unit_test.hpp b/subprojects/toml11/tests/unit_test.hpp new file mode 100644 index 00000000000..5999f57c736 --- /dev/null +++ b/subprojects/toml11/tests/unit_test.hpp @@ -0,0 +1,23 @@ +#ifndef BOOST_TEST_MODULE +# error "Please #define BOOST_TEST_MODULE before you #include " +#endif + +#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST +# include +#else +# include +#endif + +#include +#include + +static inline auto testinput(const std::string& basename) -> std::string +{ + const auto this_or_that = [](const char *const s, const char *const t) { return s ? s : t; }; + std::string directory = this_or_that(std::getenv("TOMLDIR"), "toml"); + if (!directory.empty() && directory.back() != '/') + { + directory.push_back('/'); + } + return directory.append("tests/").append(basename); +} diff --git a/subprojects/toml11/toml.hpp b/subprojects/toml11/toml.hpp index f34cfcccaf3..e975f4e4310 100644 --- a/subprojects/toml11/toml.hpp +++ b/subprojects/toml11/toml.hpp @@ -25,17 +25,9 @@ #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 0 +#define TOML11_VERSION_MINOR 8 +#define TOML11_VERSION_PATCH 1 #include "toml/parser.hpp" #include "toml/literal.hpp" diff --git a/subprojects/toml11/toml/color.hpp b/subprojects/toml11/toml/color.hpp index 4cb572cb089..a3fd890f7fe 100644 --- a/subprojects/toml11/toml/color.hpp +++ b/subprojects/toml11/toml/color.hpp @@ -17,11 +17,41 @@ namespace color_ansi { namespace detail { + inline int colorize_index() { static const int index = std::ios_base::xalloc(); return index; } + +// Control color mode globally +class color_mode +{ + public: + inline void enable() + { + should_color_ = true; + } + inline void disable() + { + should_color_ = false; + } + + inline bool should_color() const + { + return should_color_; + } + + static color_mode& status() + { + static color_mode status_; + return status_; + } + + private: + bool should_color_ = false; +}; + } // detail inline std::ostream& colorize(std::ostream& os) @@ -55,6 +85,21 @@ 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;} + +inline void enable() +{ + return detail::color_mode::status().enable(); +} +inline void disable() +{ + return detail::color_mode::status().disable(); +} + +inline bool should_color() +{ + return detail::color_mode::status().should_color(); +} + } // color_ansi // ANSI escape sequence is the only and default colorization method currently diff --git a/subprojects/toml11/toml/comments.hpp b/subprojects/toml11/toml/comments.hpp index ec250411755..c0f66f39ec0 100644 --- a/subprojects/toml11/toml/comments.hpp +++ b/subprojects/toml11/toml/comments.hpp @@ -425,14 +425,14 @@ struct discard_comments // 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 operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");} + const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");} 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();} + reference front() noexcept {never_call("toml::discard_comment::front");} + const_reference front() const noexcept {never_call("toml::discard_comment::front");} + reference back() noexcept {never_call("toml::discard_comment::back");} + const_reference back() const noexcept {never_call("toml::discard_comment::back");} pointer data() noexcept {return nullptr;} const_pointer data() const noexcept {return nullptr;} @@ -450,6 +450,18 @@ struct discard_comments 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{};} + + private: + + [[noreturn]] static void never_call(const char *const this_function) + { +#ifdef __has_builtin +# if __has_builtin(__builtin_unreachable) + __builtin_unreachable(); +# endif +#endif + throw std::logic_error{this_function}; + } }; inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;} diff --git a/subprojects/toml11/toml/datetime.hpp b/subprojects/toml11/toml/datetime.hpp index d8127c150a9..83d04ba4f0c 100644 --- a/subprojects/toml11/toml/datetime.hpp +++ b/subprojects/toml11/toml/datetime.hpp @@ -21,34 +21,34 @@ namespace toml namespace detail { // TODO: find more sophisticated way to handle this -#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE) +#if defined(_MSC_VER) 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."); } + 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_r(src, &dst); - if (!result) { throw std::runtime_error("gmtime_r failed."); } + const auto result = ::gmtime_s(&dst, src); + if (result) { throw std::runtime_error("gmtime_s failed."); } return dst; } -#elif defined(_MSC_VER) +#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_s(&dst, src); - if (result) { throw std::runtime_error("localtime_s failed."); } + const auto result = ::localtime_r(src, &dst); + if (!result) { throw std::runtime_error("localtime_r 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."); } + const auto result = ::gmtime_r(src, &dst); + if (!result) { throw std::runtime_error("gmtime_r failed."); } return dst; } #else // fallback. not threadsafe @@ -85,9 +85,9 @@ enum class month_t : std::uint8_t struct local_date { - std::int16_t year; // A.D. (like, 2018) - std::uint8_t month; // [0, 11] - std::uint8_t day; // [1, 31] + std::int16_t year{}; // A.D. (like, 2018) + std::uint8_t month{}; // [0, 11] + std::uint8_t day{}; // [1, 31] local_date(int y, month_t m, int d) : year (static_cast(y)), @@ -181,12 +181,12 @@ operator<<(std::basic_ostream& os, const local_date& date) struct local_time { - std::uint8_t hour; // [0, 23] - std::uint8_t minute; // [0, 59] - std::uint8_t second; // [0, 60] - std::uint16_t millisecond; // [0, 999] - std::uint16_t microsecond; // [0, 999] - std::uint16_t nanosecond; // [0, 999] + std::uint8_t hour{}; // [0, 23] + std::uint8_t minute{}; // [0, 59] + std::uint8_t second{}; // [0, 60] + std::uint16_t millisecond{}; // [0, 999] + std::uint16_t microsecond{}; // [0, 999] + std::uint16_t nanosecond{}; // [0, 999] local_time(int h, int m, int s, int ms = 0, int us = 0, int ns = 0) @@ -297,8 +297,8 @@ operator<<(std::basic_ostream& os, const local_time& time) struct time_offset { - std::int8_t hour; // [-12, 12] - std::int8_t minute; // [-59, 59] + std::int8_t hour{}; // [-12, 12] + std::int8_t minute{}; // [-59, 59] time_offset(int h, int m) : hour (static_cast(h)), @@ -364,8 +364,8 @@ operator<<(std::basic_ostream& os, const time_offset& offset) struct local_datetime { - local_date date; - local_time time; + local_date date{}; + local_time time{}; local_datetime(local_date d, local_time t): date(d), time(t) {} @@ -478,9 +478,9 @@ operator<<(std::basic_ostream& os, const local_datetime& dt) struct offset_datetime { - local_date date; - local_time time; - time_offset offset; + local_date date{}; + local_time time{}; + time_offset offset{}; offset_datetime(local_date d, local_time t, time_offset o) : date(d), time(t), offset(o) diff --git a/subprojects/toml11/toml/exception.hpp b/subprojects/toml11/toml/exception.hpp index c64651d0ada..06bfe6ec91f 100644 --- a/subprojects/toml11/toml/exception.hpp +++ b/subprojects/toml11/toml/exception.hpp @@ -2,14 +2,32 @@ // Distributed under the MIT License. #ifndef TOML11_EXCEPTION_HPP #define TOML11_EXCEPTION_HPP -#include + +#include #include +#include + +#include #include "source_location.hpp" namespace toml { +struct file_io_error : public std::runtime_error +{ + public: + file_io_error(int errnum, const std::string& msg, const std::string& fname) + : std::runtime_error(msg + " \"" + fname + "\": errno = " + std::to_string(errnum)), + errno_(errnum) + {} + + int get_errno() const noexcept {return errno_;} + + private: + int errno_; +}; + struct exception : public std::exception { public: diff --git a/subprojects/toml11/toml/get.hpp b/subprojects/toml11/toml/get.hpp index d7fdf553b22..ac1b354fc72 100644 --- a/subprojects/toml11/toml/get.hpp +++ b/subprojects/toml11/toml/get.hpp @@ -215,6 +215,7 @@ template, // T is a container detail::negation>, // w/o push_back(...) + detail::negation>, // T does not have special conversion detail::negation< // not toml::array detail::is_exact_toml_type>> >::value, T> @@ -259,6 +260,11 @@ template::value, T> get(const basic_value&); +template class M, template class V> +detail::enable_if_t::value, T> +get(basic_value&); + // T(const toml::value&) and T is not toml::basic_value, // and it does not have `from` nor `from_toml`. template::value, T> get(const basic_value&); +template class M, template class V> +detail::enable_if_t>, + std::is_constructible&>, + detail::negation>, + detail::negation> + >::value, T> +get(basic_value&); + // ============================================================================ // array-like types; most likely STL container, like std::vector, etc. @@ -324,6 +340,7 @@ template, // T is a container detail::negation>, // w/o push_back + detail::negation>, // T does not have special conversion detail::negation< // T is not toml::array detail::is_exact_toml_type>> >::value, T> @@ -449,6 +466,13 @@ get(const basic_value& v) { return ::toml::from::from_toml(v); } +template class M, template class V> +detail::enable_if_t::value, T> +get(basic_value& v) +{ + return ::toml::from::from_toml(v); +} template class M, template class V> @@ -463,6 +487,19 @@ get(const basic_value& v) return T(v); } +template class M, template class V> +detail::enable_if_t>, // T is not a toml::value + std::is_constructible&>, // T is constructible from toml::value + detail::negation>, // and T does not have T.from_toml(v); + detail::negation> // and T does not have toml::from{}; + >::value, T> +get(basic_value& v) +{ + return T(v); +} + // ============================================================================ // find diff --git a/subprojects/toml11/toml/lexer.hpp b/subprojects/toml11/toml/lexer.hpp index ea5050b8dd1..2a1ff2d618d 100644 --- a/subprojects/toml11/toml/lexer.hpp +++ b/subprojects/toml11/toml/lexer.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include "combinator.hpp" @@ -133,6 +132,9 @@ using lex_escape_seq_char = either, character<'\\'>, character<'b'>, character<'f'>, character<'n'>, character<'r'>, character<'t'>, +#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES + character<'e'>, // ESC (0x1B) +#endif lex_escape_unicode_short, lex_escape_unicode_long >; @@ -261,21 +263,20 @@ using lex_array_table = sequence; using lex_utf8_2byte = sequence< - in_range(0xC2), static_cast(0xDF)>, - in_range(0x80), static_cast(0xBF)> + in_range<'\xC2', '\xDF'>, + in_range<'\x80', '\xBF'> >; using lex_utf8_3byte = sequence(0xE0)>, in_range(0xA0), static_cast(0xBF)>>, - sequence(0xE1), static_cast(0xEC)>, in_range(0x80), static_cast(0xBF)>>, - sequence(0xED)>, in_range(0x80), static_cast(0x9F)>>, - sequence(0xEE), static_cast(0xEF)>, in_range(0x80), static_cast(0xBF)>> - >, in_range(0x80), static_cast(0xBF)>>; + sequence, in_range<'\xA0', '\xBF'>>, + sequence, in_range<'\x80', '\xBF'>>, + sequence, in_range<'\x80', '\x9F'>>, + sequence, in_range<'\x80', '\xBF'>> + >, in_range<'\x80', '\xBF'>>; using lex_utf8_4byte = sequence(0xF0)>, in_range(0x90), static_cast(0xBF)>>, - sequence(0xF1), static_cast(0xF3)>, in_range(0x80), static_cast(0xBF)>>, - sequence(0xF4)>, in_range(0x80), static_cast(0x8F)>> - >, in_range(0x80), static_cast(0xBF)>, - in_range(0x80), static_cast(0xBF)>>; + sequence, in_range<'\x90', '\xBF'>>, + sequence, in_range<'\x80', '\xBF'>>, + sequence, in_range<'\x80', '\x8F'>> + >, in_range<'\x80', '\xBF'>, in_range<'\x80', '\xBF'>>; using lex_utf8_code = either< lex_utf8_1byte, lex_utf8_2byte, diff --git a/subprojects/toml11/toml/literal.hpp b/subprojects/toml11/toml/literal.hpp index 04fbbc13e18..5086a76813e 100644 --- a/subprojects/toml11/toml/literal.hpp +++ b/subprojects/toml11/toml/literal.hpp @@ -53,7 +53,7 @@ literal_internal_impl(::toml::detail::location loc) // 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(loc)) + if(auto data = ::toml::detail::parse_value(loc, 0)) { return data.unwrap(); } diff --git a/subprojects/toml11/toml/parser.hpp b/subprojects/toml11/toml/parser.hpp index e3117991811..a8553dccf24 100644 --- a/subprojects/toml11/toml/parser.hpp +++ b/subprojects/toml11/toml/parser.hpp @@ -8,6 +8,7 @@ #include "combinator.hpp" #include "lexer.hpp" +#include "macros.hpp" #include "region.hpp" #include "result.hpp" #include "types.hpp" @@ -22,6 +23,11 @@ #endif // __cpp_lib_filesystem #endif // TOML11_DISABLE_STD_FILESYSTEM +// the previous commit works with 500+ recursions. so it may be too small. +// but in most cases, i think we don't need such a deep recursion of +// arrays or inline-tables. +#define TOML11_VALUE_RECURSION_LIMIT 64 + namespace toml { namespace detail @@ -57,16 +63,55 @@ parse_binary_integer(location& loc) { auto str = token.unwrap().str(); assert(str.size() > 2); // minimum -> 0b1 + assert(str.at(0) == '0' && str.at(1) == 'b'); + + // skip all the zeros and `_` locating at the MSB + str.erase(str.begin(), std::find_if( + str.begin() + 2, // to skip prefix `0b` + str.end(), + [](const char c) { return c == '1'; }) + ); + assert(str.empty() || str.front() == '1'); + + // since toml11 uses int64_t, 64bit (unsigned) input cannot be read. + const auto max_length = 63 + std::count(str.begin(), str.end(), '_'); + if(static_cast(max_length) < str.size()) + { + loc.reset(first); + return err(format_underline("toml::parse_binary_integer: " + "only signed 64bit integer is available", + {{source_location(loc), "too large input (> int64_t)"}})); + } + integer retval(0), base(1); - for(auto i(str.rbegin()), e(str.rend() - 2); i!=e; ++i) + for(auto i(str.rbegin()), e(str.rend()); i!=e; ++i) { - if (*i == '1'){retval += base; base *= 2;} - else if(*i == '0'){base *= 2;} - else if(*i == '_'){/* do nothing. */} - else // internal error. + assert(base != 0); // means overflow, checked in the above code + if(*i == '1') + { + retval += base; + if( (std::numeric_limits::max)() / 2 < base ) + { + base = 0; + } + base *= 2; + } + else if(*i == '0') + { + if( (std::numeric_limits::max)() / 2 < base ) + { + base = 0; + } + base *= 2; + } + else if(*i == '_') + { + // do nothing. + } + else // should be detected by lex_bin_int. [[unlikely]] { throw internal_error(format_underline( - "toml::parse_integer: internal error", + "toml::parse_binary_integer: internal error", {{source_location(token.unwrap()), "invalid token"}}), source_location(loc)); } @@ -91,6 +136,21 @@ parse_octal_integer(location& loc) std::istringstream iss(str); integer retval(0); iss >> std::oct >> retval; + if(iss.fail()) + { + // `istream` sets `failbit` if internally-called `std::num_get::get` + // fails. + // `std::num_get::get` calls `std::strtoll` if the argument type is + // signed. + // `std::strtoll` fails if + // - the value is out_of_range or + // - no conversion is possible. + // since we already checked that the string is valid octal integer, + // so the error reason is out_of_range. + loc.reset(first); + return err(format_underline("toml::parse_octal_integer:", + {{source_location(loc), "out of range"}})); + } return ok(std::make_pair(retval, token.unwrap())); } loc.reset(first); @@ -111,6 +171,13 @@ parse_hexadecimal_integer(location& loc) std::istringstream iss(str); integer retval(0); iss >> std::hex >> retval; + if(iss.fail()) + { + // see parse_octal_integer for detail of this error message. + loc.reset(first); + return err(format_underline("toml::parse_hexadecimal_integer:", + {{source_location(loc), "out of range"}})); + } return ok(std::make_pair(retval, token.unwrap())); } loc.reset(first); @@ -157,6 +224,13 @@ parse_integer(location& loc) std::istringstream iss(str); integer retval(0); iss >> retval; + if(iss.fail()) + { + // see parse_octal_integer for detail of this error message. + loc.reset(first); + return err(format_underline("toml::parse_integer:", + {{source_location(loc), "out of range"}})); + } return ok(std::make_pair(retval, token.unwrap())); } loc.reset(first); @@ -245,6 +319,13 @@ parse_floating(location& loc) std::istringstream iss(str); floating v(0.0); iss >> v; + if(iss.fail()) + { + // see parse_octal_integer for detail of this error message. + loc.reset(first); + return err(format_underline("toml::parse_floating:", + {{source_location(loc), "out of range"}})); + } return ok(std::make_pair(v, token.unwrap())); } loc.reset(first); @@ -327,6 +408,9 @@ inline result parse_escape_sequence(location& loc) case 'n' :{loc.advance(); return ok(std::string("\n"));} case 'f' :{loc.advance(); return ok(std::string("\f"));} case 'r' :{loc.advance(); return ok(std::string("\r"));} +#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES + case 'e' :{loc.advance(); return ok(std::string("\x1b"));} // ESC +#endif case 'u' : { if(const auto token = lex_escape_unicode_short::invoke(loc)) @@ -522,7 +606,7 @@ parse_basic_string(location& loc) inner_loc.reset(first); inner_loc.advance(err_loc); throw syntax_error(format_underline( - "parse_ml_basic_string: invalid utf8 sequence found", + "parse_basic_string: invalid utf8 sequence found", {{source_location(inner_loc), "here"}}), source_location(inner_loc)); } @@ -542,7 +626,8 @@ parse_ml_literal_string(location& loc) const auto first = loc.iter(); if(const auto token = lex_ml_literal_string::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + auto inner_loc = loc; + inner_loc.reset(first); const auto open = lex_ml_literal_string_open::invoke(inner_loc); if(!open) @@ -598,7 +683,7 @@ parse_ml_literal_string(location& loc) inner_loc.reset(first); inner_loc.advance(err_loc); throw syntax_error(format_underline( - "parse_ml_basic_string: invalid utf8 sequence found", + "parse_ml_literal_string: invalid utf8 sequence found", {{source_location(inner_loc), "here"}}), source_location(inner_loc)); } @@ -618,7 +703,8 @@ parse_literal_string(location& loc) const auto first = loc.iter(); if(const auto token = lex_literal_string::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + auto inner_loc = loc; + inner_loc.reset(first); const auto open = lex_apostrophe::invoke(inner_loc); if(!open) @@ -652,7 +738,7 @@ parse_literal_string(location& loc) inner_loc.reset(first); inner_loc.advance(err_loc); throw syntax_error(format_underline( - "parse_ml_basic_string: invalid utf8 sequence found", + "parse_literal_string: invalid utf8 sequence found", {{source_location(inner_loc), "here"}}), source_location(inner_loc)); } @@ -709,7 +795,7 @@ parse_local_date(location& loc) if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') { throw internal_error(format_underline( - "toml::parse_inner_local_date: invalid year format", + "toml::parse_local_date: invalid year format", {{source_location(inner_loc), "should be `-`"}}), source_location(inner_loc)); } @@ -812,7 +898,7 @@ parse_local_time(location& loc) if((hour < 0 || 23 < hour) || (minute < 0 || 59 < minute) || (second < 0 || 60 < second)) // it may be leap second { - throw syntax_error(format_underline("toml::parse_time: " + throw syntax_error(format_underline("toml::parse_local_time: " "invalid time: it does not conform RFC3339.", {{ source_location(loc), "hour should be 00-23, minute should be" " 00-59, second should be 00-60 (depending on the leap" @@ -1016,7 +1102,7 @@ parse_key(location& loc) else { throw internal_error(format_underline( - "toml::detail::parse_key: dotted key contains invalid key", + "toml::parse_key: dotted key contains invalid key", {{source_location(inner_loc), k.unwrap_err()}}), source_location(inner_loc)); } @@ -1058,15 +1144,23 @@ parse_key(location& loc) // forward-decl to implement parse_array and parse_table template -result parse_value(location&); +result parse_value(location&, const std::size_t n_rec); template result, std::string> -parse_array(location& loc) +parse_array(location& loc, const std::size_t n_rec) { using value_type = Value; using array_type = typename value_type::array_type; + if(n_rec > TOML11_VALUE_RECURSION_LIMIT) + { + // parse_array does not have any way to handle recursive error currently... + throw syntax_error(std::string("toml::parse_array: recursion limit (" + TOML11_STRINGIZE(TOML11_VALUE_RECURSION_LIMIT) ") exceeded"), + source_location(loc)); + } + const auto first = loc.iter(); if(loc.iter() == loc.end()) { @@ -1093,7 +1187,7 @@ parse_array(location& loc) region(loc, first, loc.iter()))); } - if(auto val = parse_value(loc)) + if(auto val = parse_value(loc, n_rec+1)) { // After TOML v1.0.0-rc.1, array becomes to be able to have values // with different types. So here we will omit this by default. @@ -1167,7 +1261,7 @@ parse_array(location& loc) template result, region>, Value>, std::string> -parse_key_value_pair(location& loc) +parse_key_value_pair(location& loc, const std::size_t n_rec) { using value_type = Value; @@ -1214,7 +1308,7 @@ parse_key_value_pair(location& loc) } const auto after_kvsp = loc.iter(); // err msg - auto val = parse_value(loc); + auto val = parse_value(loc, n_rec); if(!val) { std::string msg; @@ -1257,9 +1351,11 @@ std::string format_dotted_keys(InputIterator first, const InputIterator last) // forward decl for is_valid_forward_table_definition result, region>, std::string> parse_table_key(location& loc); +result, region>, std::string> +parse_array_table_key(location& loc); template result, std::string> -parse_inline_table(location& loc); +parse_inline_table(location& loc, const std::size_t n_rec); // The following toml file is allowed. // ```toml @@ -1297,7 +1393,7 @@ bool is_valid_forward_table_definition(const Value& fwd, const Value& inserting, inserting_reg = ptr->str(); } location inserting_def("internal", std::move(inserting_reg)); - if(const auto inlinetable = parse_inline_table(inserting_def)) + if(const auto inlinetable = parse_inline_table(inserting_def, 0)) { // check if we are overwriting existing table. // ```toml @@ -1310,6 +1406,46 @@ bool is_valid_forward_table_definition(const Value& fwd, const Value& inserting, return false; } + // Valid and invalid cases when inserting to the [a.b] table: + // + // ## Invalid + // + // ```toml + // # invalid + // [a] + // b.c.d = "foo" + // [a.b] # a.b is already defined and closed + // d = "bar" + // ``` + // ```toml + // # invalid + // a = {b.c.d = "foo"} + // [a.b] # a is already defined and inline table is closed + // d = "bar" + // ``` + // ```toml + // # invalid + // a.b.c.d = "foo" + // [a.b] # a.b is already defined and dotted-key table is closed + // d = "bar" + // ``` + // + // ## Valid + // + // ```toml + // # OK. a.b is defined, but is *overwritable* + // [a.b.c] + // d = "foo" + // [a.b] + // d = "bar" + // ``` + // ```toml + // # OK. a.b is defined, but is *overwritable* + // [a] + // b.c.d = "foo" + // b.e = "bar" + // ``` + // ------------------------------------------------------------------------ // check table defined before @@ -1332,7 +1468,22 @@ bool is_valid_forward_table_definition(const Value& fwd, const Value& inserting, // the keys are not equivalent. it is allowed. return true; } - if(const auto dotkeys = parse_key(def)) + // nested array-of-table definition implicitly defines tables. + // those tables can be reopened. + if(const auto atabkeys = parse_array_table_key(def)) + { + // table keys always contains all the nodes from the root. + const auto& tks = atabkeys.unwrap().first; + if(std::size_t(std::distance(key_first, key_last)) == tks.size() && + std::equal(tks.begin(), tks.end(), key_first)) + { + // the keys are equivalent. it is not allowed. + return false; + } + // the keys are not equivalent. it is allowed. + return true; + } + if(const auto dotkeys = parse_key(def)) // a.b.c = "foo" { // consider the following case. // [a] @@ -1340,6 +1491,18 @@ bool is_valid_forward_table_definition(const Value& fwd, const Value& inserting, // [a.b.c] // e = 2.71 // this defines the table [a.b.c] twice. no? + if(const auto reopening_dotkey_by_table = parse_table_key(inserting_def)) + { + // re-opening a dotkey-defined table by a table is invalid. + // only dotkey can append a key-val. Like: + // ```toml + // a.b.c = "foo" + // a.b.d = "bar" # OK. reopen `a.b` by dotkey + // [a.b] + // e = "bar" # Invalid. re-opening `a.b` by [a.b] is not allowed. + // ``` + return false; + } // a dotted key starts from the node representing a table in which the // dotted key belongs to. @@ -1618,6 +1781,29 @@ insert_nested_key(typename Value::table_type& root, const Value& v, {v.location(), "inserting this"} }), v.location()); } + if(a.empty()) + { + throw syntax_error(format_underline(concat_to_string( + "toml::insert_value: table (\"", + format_dotted_keys(first, last), "\") conflicts with" + " existing value"), { + {tab->at(k).location(), std::string("this array is not insertable")}, + {v.location(), std::string("appending it to the statically sized array")} + }), v.location()); + } + if(const auto ptr = detail::get_region(a.at(0))) + { + if(ptr->str().substr(0,2) != "[[") + { + throw syntax_error(format_underline(concat_to_string( + "toml::insert_value: a table (\"", + format_dotted_keys(first, last), "\") cannot be " + "inserted to an existing inline array-of-tables"), { + {tab->at(k).location(), std::string("this array of table has a static size")}, + {v.location(), std::string("appending it to the statically sized array")} + }), v.location()); + } + } tab = std::addressof(a.back().as_table()); } else @@ -1638,11 +1824,18 @@ insert_nested_key(typename Value::table_type& root, const Value& v, template result, std::string> -parse_inline_table(location& loc) +parse_inline_table(location& loc, const std::size_t n_rec) { using value_type = Value; using table_type = typename value_type::table_type; + if(n_rec > TOML11_VALUE_RECURSION_LIMIT) + { + throw syntax_error(std::string("toml::parse_inline_table: recursion limit (" + TOML11_STRINGIZE(TOML11_VALUE_RECURSION_LIMIT) ") exceeded"), + source_location(loc)); + } + const auto first = loc.iter(); table_type retval; if(!(loc.iter() != loc.end() && *loc.iter() == '{')) @@ -1663,7 +1856,7 @@ parse_inline_table(location& loc) // it starts from "{". it should be formatted as inline-table while(loc.iter() != loc.end()) { - const auto kv_r = parse_key_value_pair(loc); + const auto kv_r = parse_key_value_pair(loc, n_rec+1); if(!kv_r) { return err(kv_r.unwrap_err()); @@ -1907,7 +2100,7 @@ parse_value_helper(result, std::string> rslt) } template -result parse_value(location& loc) +result parse_value(location& loc, const std::size_t n_rec) { const auto first = loc.iter(); if(first == loc.end()) @@ -1932,8 +2125,8 @@ result parse_value(location& loc) case value_t::local_datetime : {return parse_value_helper(parse_local_datetime(loc) );} case value_t::local_date : {return parse_value_helper(parse_local_date(loc) );} case value_t::local_time : {return parse_value_helper(parse_local_time(loc) );} - case value_t::array : {return parse_value_helper(parse_array(loc) );} - case value_t::table : {return parse_value_helper(parse_inline_table(loc));} + case value_t::array : {return parse_value_helper(parse_array(loc, n_rec));} + case value_t::table : {return parse_value_helper(parse_inline_table(loc, n_rec));} default: { const auto msg = format_underline("toml::parse_value: " @@ -2034,7 +2227,7 @@ parse_array_table_key(location& loc) if(!close) { throw internal_error(format_underline( - "toml::parse_table_key: no `]]`", + "toml::parse_array_table_key: no `]]`", {{source_location(inner_loc), "should be `]]`"}}), source_location(inner_loc)); } @@ -2098,7 +2291,7 @@ parse_ml_table(location& loc) return ok(tab); } - if(const auto kv = parse_key_value_pair(loc)) + if(const auto kv = parse_key_value_pair(loc, 0)) { const auto& kvpair = kv.unwrap(); const std::vector& keys = kvpair.first.first; @@ -2256,27 +2449,14 @@ result parse_toml_file(location& loc) return ok(Value(std::move(data), file, comments)); } -} // detail - template class Table = std::unordered_map, template class Array = std::vector> basic_value -parse(std::istream& is, const std::string& fname = "unknown file") +parse(std::vector& letters, const std::string& fname) { using value_type = basic_value; - const auto beg = is.tellg(); - is.seekg(0, std::ios::end); - const auto end = is.tellg(); - const auto fsize = end - beg; - is.seekg(beg); - - // read whole file as a sequence of char - assert(fsize >= 0); - std::vector letters(static_cast(fsize)); - is.read(letters.data(), fsize); - // append LF. // Although TOML does not require LF at the EOF, to make parsing logic // simpler, we "normalize" the content by adding LF if it does not exist. @@ -2306,25 +2486,91 @@ parse(std::istream& is, const std::string& fname = "unknown file") } } - const auto data = detail::parse_toml_file(loc); - if(!data) + if (auto data = detail::parse_toml_file(loc)) + { + return std::move(data).unwrap(); + } + else { - throw syntax_error(data.unwrap_err(), source_location(loc)); + throw syntax_error(std::move(data).unwrap_err(), source_location(loc)); } - return data.unwrap(); +} + +} // detail + +template class Table = std::unordered_map, + template class Array = std::vector> +basic_value +parse(FILE * file, const std::string& fname) +{ + const long beg = std::ftell(file); + if (beg == -1l) + { + throw file_io_error(errno, "Failed to access", fname); + } + + const int res_seekend = std::fseek(file, 0, SEEK_END); + if (res_seekend != 0) + { + throw file_io_error(errno, "Failed to seek", fname); + } + + const long end = std::ftell(file); + if (end == -1l) + { + throw file_io_error(errno, "Failed to access", fname); + } + + const auto fsize = end - beg; + + const auto res_seekbeg = std::fseek(file, beg, SEEK_SET); + if (res_seekbeg != 0) + { + throw file_io_error(errno, "Failed to seek", fname); + } + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters(static_cast(fsize)); + std::fread(letters.data(), sizeof(char), static_cast(fsize), file); + + return detail::parse(letters, fname); +} + +template class Table = std::unordered_map, + template class Array = std::vector> +basic_value +parse(std::istream& is, std::string fname = "unknown file") +{ + const auto beg = is.tellg(); + is.seekg(0, std::ios::end); + const auto end = is.tellg(); + const auto fsize = end - beg; + is.seekg(beg); + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters(static_cast(fsize)); + is.read(letters.data(), fsize); + + return detail::parse(letters, fname); } template class Table = std::unordered_map, template class Array = std::vector> -basic_value parse(const std::string& fname) +basic_value parse(std::string fname) { - std::ifstream ifs(fname.c_str(), std::ios_base::binary); + std::ifstream ifs(fname, std::ios_base::binary); if(!ifs.good()) { - throw std::runtime_error("toml::parse: file open error -> " + fname); + throw std::ios_base::failure( + "toml::parse: Error opening file \"" + fname + "\""); } - return parse(ifs, fname); + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + return parse(ifs, std::move(fname)); } #ifdef TOML11_HAS_STD_FILESYSTEM @@ -2353,9 +2599,10 @@ basic_value parse(const std::filesystem::path& fpath) std::ifstream ifs(fpath, std::ios_base::binary); if(!ifs.good()) { - throw std::runtime_error("toml::parse: file open error -> " + - fpath.string()); + throw std::ios_base::failure( + "toml::parse: Error opening file \"" + fpath.string() + "\""); } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); return parse(ifs, fpath.string()); } #endif // TOML11_HAS_STD_FILESYSTEM diff --git a/subprojects/toml11/toml/region.hpp b/subprojects/toml11/toml/region.hpp index 2e01e51d086..72a6f11e999 100644 --- a/subprojects/toml11/toml/region.hpp +++ b/subprojects/toml11/toml/region.hpp @@ -70,7 +70,7 @@ struct region_base struct location final : public region_base { using const_iterator = typename std::vector::const_iterator; - using difference_type = typename const_iterator::difference_type; + using difference_type = typename std::iterator_traits::difference_type; using source_ptr = std::shared_ptr>; location(std::string source_name, std::vector cont) @@ -92,7 +92,7 @@ struct location final : public region_base char front() const noexcept override {return *iter_;} // this const prohibits codes like `++(loc.iter())`. - const const_iterator iter() const noexcept {return iter_;} + std::add_const::type iter() const noexcept {return iter_;} const_iterator begin() const noexcept {return source_->cbegin();} const_iterator end() const noexcept {return source_->cend();} @@ -227,8 +227,7 @@ struct region final : public region_base region& operator+=(const region& other) { // different regions cannot be concatenated - assert(this->begin() == other.begin() && this->end() == other.end() && - this->last_ == other.first_); + assert(this->source_ == other.source_ && this->last_ == other.first_); this->last_ = other.last_; return *this; diff --git a/subprojects/toml11/toml/serializer.hpp b/subprojects/toml11/toml/serializer.hpp index 88ae775a83d..23fb89a6d05 100644 --- a/subprojects/toml11/toml/serializer.hpp +++ b/subprojects/toml11/toml/serializer.hpp @@ -7,6 +7,14 @@ #include +#if defined(_WIN32) +#include +#elif defined(__APPLE__) || defined(__FreeBSD__) +#include +#elif defined(__linux__) +#include +#endif + #include "lexer.hpp" #include "value.hpp" @@ -55,7 +63,19 @@ format_key(const std::basic_string& k) case '\f': {serialized += "\\f"; break;} case '\n': {serialized += "\\n"; break;} case '\r': {serialized += "\\r"; break;} - default : {serialized += c; break;} + default: { + if (c >= 0x00 && c < 0x20) + { + std::array buf; + std::snprintf(buf.data(), buf.size(), "\\u00%02x", static_cast(c)); + serialized += buf.data(); + } + else + { + serialized += c; + } + break; + } } } serialized += "\""; @@ -120,7 +140,31 @@ struct serializer } std::string operator()(const integer_type i) const { - return std::to_string(i); +#if defined(_WIN32) + _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + const std::string original_locale(setlocale(LC_NUMERIC, nullptr)); + setlocale(LC_NUMERIC, "C"); +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__) + const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0)); + locale_t original_locale(0); + if(c_locale != locale_t(0)) + { + original_locale = uselocale(c_locale); + } +#endif + + const auto str = std::to_string(i); + +#if defined(_WIN32) + setlocale(LC_NUMERIC, original_locale.c_str()); + _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__) + if(original_locale != locale_t(0)) + { + uselocale(original_locale); + } +#endif + return str; } std::string operator()(const floating_type f) const { @@ -147,12 +191,40 @@ struct serializer } } + // set locale to "C". + // To make it thread-local, we use OS-specific features. + // If we set process-global locale, it can break other thread that also + // outputs something simultaneously. +#if defined(_WIN32) + _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + const std::string original_locale(setlocale(LC_NUMERIC, nullptr)); + setlocale(LC_NUMERIC, "C"); +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__) + const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0)); + locale_t original_locale(0); + if(c_locale != locale_t(0)) + { + original_locale = uselocale(c_locale); + } +#endif + const auto fmt = "%.*g"; const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f); // +1 for null character(\0) std::vector buf(static_cast(bsz + 1), '\0'); std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f); + // restore the original locale +#if defined(_WIN32) + setlocale(LC_NUMERIC, original_locale.c_str()); + _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__) + if(original_locale != locale_t(0)) + { + uselocale(original_locale); + } +#endif + std::string token(buf.begin(), std::prev(buf.end())); if(!token.empty() && token.back() == '.') // 1. => 1.0 { diff --git a/subprojects/toml11/toml/source_location.hpp b/subprojects/toml11/toml/source_location.hpp index fa175b5b48d..135024fe191 100644 --- a/subprojects/toml11/toml/source_location.hpp +++ b/subprojects/toml11/toml/source_location.hpp @@ -125,7 +125,7 @@ inline std::string format_underline(const std::string& message, std::ostringstream retval; - if(colorize) + if(color::should_color() || colorize) { retval << color::colorize; // turn on ANSI color } @@ -137,12 +137,18 @@ inline std::string format_underline(const std::string& message, // 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 + retval +#ifndef TOML11_NO_ERROR_PREFIX + << color::bold << color::red << "[error]" << color::reset +#endif << color::bold << message.substr(7) << color::reset << '\n'; } else { - retval << color::bold << color::red << "[error] " << color::reset + retval +#ifndef TOML11_NO_ERROR_PREFIX + << color::bold << color::red << "[error] " << color::reset +#endif << color::bold << message << color::reset << '\n'; } diff --git a/subprojects/toml11/toml/string.hpp b/subprojects/toml11/toml/string.hpp index 5136d8c568c..def3e57c38d 100644 --- a/subprojects/toml11/toml/string.hpp +++ b/subprojects/toml11/toml/string.hpp @@ -2,12 +2,15 @@ // Distributed under the MIT License. #ifndef TOML11_STRING_HPP #define TOML11_STRING_HPP + +#include "version.hpp" + #include #include #include -#if __cplusplus >= 201703L +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L #if __has_include() #define TOML11_USING_STRING_VIEW 1 #include diff --git a/subprojects/toml11/toml/traits.hpp b/subprojects/toml11/toml/traits.hpp index 5495c93b244..255d9e888c0 100644 --- a/subprojects/toml11/toml/traits.hpp +++ b/subprojects/toml11/toml/traits.hpp @@ -5,6 +5,7 @@ #include "from.hpp" #include "into.hpp" +#include "version.hpp" #include #include @@ -13,7 +14,7 @@ #include #include -#if __cplusplus >= 201703L +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L #if __has_include() #include #endif // has_include() @@ -146,7 +147,7 @@ struct has_specialized_into : decltype(has_specialized_into_impl::check(nullp // --------------------------------------------------------------------------- // C++17 and/or/not -#if __cplusplus >= 201703L +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L using std::conjunction; using std::disjunction; @@ -208,7 +209,7 @@ template struct is_container : conjunction< negation>, // not a map negation>, // not a std::string -#if __cplusplus >= 201703L +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L #if __has_include() negation>, // not a std::string_view #endif // has_include() @@ -233,7 +234,7 @@ struct is_basic_value<::toml::basic_value>: std::true_type{}; // --------------------------------------------------------------------------- // C++14 index_sequence -#if __cplusplus >= 201402L +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L using std::index_sequence; using std::make_index_sequence; @@ -263,12 +264,12 @@ struct index_sequence_maker<0> template using make_index_sequence = typename index_sequence_maker::type; -#endif // __cplusplus >= 2014 +#endif // cplusplus >= 2014 // --------------------------------------------------------------------------- // C++14 enable_if_t -#if __cplusplus >= 201402L +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L using std::enable_if_t; @@ -277,12 +278,12 @@ using std::enable_if_t; template using enable_if_t = typename std::enable_if::type; -#endif // __cplusplus >= 2014 +#endif // cplusplus >= 2014 // --------------------------------------------------------------------------- // return_type_of_t -#if __cplusplus >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703 +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703 template using return_type_of_t = std::invoke_result_t; diff --git a/subprojects/toml11/toml/utility.hpp b/subprojects/toml11/toml/utility.hpp index 4a6b4309d7f..53a18b944a3 100644 --- a/subprojects/toml11/toml/utility.hpp +++ b/subprojects/toml11/toml/utility.hpp @@ -7,8 +7,9 @@ #include #include "traits.hpp" +#include "version.hpp" -#if __cplusplus >= 201402L +#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))) @@ -21,7 +22,7 @@ namespace toml { -#if __cplusplus >= 201402L +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L using std::make_unique; @@ -33,7 +34,7 @@ inline std::unique_ptr make_unique(Ts&& ... args) return std::unique_ptr(new T(std::forward(args)...)); } -#endif // __cplusplus >= 2014 +#endif // TOML11_CPLUSPLUS_STANDARD_VERSION >= 2014 namespace detail { @@ -91,7 +92,7 @@ T from_string(const std::string& str, T opt) namespace detail { -#if __cplusplus >= 201402L +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L template decltype(auto) last_one(T&& tail) noexcept { diff --git a/subprojects/toml11/toml/value.hpp b/subprojects/toml11/toml/value.hpp index 1b43db8d4c7..d57ab8080dd 100644 --- a/subprojects/toml11/toml/value.hpp +++ b/subprojects/toml11/toml/value.hpp @@ -247,6 +247,7 @@ class basic_value } basic_value& operator=(const basic_value& v) { + if(this == std::addressof(v)) {return *this;} this->cleanup(); this->region_info_ = v.region_info_; this->comments_ = v.comments_; @@ -269,6 +270,7 @@ class basic_value } basic_value& operator=(basic_value&& v) { + if(this == std::addressof(v)) {return *this;} this->cleanup(); this->region_info_ = std::move(v.region_info_); this->comments_ = std::move(v.comments_); @@ -1712,9 +1714,9 @@ class basic_value { switch(this->type_) { - case value_t::string : {string_.~string(); return;} - case value_t::array : {array_.~array_storage(); return;} - case value_t::table : {table_.~table_storage(); return;} + case value_t::string : {string_.~string(); return;} + case value_t::array : {array_.~array_storage(); return;} + case value_t::table : {table_.~table_storage(); return;} default : return; } } diff --git a/subprojects/toml11/toml/version.hpp b/subprojects/toml11/toml/version.hpp new file mode 100644 index 00000000000..9cbfa39be00 --- /dev/null +++ b/subprojects/toml11/toml/version.hpp @@ -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 From 857fa958e1030e80ffacd40a63ee8f8ed1dc8765 Mon Sep 17 00:00:00 2001 From: polar Date: Tue, 26 Mar 2024 15:44:16 +0000 Subject: [PATCH 3/3] fixed build --- package.nix | 2 ++ src/libexpr/primops/fromTOML.cc | 2 +- subprojects/toml11/toml/string.hpp | 2 +- subprojects/toml11/toml/traits.hpp | 2 +- subprojects/toml11/toml/utility.hpp | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package.nix b/package.nix index 7d9a39771ee..a05a9fb88eb 100644 --- a/package.nix +++ b/package.nix @@ -172,6 +172,7 @@ in { ./doc ./misc ./precompiled-headers.h + ./subprojects/toml11 ./src ./COPYING ./scripts/local.mk @@ -182,6 +183,7 @@ in { # Source might not be compiled, but still must be available # for Doxygen to gather comments. ./src + ./subprojects/toml11 ./tests/unit ] ++ lib.optionals buildUnitTests [ ./tests/unit diff --git a/src/libexpr/primops/fromTOML.cc b/src/libexpr/primops/fromTOML.cc index 94be7960a06..13909fd59f4 100644 --- a/src/libexpr/primops/fromTOML.cc +++ b/src/libexpr/primops/fromTOML.cc @@ -1,7 +1,7 @@ #include "primops.hh" #include "eval-inline.hh" -#include "../../toml11/toml.hpp" +#include "../../../subprojects/toml11/toml.hpp" #include diff --git a/subprojects/toml11/toml/string.hpp b/subprojects/toml11/toml/string.hpp index def3e57c38d..82318d4901b 100644 --- a/subprojects/toml11/toml/string.hpp +++ b/subprojects/toml11/toml/string.hpp @@ -3,7 +3,7 @@ #ifndef TOML11_STRING_HPP #define TOML11_STRING_HPP -#include "version.hpp" +// #include "version.hpp" #include diff --git a/subprojects/toml11/toml/traits.hpp b/subprojects/toml11/toml/traits.hpp index 255d9e888c0..0768fac92af 100644 --- a/subprojects/toml11/toml/traits.hpp +++ b/subprojects/toml11/toml/traits.hpp @@ -5,7 +5,7 @@ #include "from.hpp" #include "into.hpp" -#include "version.hpp" +// #include "version.hpp" #include #include diff --git a/subprojects/toml11/toml/utility.hpp b/subprojects/toml11/toml/utility.hpp index 53a18b944a3..fb9bf21607e 100644 --- a/subprojects/toml11/toml/utility.hpp +++ b/subprojects/toml11/toml/utility.hpp @@ -7,7 +7,7 @@ #include #include "traits.hpp" -#include "version.hpp" +// #include "version.hpp" #if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L # define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]