diff --git a/include/toml11/fwd/error_info_fwd.hpp b/include/toml11/fwd/error_info_fwd.hpp index 5d30b86..5b8600c 100644 --- a/include/toml11/fwd/error_info_fwd.hpp +++ b/include/toml11/fwd/error_info_fwd.hpp @@ -41,6 +41,10 @@ struct error_info std::string suffix_; // hint or something like that }; +// forward decl +template +class basic_value; + namespace detail { inline error_info make_error_info_rec(error_info e) @@ -53,6 +57,10 @@ inline error_info make_error_info_rec(error_info e, std::string s) return e; } +template +error_info make_error_info_rec(error_info e, + const basic_value& v, std::string msg, Ts&& ... tail); + template error_info make_error_info_rec(error_info e, source_location loc, std::string msg, Ts&& ... tail) diff --git a/include/toml11/value.hpp b/include/toml11/value.hpp index fe1720d..6139ad9 100644 --- a/include/toml11/value.hpp +++ b/include/toml11/value.hpp @@ -2026,12 +2026,16 @@ operator>=(const basic_value& lhs, const basic_value& rhs) } // error_info helper +namespace detail +{ template error_info make_error_info_rec(error_info e, const basic_value& v, std::string msg, Ts&& ... tail) { return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward(tail)...); } +} // detail + template error_info make_error_info( std::string title, const basic_value& v, std::string msg, Ts&& ... tail) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3ca04aa..d95901e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,7 @@ set(TOML11_TEST_NAMES test_comments test_datetime + test_error_message test_find test_find_or test_format_integer diff --git a/tests/test_error_message.cpp b/tests/test_error_message.cpp new file mode 100644 index 0000000..567dc4a --- /dev/null +++ b/tests/test_error_message.cpp @@ -0,0 +1,79 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" + +#include + +TEST_CASE("testing custom error message using source_location") +{ + const toml::value root = toml::parse_str(R"( + range = [0, 42] + val = 54 + )"); + + const auto& lower = root.at("range").at(0); + const auto& upper = root.at("range").at(1); + const auto& val = root.at("val"); + + const auto err = toml::make_error_info("val not in range", + lower.location(), "lower limit is defined here", + upper.location(), "upper limit is defined here", + val.location(), "this is not in the range", + "Hint: upper limit is inclusive" + ); + + CHECK_EQ(err.title(), "val not in range"); + CHECK_EQ(err.locations().size(), 3); + CHECK_EQ(err.locations().at(0).second, "lower limit is defined here"); + CHECK_EQ(err.locations().at(1).second, "upper limit is defined here"); + CHECK_EQ(err.locations().at(2).second, "this is not in the range" ); +} + +TEST_CASE("testing custom error message using value") +{ + const toml::value root = toml::parse_str(R"( + range = [0, 42] + val = 54 + )"); + + const auto& lower = root.at("range").at(0); + const auto& upper = root.at("range").at(1); + const auto& val = root.at("val"); + + const auto err = toml::make_error_info("val not in range", + lower, "lower limit is defined here", + upper, "upper limit is defined here", + val, "this is not in the range", + "Hint: upper limit is inclusive" + ); + + CHECK_EQ(err.title(), "val not in range"); + CHECK_EQ(err.locations().size(), 3); + CHECK_EQ(err.locations().at(0).second, "lower limit is defined here"); + CHECK_EQ(err.locations().at(1).second, "upper limit is defined here"); + CHECK_EQ(err.locations().at(2).second, "this is not in the range" ); +} + +TEST_CASE("testing custom error message using source_location and value") +{ + const toml::value root = toml::parse_str(R"( + range = [0, 42] + val = 54 + )"); + + const auto& lower = root.at("range").at(0); + const auto& upper = root.at("range").at(1); + const auto& val = root.at("val"); + + const auto err = toml::make_error_info("val not in range", + lower, "lower limit is defined here", + upper, "upper limit is defined here", + val.location(), "this is not in the range", + "Hint: upper limit is inclusive" + ); + + CHECK_EQ(err.title(), "val not in range"); + CHECK_EQ(err.locations().size(), 3); + CHECK_EQ(err.locations().at(0).second, "lower limit is defined here"); + CHECK_EQ(err.locations().at(1).second, "upper limit is defined here"); + CHECK_EQ(err.locations().at(2).second, "this is not in the range" ); +}