tomlplusplus/tests/tests.h
Mark Gillard 2219fd22bb release 0.1.0
- added `toml::is_number<>`
- added `toml::node_type::none`
- added initializer_list and vector relops to `toml::array`
- added constructors for `time_offset` and `date_time`
- added much to `node_view`
- added tests for `node_view` value relops
- added lots more documentation
- removed `time_offset::from_hh_mm`
- removed the handling of `\s` literals (looks like it's not going be accepted as-is)
2020-02-20 23:33:32 +02:00

229 lines
5.4 KiB
C++

#pragma once
#define TOML_UNDEF_MACROS 0
#include "../include/toml++/toml.h"
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
#include "catch2.h"
#include <sstream>
using namespace toml;
using namespace Catch::literals;
TOML_POP_WARNINGS
#define S(str) TOML_STRING_PREFIX(str)
template <typename CHAR, typename FUNC>
void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func, std::string_view source_path = {}) noexcept
{
constexpr auto validate_table = [](table&& tabl, std::string_view path) noexcept -> table&&
{
CHECK(tabl.source().begin != source_position{});
CHECK(tabl.source().end != source_position{});
if (path.empty())
CHECK(tabl.source().path == nullptr);
else
{
REQUIRE(tabl.source().path != nullptr);
CHECK(*tabl.source().path == path);
}
return std::move(tabl);
};
#if TOML_EXCEPTIONS
try
{
std::forward<FUNC>(func)(validate_table(toml::parse(toml_str, source_path), source_path));
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), toml_str.length());
std::forward<FUNC>(func)(validate_table(toml::parse(ss, source_path), source_path));
}
}
catch (const toml::parse_error& err)
{
FAIL(
"Parse error on line "sv << err.source().begin.line
<< ", column "sv << err.source().begin.column
<< ":\n"sv << err.description()
);
}
#else
{
toml::parse_result result = toml::parse(toml_str, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(std::move(result), source_path));
else
{
FAIL(
"Parse error on line "sv << result.error().source().begin.line
<< ", column "sv << result.error().source().begin.column
<< ":\n"sv << result.error().description()
);
return;
}
}
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), toml_str.length());
toml::parse_result result = toml::parse(ss, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(std::move(result), source_path));
else
{
FAIL(
"Parse error on line "sv << result.error().source().begin.line
<< ", column "sv << result.error().source().begin.column
<< ":\n"sv << result.error().description()
);
return;
}
}
#endif
}
template <typename CHAR>
void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
{
#if TOML_EXCEPTIONS
static constexpr auto run_tests = [](auto&& fn) noexcept
{
try
{
fn();
}
catch (const toml::parse_error&)
{
SUCCEED("toml::parse_error thrown OK"sv);
return true;
}
catch (const std::exception& exc)
{
FAIL("Expected parsing failure, saw exception: "sv << exc.what());
}
catch (...)
{
FAIL("Expected parsing failure, saw unspecified error"sv);
}
return false;
};
if (run_tests([=]() { (void)toml::parse(toml_str); }))
run_tests([=]()
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), toml_str.length());
(void)toml::parse(ss);
});
#else
static constexpr auto run_tests = [](auto&& fn) noexcept
{
toml::parse_result result = fn();
if (result)
{
FAIL("Expected parsing failure"sv);
return false;
}
else
{
SUCCEED("toml::parse_error returned OK"sv);
return true;
}
};
if (run_tests([=]() noexcept { return toml::parse(toml_str); }))
run_tests([=]() noexcept
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), toml_str.length());
return toml::parse(ss);
});
#endif
}
template <typename T>
void parse_expected_value(std::string_view value_str, const T& expected) noexcept
{
std::string value;
static constexpr auto value_key = "val = "sv;
value.reserve(value_key.length() + value_str.length());
value.append(value_key);
value.append(value_str);
static constexpr auto is_val = [](char32_t codepoint) noexcept
{
if constexpr (std::is_same_v<string, impl::promoted<T>>)
return codepoint == U'"' || codepoint == U'\'';
else
return !impl::is_whitespace(codepoint);
};
source_position pos{ 1, static_cast<source_index>(value_key.length()) };
source_position begin{}, end{};
impl::utf8_decoder decoder;
for (auto c : value_str)
{
decoder(static_cast<uint8_t>(c));
if (!decoder.has_code_point())
continue;
if (impl::is_line_break(decoder.codepoint))
{
if (decoder.codepoint != U'\r')
{
pos.line++;
pos.column = source_index{ 1 };
}
continue;
}
pos.column++;
if (is_val(decoder.codepoint))
{
if (!begin)
begin = pos;
else
end = pos;
}
}
if (!end)
end = begin;
end.column++;
parsing_should_succeed(std::string_view{ value }, [&](table&& tbl) noexcept
{
CHECK(tbl.size() == 1);
const auto nv = tbl[S("val"sv)];
REQUIRE(nv);
REQUIRE(nv.as<impl::promoted<T>>());
REQUIRE(nv.get()->type() == impl::node_type_of<T>);
//check the raw value
CHECK(nv.as<impl::promoted<T>>()->get() == expected);
//check the value relops
CHECK(*nv.as<impl::promoted<T>>() == expected);
CHECK(expected == *nv.as<impl::promoted<T>>());
CHECK(!(*nv.as<impl::promoted<T>>() != expected));
CHECK(!(expected != *nv.as<impl::promoted<T>>()));
//check the node_view relops
CHECK(nv == expected);
CHECK(expected == nv);
CHECK(!(nv != expected));
CHECK(!(expected != nv));
//make sure source info is correct
CHECK(nv.get()->source().begin == begin);
CHECK(nv.get()->source().end == end);
});
}