Fix test failures in the coverage tests

- unit-custom-object-key-type: remove the unused make_strict_key(strict_key)
  overload, the unused range constructor and default constructor, and guard
  data() with JSON_DIAGNOSTICS (unused-function/-member-function errors with
  GCC and clang -Weverything).
- unit-json_view_compare: move the two new sections to the new
  unit-json_view_compare_values.cpp, as the object file got too large for the
  MinGW assembler again, and use a std::map with std::greater instead of
  std::unordered_map, which does not accept the incomplete basic_json
  (clang 3.9, icpc).
- unit-json_view_dump: rename the variables that hid outer ones (MSVC C4456).
- unit-stream-bulk-scan: restore the real size of the oversized get area
  before the adapter is destroyed (JSON_PRECISE_STREAM_POSITION reads the
  character at the read position), and skip the test where the streambuf
  cannot hold a get area larger than an int (MSVC).
- unit-regression1: with JSON_NO_THREAD_LOCAL, copies are built member by
  member and keep correct timestamps, so check the corresponding outcome.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
Claude committed 2026-11-02 05:59:57 +00:00
1 parent 056ba3b7c1
commit 2301f01284
6 files changed
+117 -91

No files matched your search

+2 -17
View File
@@ -139,20 +139,20 @@ namespace
class strict_key
{
public:
strict_key() = default;
strict_key(const char* value)
: m_value(value)
{}
strict_key(const std::string& /*value*/) = delete;
#if JSON_DIAGNOSTICS
// Required by JSON_DIAGNOSTICS, which reads object keys through data()
// when building the path of an exception.
const char* data() const noexcept
{
return m_value.data();
}
#endif
friend bool operator<(const strict_key& lhs, const strict_key& rhs)
{
@@ -168,11 +168,6 @@ strict_key make_strict_key(const std::string& key)
return strict_key(key.c_str());
}
strict_key make_strict_key(const strict_key& key)
{
return key;
}
template<class Key, class Value, class Compare, class Allocator>
class strict_object
: public std::map <
@@ -184,16 +179,6 @@ class strict_object
{
public:
strict_object() = default;
// the range of another object type, whose keys are made into strict_keys
template<class Iterator>
strict_object(Iterator first, Iterator last)
{
for (; first != last; ++first)
{
this->emplace(make_strict_key(first->first), Value(std::move(first->second)));
}
}
};
template<typename T, typename = void>
-62
View File
@@ -21,22 +21,13 @@ using json_view_test::generator;
#include <array>
#include <cstddef>
#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
// These tests were split off unit-json_view_dump.cpp, whose object file got too
// large for the MinGW assembler ("file too big"). Like that file, this one is
// also built with C++17, as it mentions JSON_HAS_CPP_17.
namespace
{
// an object type without a comparison of keys, and with an arbitrary order of members
template<typename Key, typename Value, typename /*Compare*/, typename Allocator>
using unordered_object = std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, Allocator>;
} // namespace
TEST_CASE("json_view comparison")
{
SECTION("equality of the values parse() produces")
@@ -214,59 +205,6 @@ TEST_CASE("json_view comparison")
CHECK(!(null_document.root() == discarded));
}
SECTION("values that differ in their first bytes, or are written differently")
{
const auto same = [](const char* x, const char* y)
{
const json_document dx = json_document::parse(x);
const json_document dy = json_document::parse(y);
const bool equal = dx.root() == dy.root();
CHECK(equal == (json::parse(x) == json::parse(y)));
CHECK(equal == (dx.root() == json::parse(y)));
const nlohmann::json_editable_document ex = nlohmann::json_editable_document::parse(x);
CHECK(equal == (ex.root() == dy.root()));
return equal;
};
// booleans
CHECK(!same("true", "false"));
CHECK(!same("[true]", "[false]"));
CHECK(!same(R"({"a":false,"b":[1]})", R"({"a":true,"b":[1]})"));
CHECK(same(R"({"a":true,"b":[1]})", R"({"a":true,"b":[1]})"));
// strings and keys of equal length that differ in the first eight bytes (they are compared in words)
CHECK(!same(R"("abcdefghijklmnopqrstuvwxyz")", R"("Xbcdefghijklmnopqrstuvwxyz")"));
CHECK(!same(R"(["abcdefghijklmnopq",1])", R"(["abcdefghXjklmnopq",1])"));
CHECK(!same(R"({"abcdefghijklmnopq":1})", R"({"Xbcdefghijklmnopq":1})"));
CHECK(!same(R"({"abcdefghijklmnopq":[1]})", R"({"abcdefghijklmnopX":[1]})"));
// floats of one layout and different tokens are the same value
CHECK(same("[1.5e0, 2]", "[1.5E0, 2]"));
CHECK(same("[1.5e0, 2]", "[1.5e+0, 2]"));
CHECK(same("[1.50, 2]", "[1.5, 2]"));
CHECK(!same("[1.5e0, 2]", "[1.6e0, 2]"));
CHECK(!same("[1.5e0, 2]", "[1.5E1, 2]"));
CHECK(same(R"({"a":1.25e0,"b":[3]})", R"({"a":1.25E0,"b":[3]})"));
}
SECTION("a basic_json whose members are not sorted")
{
// (an object type that is not an ordered map, and does not keep its members sorted either)
using unordered_json = nlohmann::basic_json<unordered_object>;
using unordered_document = nlohmann::basic_json_document<unordered_json>;
std::string text = "{";
for (char key = 'a'; key <= 'p'; ++key)
{
text += (key != 'a' ? ",\"" : "\"") + std::string(1, key) + "\":[" + std::to_string(key) + "]";
}
text += "}";
const unordered_json j = unordered_json::parse(text);
const unordered_document d = unordered_document::parse(text);
CHECK(d.root() == j);
CHECK(j == d.root());
unordered_json other = j;
other["k"] = 0;
CHECK(d.root() != other);
CHECK(other != d.root());
}
SECTION("values that are the same text, or the same value written differently, at any depth")
{
// nested arrays and objects around depths where the walk over equal text gives up
@@ -0,0 +1,83 @@
// __ _____ _____ _____
// __| | __| | | | 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
#include "doctest_compatibility.h"
#include <nlohmann/json_view.hpp>
using nlohmann::json;
using nlohmann::json_document;
#include <functional>
#include <map>
#include <string>
// These tests were split off unit-json_view_compare.cpp, whose object file got
// too large for the MinGW assembler ("file too big").
namespace
{
// an object type that does not enumerate its members in ascending order of keys
template<typename Key, typename Value, typename /*Compare*/, typename Allocator>
using descending_object = std::map<Key, Value, std::greater<Key>, Allocator>;
} // namespace
TEST_CASE("json_view comparison of differing values")
{
SECTION("values that differ in their first bytes, or are written differently")
{
const auto same = [](const char* x, const char* y)
{
const json_document dx = json_document::parse(x);
const json_document dy = json_document::parse(y);
const bool equal = dx.root() == dy.root();
CHECK(equal == (json::parse(x) == json::parse(y)));
CHECK(equal == (dx.root() == json::parse(y)));
const nlohmann::json_editable_document ex = nlohmann::json_editable_document::parse(x);
CHECK(equal == (ex.root() == dy.root()));
return equal;
};
// booleans
CHECK(!same("true", "false"));
CHECK(!same("[true]", "[false]"));
CHECK(!same(R"({"a":false,"b":[1]})", R"({"a":true,"b":[1]})"));
CHECK(same(R"({"a":true,"b":[1]})", R"({"a":true,"b":[1]})"));
// strings and keys of equal length that differ in the first eight bytes (they are compared in words)
CHECK(!same(R"("abcdefghijklmnopqrstuvwxyz")", R"("Xbcdefghijklmnopqrstuvwxyz")"));
CHECK(!same(R"(["abcdefghijklmnopq",1])", R"(["abcdefghXjklmnopq",1])"));
CHECK(!same(R"({"abcdefghijklmnopq":1})", R"({"Xbcdefghijklmnopq":1})"));
CHECK(!same(R"({"abcdefghijklmnopq":[1]})", R"({"abcdefghijklmnopX":[1]})"));
// floats of one layout and different tokens are the same value
CHECK(same("[1.5e0, 2]", "[1.5E0, 2]"));
CHECK(same("[1.5e0, 2]", "[1.5e+0, 2]"));
CHECK(same("[1.50, 2]", "[1.5, 2]"));
CHECK(!same("[1.5e0, 2]", "[1.6e0, 2]"));
CHECK(!same("[1.5e0, 2]", "[1.5E1, 2]"));
CHECK(same(R"({"a":1.25e0,"b":[3]})", R"({"a":1.25E0,"b":[3]})"));
}
SECTION("a basic_json whose members are not sorted")
{
// (an object type that is not an ordered map, and does not keep its members sorted either)
using descending_json = nlohmann::basic_json<descending_object>;
using descending_document = nlohmann::basic_json_document<descending_json>;
std::string text = "{";
for (char key = 'a'; key <= 'p'; ++key)
{
text += (key != 'a' ? ",\"" : "\"") + std::string(1, key) + "\":[" + std::to_string(key) + "]";
}
text += "}";
const descending_json j = descending_json::parse(text);
const descending_document d = descending_document::parse(text);
CHECK(d.root() == j);
CHECK(j == d.root());
descending_json other = j;
other["k"] = 0;
CHECK(d.root() != other);
CHECK(other != d.root());
}
}
+7 -7
View File
@@ -247,15 +247,15 @@ TEST_CASE("json_view dump")
})
{
CAPTURE(token)
const std::string text = std::string("[") + token + padding + "]";
const json_document d = json_document::parse(text);
const json j = json::parse(text);
CHECK(d.root()[0].get<double>() == j[0].get<double>());
CHECK(d.root().dump() == j.dump());
const std::string padded = std::string("[") + token + padding + "]";
const json_document padded_document = json_document::parse(padded);
const json padded_json = json::parse(padded);
CHECK(padded_document.root()[0].get<double>() == padded_json[0].get<double>());
CHECK(padded_document.root().dump() == padded_json.dump());
// a float document converts the tokens as well
using json_float = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
const nlohmann::basic_json_document<json_float> float_doc = nlohmann::basic_json_document<json_float>::parse(text);
CHECK(float_doc.root()[0].get<float>() == json_float::parse(text)[0].get<float>());
const nlohmann::basic_json_document<json_float> float_doc = nlohmann::basic_json_document<json_float>::parse(padded);
CHECK(float_doc.root()[0].get<float>() == json_float::parse(padded)[0].get<float>());
}
}
+9 -1
View File
@@ -1553,11 +1553,19 @@ TEST_CASE("regression tests 1")
SECTION("a missing member of an object")
{
my_json j = make();
#ifdef JSON_NO_THREAD_LOCAL
// the objects below the outermost one are not copied by their
// object_t here, but member by member, which keeps their
// timestamps correct: "c" is not mistaken for "b" and is inserted
CHECK(j[my_json::json_pointer("/k/a/c/d")].is_null());
CHECK(j["x"]["a"].dump() == R"({"b":1,"c":{"d":null}})");
#else
// the timestamp of "c" is that of "b" again, so that emplace()
// finds the member "b", a number, which has no member "d"
my_json j = make();
CHECK_THROWS_AS(j[my_json::json_pointer("/k/a/c/d")], my_json::out_of_range&);
CHECK(j["x"]["a"].dump() == R"({"b":1})");
#endif
}
SECTION("a null value is converted to an object")
+16 -4
View File
@@ -109,6 +109,14 @@ class oversized_get_area_streambuf : public std::streambuf
setg(m_data.data(), m_data.data(), m_data.data() + claimed_size);
}
// Give the get area back its real size, so that the adapter may read the
// character at the read position when it is destroyed (with
// JSON_PRECISE_STREAM_POSITION, it consumes the last character returned).
void restore_get_area()
{
setg(m_data.data(), m_data.data(), m_data.data() + m_data.size());
}
private:
std::array<char, 8> m_data{{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}};
};
@@ -458,14 +466,16 @@ TEST_CASE("parsing from a std::istream scans the get area in bulk")
SECTION("skipping more characters than gbump() takes at once")
{
// gbump() takes an int, but a get area can be larger
if (sizeof(std::size_t) < 8)
const std::size_t claimed = sizeof(std::size_t) < 8 ? 0 : std::size_t{3} << 30u;
oversized_get_area_streambuf buf(claimed);
if (claimed == 0 || static_cast<std::size_t>(buf.in_avail()) != claimed)
{
MESSAGE("a get area larger than an int needs a 64-bit size_t");
// a 32-bit size_t, or a standard library whose streambuf stores
// the size of the get area in an int (MSVC)
MESSAGE("a get area larger than an int is not supported");
}
else
{
const std::size_t claimed = std::size_t{3} << 30u;
oversized_get_area_streambuf buf(claimed);
std::istream is(&buf);
nlohmann::detail::input_stream_adapter ia(is);
CHECK(ia.get_character() == 'a');
@@ -477,6 +487,8 @@ TEST_CASE("parsing from a std::istream scans the get area in bulk")
ia.bulk_skip(ia.bulk_remaining());
CHECK(ia.bulk_remaining() == 0);
buf.restore_get_area();
}
}
#endif