mirror of
https://github.com/nlohmann/json.git
synced 2026-11-03 03:15:34 +00:00
* CI: measure line coverage without lcov's unexecuted-block adjustment Drop geninfo_unexecuted_blocks=1 from the lcov capture of ci_test_coverage: it reset every line of an inlined or templated function to 0 as soon as one copy had an unexecuted block, which understated the line coverage by about three points. Add -fvar-tracking-assignments to both coverage builds. At -O0, GCC inlines always_inline functions before it places the coverage counters, so the call sites of such helpers (put_literal() and others) got no line record and showed as 0 in an -O3 translation unit that never reaches them. With the flag, the call sites carry counts in every translation unit. The generated code is identical. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Remove unreachable code found by the coverage analysis Remove code that no input can reach, and mark the lines that cannot be covered with LCOV_EXCL_LINE: - BJData writer: the dry_run parameter of the ND-array element writers was always true; replace them by range checks. - BON8 writer: call throw_integer_out_of_range() directly instead of write_bon8_value() for values that always throw. - binary_writer: integer_bits() is only called for integers of up to 64 bits. - serializer, view serializer, lexer: replace guards that the callers make unreachable by assertions or by the simpler code (surrogate pairs under ensure_ascii, next_unget, '-' at the end of the buffer). - json_view: drop unreachable branches in scalar(), set(), check_utf8_scan(), append_input_impl() and unescape(). - Mark exception-cleanup braces, 2 GiB limits, big-endian and 32-bit code, and fall-through case labels with LCOV_EXCL_LINE. No behavior changes for any input that reaches these functions. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Tests: cover the remaining lines of the library headers Add tests for the lines of include/nlohmann that were not covered: the binary readers and writers, the lexer and locale paths, the json_view modules, the custom number, key and array types, json_pointer, json_patch, diff and the iterators. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * 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> * Return std::size_t from the hash helper in the ordered_json test MSVC (Win32) rejected the implicit conversion of the unsigned long long product to the 32-bit std::size_t (C4244 as an error). Also note when JSON_NO_THREAD_LOCAL is set in the regression test. 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> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> Signed-off-by: Claude <noreply@anthropic.com> Co-authored-by: Claude <noreply@anthropic.com>
130 lines
4.3 KiB
C++
130 lines
4.3 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
|
|
|
|
// This file contains the C++17-only part of unit-msgpack.cpp (std::byte
|
|
// input). It is kept in a separate translation unit so the (much larger)
|
|
// unit-msgpack.cpp does not need to be compiled and run a second time just
|
|
// for this one test case (#5418).
|
|
|
|
#include "doctest_compatibility.h"
|
|
|
|
#include <nlohmann/json.hpp>
|
|
using nlohmann::json;
|
|
|
|
#ifdef JSON_HAS_CPP_17
|
|
#include <cstddef>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Test suite for verifying MessagePack handling with std::byte input
|
|
TEST_CASE("MessagePack with std::byte")
|
|
{
|
|
|
|
SECTION("std::byte compatibility")
|
|
{
|
|
SECTION("vector roundtrip")
|
|
{
|
|
json original =
|
|
{
|
|
{"name", "test"},
|
|
{"value", 42},
|
|
{"array", {1, 2, 3}}
|
|
};
|
|
|
|
std::vector<uint8_t> temp = json::to_msgpack(original);
|
|
// Convert the uint8_t vector to std::byte vector
|
|
std::vector<std::byte> msgpack_data(temp.size());
|
|
for (size_t i = 0; i < temp.size(); ++i)
|
|
{
|
|
msgpack_data[i] = std::byte(temp[i]);
|
|
}
|
|
// Deserialize from std::byte vector back to JSON
|
|
json from_bytes;
|
|
CHECK_NOTHROW(from_bytes = json::from_msgpack(msgpack_data));
|
|
|
|
CHECK(from_bytes == original);
|
|
}
|
|
|
|
SECTION("empty vector")
|
|
{
|
|
const std::vector<std::byte> empty_data;
|
|
CHECK_THROWS_WITH_AS([&]()
|
|
{
|
|
[[maybe_unused]] auto result = json::from_msgpack(empty_data);
|
|
return true;
|
|
}
|
|
(),
|
|
"[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing MessagePack value: unexpected end of input",
|
|
json::parse_error&);
|
|
}
|
|
|
|
SECTION("comparison with workaround")
|
|
{
|
|
json original =
|
|
{
|
|
{"string", "hello"},
|
|
{"integer", 42},
|
|
{"float", 3.14},
|
|
{"boolean", true},
|
|
{"null", nullptr},
|
|
{"array", {1, 2, 3}},
|
|
{"object", {{"key", "value"}}}
|
|
};
|
|
|
|
std::vector<uint8_t> temp = json::to_msgpack(original);
|
|
|
|
std::vector<std::byte> msgpack_data(temp.size());
|
|
for (size_t i = 0; i < temp.size(); ++i)
|
|
{
|
|
msgpack_data[i] = std::byte(temp[i]);
|
|
}
|
|
// Attempt direct deserialization using std::byte input
|
|
const json direct_result = json::from_msgpack(msgpack_data);
|
|
|
|
// Test the workaround approach: reinterpret as unsigned char* and use iterator range
|
|
const auto* const char_start = reinterpret_cast<unsigned char const*>(msgpack_data.data());
|
|
const auto* const char_end = char_start + msgpack_data.size();
|
|
json workaround_result = json::from_msgpack(char_start, char_end);
|
|
|
|
// Verify that the final deserialized JSON matches the original JSON
|
|
CHECK(direct_result == workaround_result);
|
|
CHECK(direct_result == original);
|
|
}
|
|
}
|
|
}
|
|
|
|
// JSON text (not MessagePack) as std::byte input: the error position is
|
|
// computed from the bytes consumed so far
|
|
TEST_CASE("JSON text with std::byte")
|
|
{
|
|
const auto to_bytes = [](const std::string & text)
|
|
{
|
|
std::vector<std::byte> bytes;
|
|
for (const char c : text)
|
|
{
|
|
bytes.push_back(static_cast<std::byte>(c));
|
|
}
|
|
return bytes;
|
|
};
|
|
|
|
SECTION("valid text")
|
|
{
|
|
const json j = json::parse(to_bytes("[1,\n2]"));
|
|
CHECK(j == json({1, 2}));
|
|
CHECK(json::accept(to_bytes("[1,\n2]")));
|
|
}
|
|
|
|
SECTION("invalid text")
|
|
{
|
|
CHECK_FALSE(json::accept(to_bytes("[1,\n2,")));
|
|
CHECK_THROWS_WITH_AS(json::parse(to_bytes("[1,\n2,")),
|
|
"[json.exception.parse_error.101] parse error at line 2, column 3: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
|
|
}
|
|
}
|
|
#endif
|