Improve unit testing (Part 1) (#3380)

* Refactor unit test creation

Add functions for creating tests and to supply test- and
standard-specific build settings.

Raises minimum CMake version to 3.13 in test directory.

json_test_add_test_for(
    <file>
    MAIN <main>
    [CXX_STANDARDS <version_number>...] [FORCE])

Given a <file> unit-foo.cpp, produces

    test-foo_cpp<version_number>

if C++ standard <version_number> is supported by the compiler and
thesource file contains JSON_HAS_CPP_<version_number>.  Use FORCE to
create the test regardless of the file containing
JSON_HAS_CPP_<version_number>.  Test targets are linked against <main>.
CXX_STANDARDS defaults to "11".

json_test_set_test_options(
    all|<tests>
    [CXX_STANDARDS all|<args>...]
    [COMPILE_DEFINITIONS <args>...]
    [COMPILE_FEATURES <args>...]
    [COMPILE_OPTIONS <args>...]
    [LINK_LIBRARIES <args>...]
    [LINK_OPTIONS <args>...])

Supply test- and standard-specific build settings.
Specify multiple tests using a list e.g., "test-foo;test-bar".

Must be called BEFORE the test is created.

* Use CMAKE_MODULE_PATH

* Don't undef some macros if JSON_TEST_KEEP_MACROS is defined

* Use JSON_TEST_KEEP_MACROS

Incidentally enables the regression tests for #2546 and #3070.

A CHECK_THROWS_WITH_AS in #3070 was disabled which is tracked in #3377
and a line in from_json(..., std_fs::path&) was marked with LCOV_EXCL_LINE.

* Add three-way comparison feature test macro

* Disable broken comparison if JSON_HAS_THREE_WAY_COMPARISON

* Fix redefinition of inline constexpr statics

Redelcaration of inline constexpr static data members in namespace scope
was deprecated in C++17. Fixes -Werror=deprecated compilation failures.

* Fix more test build failures due to missing noexcept

* CI: update cmake_flags test to use CMake 3.13 in test directory

Also change default for JSON_BuildTests option to depend on CMake
version.

* CI: turn *_CXXFLAGS into CMake lists

* CI: use JSON_TestStandards to set CXX_STANDARD

* CI: pass extra CXXFLAGS to standards tests
This commit is contained in:
Florian Albrechtskirchinger
2022-03-24 07:54:07 +01:00
committed by GitHub
parent 700b95f447
commit ad103e5b45
20 changed files with 756 additions and 607 deletions

View File

@@ -37,7 +37,7 @@ SOFTWARE.
/* forward declarations */
class alt_string;
bool operator<(const char* op1, const alt_string& op2);
bool operator<(const char* op1, const alt_string& op2) noexcept;
void int_to_string(alt_string& target, std::size_t value);
/*
@@ -152,7 +152,7 @@ class alt_string
private:
std::string str_impl {};
friend bool ::operator<(const char* /*op1*/, const alt_string& /*op2*/);
friend bool ::operator<(const char* /*op1*/, const alt_string& /*op2*/) noexcept;
};
void int_to_string(alt_string& target, std::size_t value)
@@ -172,7 +172,7 @@ using alt_json = nlohmann::basic_json <
nlohmann::adl_serializer >;
bool operator<(const char* op1, const alt_string& op2)
bool operator<(const char* op1, const alt_string& op2) noexcept
{
return op1 < op2.str_impl;
}

View File

