mirror of
https://github.com/nlohmann/json.git
synced 2026-09-29 14:24:56 +01:00
* Add tests for uncovered code paths Cover code the test suite did not reach, found from the Coveralls report of develop and a local coverage run of HEAD: - dump() of every kind of value below the bound of the recursive descent (pretty-printed objects, binary values, discarded values, scalars), and flushes of the escape and write buffers mid-string and mid-binary - the iterative comparison: objects with different keys, containers that are a prefix of each other, and elements that cannot be ordered, each both at the top level and below the nesting bound - SAX handlers that stop at any event, including the end of a nested container, in the BSON, CBOR, MessagePack, UBJSON and BJData readers - from_bson/cbor/msgpack/ubjson/bjdata returning a discarded value through the iterator and pointer overloads - JSON Patch, diff, merge_patch and update(..., true) on ordered_json - smaller gaps: get_allocator(), to_ubjson/to_bjdata into a string, value() with an unresolvable JSON pointer, integer/float comparison below the integer range and with negative fractions, conversion to a custom binary type, std::formatter::parse on a spec without '}', unescape() of a lone '~', and the callback parser's start_array() Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Cover more paths that were thought unreachable - parse_float_fast() declining malformed or inexact input, called directly since the lexer only passes well-formed numbers to it - a UTF-16 high surrogate followed by a unit above the low surrogates - self-assignment of a const_iterator - a truncated CBOR string read through non-contiguous iterators - serializing a long double under the de_DE locale, which undoes the locale's decimal point and thousands separator - values read from a binary format carrying no diagnostic positions, with and without a parser callback Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix the CI failures of the new coverage tests - declare the self-assignment reference const (misc-const-correctness) - expect the (/path) prefix that JSON_DIAGNOSTICS adds to the messages of the failing ordered_json patch operations Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Expect the byte range JSON_DIAGNOSTIC_POSITIONS adds to the patch errors Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Build the expected dump of the nested-object test with += clang-tidy (performance-inefficient-string-concatenation) reported the chain of operator+ calls that assembled the expected indented output. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Compare the BJData and UBJSON test outputs byte by byte Building a std::string from the byte vector converts each byte implicitly, which -fsanitize=integer reports for bytes of 0x80 and above (ci_test_clang_sanitizer). Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
401 lines
14 KiB
C++
401 lines
14 KiB
C++
// __ _____ _____ _____
|
|
// __| | __| | | | 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"
|
|
|
|
#define JSON_TESTS_PRIVATE
|
|
#include <nlohmann/json.hpp>
|
|
using nlohmann::json;
|
|
|
|
TEST_CASE("const_iterator class")
|
|
{
|
|
SECTION("construction")
|
|
{
|
|
SECTION("constructor")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator const it(&j);
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j(json::value_t::object);
|
|
json::const_iterator const it(&j);
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j(json::value_t::array);
|
|
json::const_iterator const it(&j);
|
|
}
|
|
}
|
|
|
|
SECTION("copy assignment")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator const it(&j);
|
|
json::const_iterator it2(&j);
|
|
it2 = it;
|
|
|
|
// assigning an iterator to itself leaves it unchanged
|
|
json const a = {1, 2, 3};
|
|
json::const_iterator it3 = a.cbegin() + 1;
|
|
const json::const_iterator& same = it3;
|
|
it3 = same;
|
|
CHECK(*it3 == 2);
|
|
}
|
|
|
|
SECTION("copy constructor from non-const iterator")
|
|
{
|
|
SECTION("create from uninitialized iterator")
|
|
{
|
|
const json::iterator it {};
|
|
json::const_iterator const cit(it);
|
|
}
|
|
|
|
SECTION("create from initialized iterator")
|
|
{
|
|
json j;
|
|
const json::iterator it = j.begin();
|
|
json::const_iterator const cit(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("initialization")
|
|
{
|
|
SECTION("set_begin")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator it(&j);
|
|
it.set_begin();
|
|
CHECK((it == j.cbegin()));
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j(json::value_t::object);
|
|
json::const_iterator it(&j);
|
|
it.set_begin();
|
|
CHECK((it == j.cbegin()));
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j(json::value_t::array);
|
|
json::const_iterator it(&j);
|
|
it.set_begin();
|
|
CHECK((it == j.cbegin()));
|
|
}
|
|
}
|
|
|
|
SECTION("set_end")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator it(&j);
|
|
it.set_end();
|
|
CHECK((it == j.cend()));
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j(json::value_t::object);
|
|
json::const_iterator it(&j);
|
|
it.set_end();
|
|
CHECK((it == j.cend()));
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j(json::value_t::array);
|
|
json::const_iterator it(&j);
|
|
it.set_end();
|
|
CHECK((it == j.cend()));
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("element access")
|
|
{
|
|
SECTION("operator*")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator const it = j.cbegin();
|
|
CHECK_THROWS_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
|
}
|
|
|
|
SECTION("number")
|
|
{
|
|
json const j(17);
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK(*it == json(17));
|
|
it = j.cend();
|
|
CHECK_THROWS_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j({{"foo", "bar"}});
|
|
json::const_iterator const it = j.cbegin();
|
|
CHECK(*it == json("bar"));
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j({1, 2, 3, 4});
|
|
json::const_iterator const it = j.cbegin();
|
|
CHECK(*it == json(1));
|
|
}
|
|
}
|
|
|
|
SECTION("operator->")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator const it = j.cbegin();
|
|
CHECK_THROWS_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
|
}
|
|
|
|
SECTION("number")
|
|
{
|
|
json const j(17);
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK(std::string(it->type_name()) == "number");
|
|
it = j.cend();
|
|
CHECK_THROWS_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j({{"foo", "bar"}});
|
|
json::const_iterator const it = j.cbegin();
|
|
CHECK(std::string(it->type_name()) == "string");
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j({1, 2, 3, 4});
|
|
json::const_iterator const it = j.cbegin();
|
|
CHECK(std::string(it->type_name()) == "number");
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("increment/decrement")
|
|
{
|
|
SECTION("post-increment")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
|
it++;
|
|
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
|
}
|
|
|
|
SECTION("number")
|
|
{
|
|
json const j(17);
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
|
it++;
|
|
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
|
it++;
|
|
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j({{"foo", "bar"}});
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
|
|
it++;
|
|
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j({1, 2, 3, 4});
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
|
|
it++;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
it++;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
it++;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
it++;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
|
|
}
|
|
}
|
|
|
|
SECTION("pre-increment")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
|
++it;
|
|
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
|
}
|
|
|
|
SECTION("number")
|
|
{
|
|
json const j(17);
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
|
++it;
|
|
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
|
++it;
|
|
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j({{"foo", "bar"}});
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
|
|
++it;
|
|
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j({1, 2, 3, 4});
|
|
json::const_iterator it = j.cbegin();
|
|
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
|
|
++it;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
++it;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
++it;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
++it;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
|
|
}
|
|
}
|
|
|
|
SECTION("post-decrement")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator const it = j.cend();
|
|
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
|
}
|
|
|
|
SECTION("number")
|
|
{
|
|
json const j(17);
|
|
json::const_iterator it = j.cend();
|
|
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
|
it--;
|
|
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
|
it--;
|
|
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j({{"foo", "bar"}});
|
|
json::const_iterator it = j.cend();
|
|
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
|
|
it--;
|
|
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j({1, 2, 3, 4});
|
|
json::const_iterator it = j.cend();
|
|
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
|
|
it--;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
it--;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
it--;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
it--;
|
|
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
}
|
|
}
|
|
|
|
SECTION("pre-decrement")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
json const j(json::value_t::null);
|
|
json::const_iterator const it = j.cend();
|
|
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
|
}
|
|
|
|
SECTION("number")
|
|
{
|
|
json const j(17);
|
|
json::const_iterator it = j.cend();
|
|
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
|
--it;
|
|
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
|
--it;
|
|
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
json const j({{"foo", "bar"}});
|
|
json::const_iterator it = j.cend();
|
|
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
|
|
--it;
|
|
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
json const j({1, 2, 3, 4});
|
|
json::const_iterator it = j.cend();
|
|
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
|
|
--it;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
--it;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
--it;
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
--it;
|
|
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
|
|
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
|
|
}
|
|
}
|
|
}
|
|
}
|