mirror of
https://github.com/nlohmann/json.git
synced 2026-09-06 00:08:00 +00:00
test: cover JSON_NO_IO, JSON_THROW/TRY/CATCH_USER, JSON_SKIP_LIBRARY_VERSION_CHECK, and JSON_DisableEnumSerialization in CI (#5423)
These four supported configuration macros were never actually compiled anywhere in the test matrix: - JSON_NO_IO and the JSON_THROW_USER/JSON_TRY_USER/JSON_CATCH_USER trio are exercised together in a new tests/src/unit-no_io_and_user_exceptions.cpp, which is automatically picked up by the existing unit-*.cpp test glob and thus built across the whole standard test matrix. - JSON_SKIP_LIBRARY_VERSION_CHECK is exercised by a new, dedicated tests/src/skip_library_version_check.cpp, compiled directly by the new ci_test_skiplibraryversioncheck target in cmake/ci.cmake: the scenario it simulates (mixing two differently-versioned inclusions of the library) unavoidably triggers the compiler's own "macro redefined" warning, which would fail under the library's own -Weverything/-Werror unit test matrix for a reason unrelated to the macro under test. - JSON_DisableEnumSerialization already had #if-guarded tests in several unit-*.cpp files (from #4384), but no CMake target ever actually set the JSON_DisableEnumSerialization CMake option, so that guarded code was never compiled. Add ci_test_disableenumserialization, mirroring the existing ci_test_noimplicitconversions/ci_test_noglobaludls targets. Building the full test suite with this option on surfaced one real, narrow gap: get<T>() on std::vector<std::byte> (used by unit-regression2.cpp's custom BinaryType tests) relies on std::byte being handled via enum serialization, so add the same #if-guard convention to the two affected SECTIONs there. Both new CI targets are added to the ci_cmake_options matrix in .github/workflows/ubuntu.yml, alongside the existing ci_test_* targets. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -100,7 +100,7 @@ jobs:
|
||||
container: ubuntu:focal
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls]
|
||||
target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_skiplibraryversioncheck]
|
||||
steps:
|
||||
- name: Install build-essential
|
||||
run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev
|
||||
|
||||
@@ -242,6 +242,40 @@ add_custom_target(ci_test_noglobaludls
|
||||
COMMENT "Compile and test with global UDLs disabled"
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Disable enum serialization.
|
||||
###############################################################################
|
||||
|
||||
add_custom_target(ci_test_disableenumserialization
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
||||
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_DisableEnumSerialization=ON
|
||||
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_disableenumserialization
|
||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_disableenumserialization
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_disableenumserialization && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
|
||||
COMMENT "Compile and test with enum serialization disabled"
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Skip the multiple-inclusion library version check.
|
||||
###############################################################################
|
||||
|
||||
# tests/src/skip_library_version_check.cpp deliberately simulates a scenario
|
||||
# (mixing two differently-versioned inclusions of the library in one
|
||||
# translation unit) that unavoidably triggers the compiler's own "macro
|
||||
# redefined" warning, so -- unlike the ci_test_* targets above -- it is
|
||||
# compiled directly here, with a modest warning set, instead of being folded
|
||||
# into the library's own -Weverything/-Werror unit test matrix.
|
||||
add_custom_target(ci_test_skiplibraryversioncheck
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/skip_library_version_check
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -std=c++11 -Wall -Wextra
|
||||
-I${PROJECT_SOURCE_DIR}/include
|
||||
${PROJECT_SOURCE_DIR}/tests/src/skip_library_version_check.cpp
|
||||
-o ${PROJECT_BINARY_DIR}/skip_library_version_check/skip_library_version_check
|
||||
COMMAND ${PROJECT_BINARY_DIR}/skip_library_version_check/skip_library_version_check
|
||||
COMMENT "Compile and run a translation unit simulating a mismatched library version, with JSON_SKIP_LIBRARY_VERSION_CHECK defined"
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Coverage.
|
||||
###############################################################################
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Standalone compile-and-run check for the JSON_SKIP_LIBRARY_VERSION_CHECK
|
||||
// configuration macro, which (per #5423) was never exercised anywhere in the
|
||||
// test matrix.
|
||||
//
|
||||
// include/nlohmann/detail/abi_macros.hpp normally emits a #warning if
|
||||
// NLOHMANN_JSON_VERSION_MAJOR/MINOR/PATCH are already defined (as they would
|
||||
// be by an earlier inclusion of a different version of the library) with
|
||||
// values that mismatch the version about to be defined -- unless
|
||||
// JSON_SKIP_LIBRARY_VERSION_CHECK is defined, in which case the check (and
|
||||
// that #warning) is skipped.
|
||||
//
|
||||
// This file deliberately is not named tests/src/unit-*.cpp: it is compiled
|
||||
// directly (with a modest, non-strict warning set) by the dedicated
|
||||
// ci_test_skiplibraryversioncheck target in cmake/ci.cmake, rather than being
|
||||
// folded into the library's own -Weverything/-Werror unit test matrix. That
|
||||
// is because the scenario simulated here -- mixing two different, already
|
||||
// differently-versioned inclusions of the library in one translation unit --
|
||||
// unavoidably also triggers the *compiler's own* "macro redefined" warning,
|
||||
// independent of (and unaffected by) JSON_SKIP_LIBRARY_VERSION_CHECK, which
|
||||
// only ever silences the library's own #warning. Building this file under
|
||||
// -Weverything -Werror would therefore fail for a reason unrelated to the
|
||||
// macro under test.
|
||||
#define NLOHMANN_JSON_VERSION_MAJOR 0
|
||||
#define NLOHMANN_JSON_VERSION_MINOR 0
|
||||
#define NLOHMANN_JSON_VERSION_PATCH 0
|
||||
|
||||
#define JSON_SKIP_LIBRARY_VERSION_CHECK 1
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
// reaching this point at all already proves that the mismatched,
|
||||
// pre-defined version macros above did not stop compilation -- which is
|
||||
// exactly what JSON_SKIP_LIBRARY_VERSION_CHECK is for. The library must
|
||||
// also still be fully usable.
|
||||
const nlohmann::json j = {{"a", 1}, {"b", {1, 2, 3}}};
|
||||
if (j.dump() != "{\"a\":1,\"b\":[1,2,3]}")
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// include/nlohmann/detail/abi_macros.hpp unconditionally (re)defines the
|
||||
// version macros to the library's real, current version right after the
|
||||
// (here, skipped) mismatch check, regardless of the deliberately wrong
|
||||
// stand-in values defined above.
|
||||
if (NLOHMANN_JSON_VERSION_MAJOR == 0 && NLOHMANN_JSON_VERSION_MINOR == 0 && NLOHMANN_JSON_VERSION_PATCH == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// This translation unit is a dedicated, small compile-and-run check for two
|
||||
// configuration macros that (per #5423) were never exercised anywhere in the
|
||||
// test matrix:
|
||||
// - JSON_NO_IO, which removes the library's <istream>/<ostream> support
|
||||
// (operator<<, operator>>, and the stream-based overloads of dump()/parse())
|
||||
// - the JSON_THROW_USER / JSON_TRY_USER / JSON_CATCH_USER trio, which lets a
|
||||
// user replace the library's internal exception handling
|
||||
//
|
||||
// Both macros are about excluding/replacing a facility the library would
|
||||
// otherwise pull in on its own, and defining one has no bearing on the other,
|
||||
// so -- to keep the test matrix small -- they are exercised together in a
|
||||
// single dedicated file instead of two.
|
||||
//
|
||||
// JSON_NO_IO requires this file itself to never rely on <iostream>/<sstream>;
|
||||
// only string-based parsing/dumping is used below.
|
||||
#define JSON_NO_IO 1
|
||||
|
||||
// The user-supplied exception macros below are a *conforming* replacement:
|
||||
// they simply forward to the real throw/try/catch keywords (via a counter so
|
||||
// the test can assert each macro was actually invoked, not just defined), so
|
||||
// every exception-related behavior the library relies on internally --
|
||||
// including rethrowing std::out_of_range as json::out_of_range in at() --
|
||||
// keeps working exactly as it would with the library's own default macros.
|
||||
static int json_throw_user_call_count = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
#define JSON_THROW_USER(exception) do { ++json_throw_user_call_count; throw exception; } while (false) // NOLINT(cppcoreguidelines-macro-usage)
|
||||
#define JSON_TRY_USER try // NOLINT(cppcoreguidelines-macro-usage)
|
||||
#define JSON_CATCH_USER(exception) catch (exception) // NOLINT(cppcoreguidelines-macro-usage)
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
TEST_CASE("JSON_NO_IO")
|
||||
{
|
||||
// everything that does not touch <istream>/<ostream> must keep working:
|
||||
// parsing from and dumping to std::string
|
||||
const json j = json::parse("{\"a\":[1,2,3],\"b\":true}");
|
||||
CHECK(j.dump() == "{\"a\":[1,2,3],\"b\":true}");
|
||||
CHECK(j.at("a").size() == 3);
|
||||
CHECK(j.at("b").get<bool>() == true);
|
||||
}
|
||||
|
||||
TEST_CASE("JSON_THROW_USER, JSON_TRY_USER, JSON_CATCH_USER")
|
||||
{
|
||||
json_throw_user_call_count = 0;
|
||||
|
||||
// a parse error goes through JSON_THROW directly, i.e., through our
|
||||
// JSON_THROW_USER override
|
||||
CHECK_THROWS_AS(json::parse("this is not JSON"), json::parse_error&);
|
||||
CHECK(json_throw_user_call_count > 0);
|
||||
|
||||
// at() on an out-of-range array index internally catches std::out_of_range
|
||||
// (JSON_TRY_USER/JSON_CATCH_USER) and rethrows it as json::out_of_range
|
||||
// (JSON_THROW_USER again), so this exercises all three macros together
|
||||
const int count_before = json_throw_user_call_count;
|
||||
const json arr = json::array({1, 2, 3});
|
||||
CHECK_THROWS_AS(arr.at(10), json::out_of_range&);
|
||||
CHECK(json_throw_user_call_count > count_before);
|
||||
}
|
||||
@@ -18,6 +18,14 @@
|
||||
// for some reason including this after the json header leads to linker errors with VS 2017...
|
||||
#include <locale>
|
||||
|
||||
// skip tests if JSON_DisableEnumSerialization=ON (#4384): std::byte is a
|
||||
// scoped enum, so get<std::byte>() (needed below to get<std::vector<std::byte>>()
|
||||
// from a plain JSON array, not just from an already-binary value) relies on
|
||||
// enum serialization being enabled
|
||||
#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1)
|
||||
#define SKIP_TESTS_FOR_ENUM_SERIALIZATION
|
||||
#endif
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
@@ -1136,6 +1144,7 @@ TEST_CASE("regression tests 2")
|
||||
CHECK((decoded == json_4804::array()));
|
||||
}
|
||||
|
||||
#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION
|
||||
SECTION("discussion #4209 - custom BinaryType direct assignment and round-tripping")
|
||||
{
|
||||
// Test that assigning a custom BinaryType directly creates a binary value, not an array
|
||||
@@ -1169,6 +1178,7 @@ TEST_CASE("regression tests 2")
|
||||
CHECK(extracted[1] == std::byte{2});
|
||||
CHECK(extracted[2] == std::byte{3});
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("issue #5046 - implicit conversion of return json to std::optional no longer implicit")
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user