@@ -1609,7 +1609,7 @@ TEST_CASE("CBOR")
// callback to set binary_seen to true if a binary value was seen
bool binary_seen = false;
auto callback = [&binary_seen](int /*depth*/, json::parse_event_t /*event*/, json & parsed)
auto callback = [&binary_seen](int /*depth*/, json::parse_event_t /*event*/, json & parsed) noexcept
{
if (parsed.is_binary())
{

View File

@@ -267,7 +267,7 @@ bool accept_helper(const std::string& s)
CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored);
// 5. parse with simple callback
json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/)
json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept
{
return true;
};
@@ -1499,7 +1499,7 @@ TEST_CASE("parser class")
// test case to make sure the callback is properly evaluated after reading a key
{
json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/)
json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept
{
return event != json::parse_event_t::key;
};
@@ -1538,14 +1538,14 @@ TEST_CASE("parser class")
SECTION("filter nothing")
{
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/)
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
{
return true;
});
CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}}));
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/)
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
{
return true;
});
@@ -1555,7 +1555,7 @@ TEST_CASE("parser class")
SECTION("filter everything")
{
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/)
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
{
return false;
});
@@ -1563,7 +1563,7 @@ TEST_CASE("parser class")
// the top-level object will be discarded, leaving a null
CHECK (j_object.is_null());
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/)
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
{
return false;
});
@@ -1574,7 +1574,7 @@ TEST_CASE("parser class")
SECTION("filter specific element")
{
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j)
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept
{
// filter all number(2) elements
return j != json(2);
@@ -1582,7 +1582,7 @@ TEST_CASE("parser class")
CHECK (j_object == json({{"bar", {{"baz", 1}}}}));
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j)
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept
{
return j != json(2);
});
@@ -1601,7 +1601,7 @@ TEST_CASE("parser class")
CHECK (j_filtered1.size() == 2);
CHECK (j_filtered1 == json({1, {{"qux", "baz"}}}));
json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/)
json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) noexcept
{
return e != json::parse_event_t::object_end;
});
@@ -1616,7 +1616,7 @@ TEST_CASE("parser class")
SECTION("first closing event")
{
{
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/)
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept
{
static bool first = true;
if (e == json::parse_event_t::object_end && first)
@@ -1633,7 +1633,7 @@ TEST_CASE("parser class")
}
{
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/)
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept
{
static bool first = true;
if (e == json::parse_event_t::array_end && first)
@@ -1657,13 +1657,13 @@ TEST_CASE("parser class")
// object and array is discarded only after the closing character
// has been read
json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/)
json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept
{
return e != json::parse_event_t::object_end;
});
CHECK(j_empty_object == json());
json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/)
json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept
{
return e != json::parse_event_t::array_end;
});
@@ -1731,7 +1731,7 @@ TEST_CASE("parser class")
{
SECTION("parser with callback")
{
json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/)
json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept
{
return true;
};

View File

@@ -32,10 +32,6 @@ SOFTWARE.
#include <nlohmann/json.hpp>
using nlohmann::json;
#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
#define JSON_HAS_CPP_20
#endif
namespace
{
// helper function to check std::less<json::value_t>
@@ -211,7 +207,7 @@ TEST_CASE("lexicographical comparison operators")
{
// Skip comparing indicies 12 and 13, and 13 and 12 in C++20 pending fix
// See issue #3207
#ifdef JSON_HAS_CPP_20
#if defined(JSON_HAS_CPP_20) || JSON_HAS_THREE_WAY_COMPARISON
if ((i == 12 && j == 13) || (i == 13 && j == 12))
{
continue;

View File

@@ -41,13 +41,6 @@ using nlohmann::json;
#include <unordered_set>
#include <valarray>
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
#define JSON_HAS_CPP_14
#endif
// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")

View File

@@ -32,13 +32,6 @@ SOFTWARE.
#include <nlohmann/json.hpp>
using nlohmann::json;
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
#define JSON_HAS_CPP_14
#endif
// This test suite uses range for loops where values are copied. This is inefficient in usual code, but required to achieve 100% coverage.
DOCTEST_GCC_SUPPRESS_WARNING_PUSH
DOCTEST_GCC_SUPPRESS_WARNING("-Wrange-loop-construct")

View File

@@ -42,10 +42,6 @@ using nlohmann::json;
#include <cstdio>
#include <test_data.hpp>
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17
#endif
#ifdef JSON_HAS_CPP_17
#include <variant>
#endif

View File

@@ -42,70 +42,8 @@ using ordered_json = nlohmann::ordered_json;
#include <type_traits>
#include <utility>
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17
#endif
#ifdef JSON_HAS_CPP_17
#include <variant>
#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)
#if defined(__cpp_lib_filesystem)
#define JSON_HAS_FILESYSTEM 1
#elif defined(__cpp_lib_experimental_filesystem)
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
#elif !defined(__has_include)
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
#elif __has_include(<filesystem>)
#define JSON_HAS_FILESYSTEM 1
#elif __has_include(<experimental/filesystem>)
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
#endif
// std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/
#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8
#undef JSON_HAS_FILESYSTEM
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#endif
// no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support
#if defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)
#undef JSON_HAS_FILESYSTEM
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#endif
// no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support
#if defined(__clang_major__) && __clang_major__ < 7
#undef JSON_HAS_FILESYSTEM
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#endif
// no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support
#if defined(_MSC_VER) && _MSC_VER < 1940
#undef JSON_HAS_FILESYSTEM
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#endif
// no filesystem support before iOS 13
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000
#undef JSON_HAS_FILESYSTEM
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#endif
// no filesystem support before macOS Catalina
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
#undef JSON_HAS_FILESYSTEM
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#endif
#endif
#endif
#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0
#endif
#ifndef JSON_HAS_FILESYSTEM
#define JSON_HAS_FILESYSTEM 0
#endif
#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
@@ -656,7 +594,7 @@ TEST_CASE("regression tests 2")
#ifdef JSON_HAS_CPP_20
SECTION("issue #2546 - parsing containers of std::byte")
{
const char DATA[] = R"("Hello, world!")";
const char DATA[] = R"("Hello, world!")"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
const auto s = std::as_bytes(std::span(DATA));
json j = json::parse(s);
CHECK(j.dump() == "\"Hello, world!\"");
@@ -810,7 +748,8 @@ TEST_CASE("regression tests 2")
const auto j_path = j.get<nlohmann::detail::std_fs::path>();
CHECK(j_path == text_path);
CHECK_THROWS_WITH_AS(nlohmann::detail::std_fs::path(json(1)), "[json.exception.type_error.302] type must be string, but is number", json::type_error);
// Disabled pending resolution of #3377
// CHECK_THROWS_WITH_AS(nlohmann::detail::std_fs::path(json(1)), "[json.exception.type_error.302] type must be string, but is number", json::type_error);
}
#endif

View File

@@ -1610,7 +1610,7 @@ TEST_CASE("UBJSON")
CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&);
json j;
nlohmann::detail::json_sax_dom_callback_parser<json> scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/)
nlohmann::detail::json_sax_dom_callback_parser<json> scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
{
return true;
});
@@ -1624,7 +1624,7 @@ TEST_CASE("UBJSON")
CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&);
json j;
nlohmann::detail::json_sax_dom_callback_parser<json> scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/)
nlohmann::detail::json_sax_dom_callback_parser<json> scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
{
return true;
});