mirror of
https://github.com/nlohmann/json.git
synced 2026-11-02 10:55:35 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16ed40b2d4 | ||
|
|
b2674a4a2f | ||
|
|
e2423a1857 | ||
|
|
67b103e506 |
No files matched your search
@@ -24,7 +24,7 @@ jobs:
|
||||
permissions:
|
||||
actions: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
|
||||
@@ -19,7 +19,7 @@ permissions:
|
||||
jobs:
|
||||
save:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
|
||||
|
||||
@@ -16,7 +16,7 @@ concurrency:
|
||||
jobs:
|
||||
check_docs_links:
|
||||
if: github.repository == 'nlohmann/json'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
comment:
|
||||
# push runs on develop have no PR to comment on (and no "pr" artifact)
|
||||
if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
|
||||
@@ -18,7 +18,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
|
||||
|
||||
@@ -24,7 +24,7 @@ on:
|
||||
jobs:
|
||||
flawfinder:
|
||||
name: Flawfinder
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
contents: write
|
||||
|
||||
if: github.repository == 'nlohmann/json'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
|
||||
|
||||
@@ -24,7 +24,7 @@ permissions:
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
|
||||
@@ -8,7 +8,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
@@ -18,7 +18,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
ci_test_gcc:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container: gcc:latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -130,7 +130,7 @@ jobs:
|
||||
run: cmake --build build --target ${{ matrix.target }}
|
||||
|
||||
ci_static_analysis_clang:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container: silkeh/clang:22
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -149,7 +149,7 @@ jobs:
|
||||
run: cmake --build build --target ${{ matrix.target }}
|
||||
|
||||
ci_cmake_options:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container: ubuntu:24.04
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -209,7 +209,7 @@ jobs:
|
||||
fail-on-error: false
|
||||
|
||||
ci_test_compilers_gcc_old:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ['4.8', '4.9', '5', '6']
|
||||
@@ -251,7 +251,7 @@ jobs:
|
||||
run: cmake --build build --target ci_test_compiler_g++-${{ matrix.compiler }}
|
||||
|
||||
ci_test_compilers_gcc:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
matrix:
|
||||
# older GCC docker images (4, 5, 6) fail to check out code
|
||||
@@ -269,7 +269,7 @@ jobs:
|
||||
run: cmake --build build --target ci_test_compiler_default
|
||||
|
||||
ci_test_compilers_clang:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', '21', '22', 'latest']
|
||||
@@ -289,7 +289,7 @@ jobs:
|
||||
run: cmake --build build --target ci_test_compiler_default
|
||||
|
||||
ci_test_standards_gcc:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container: gcc:latest
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -306,7 +306,7 @@ jobs:
|
||||
run: cmake --build build --target ci_test_gcc_cxx${{ matrix.standard }}
|
||||
|
||||
ci_test_standards_clang:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container: silkeh/clang:latest
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -330,7 +330,7 @@ jobs:
|
||||
if: ${{ matrix.stdlib == 'libstdcxx' }}
|
||||
|
||||
ci_cuda_example:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -356,7 +356,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
container: ['gcc:latest', 'silkeh/clang:latest']
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container: ${{ matrix.container }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -383,7 +383,7 @@ jobs:
|
||||
run: cmake --build build --target ci_module_cpp20
|
||||
|
||||
ci_icpc:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
# Intel discontinued the classic icc/icpc compiler in oneAPI 2024.0; this is
|
||||
# Intel's own last officially published image that still includes it.
|
||||
container: intel/oneapi-hpckit:2023.2.1-devel-ubuntu22.04
|
||||
@@ -402,7 +402,7 @@ jobs:
|
||||
run: cmake --build build --target ci_icpc
|
||||
|
||||
ci_icpx:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container: intel/oneapi-hpckit:latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -416,7 +416,7 @@ jobs:
|
||||
run: cmake --build build --target ci_icpx
|
||||
|
||||
ci_nvhpc:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container: nvcr.io/nvidia/nvhpc:25.5-devel-cuda12.9-ubuntu22.04
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
@@ -467,11 +467,13 @@ class binary_reader
|
||||
|
||||
const std::size_t element_type_parse_position = chars_read;
|
||||
// an array's elements are named "0", "1", ... in the wire format,
|
||||
// and those names are not passed on: they are skipped unless
|
||||
// error_handler_t::strict must reject ill-formed UTF-8 in them
|
||||
// and those names are not passed on: they are skipped, and only
|
||||
// checked if error_handler_t::strict must reject ill-formed UTF-8
|
||||
const bool is_object = container_stack.back().is_object;
|
||||
key.clear();
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key, is_object || error_handler == error_handler_t::strict)))
|
||||
if (JSON_HEDLEY_UNLIKELY(!(is_object || error_handler != error_handler_t::strict
|
||||
? get_bson_cstr(key, is_object)
|
||||
: check_bson_cstr(key, std::integral_constant<bool, bulk_scan> {}))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -495,7 +497,7 @@ class binary_reader
|
||||
@param[in] store whether the characters are needed; if not (the names of
|
||||
an array's elements), they are skipped and @a result may
|
||||
be left unchanged, and they are not checked against
|
||||
@ref error_handler
|
||||
@ref error_handler (@ref check_bson_cstr checks them)
|
||||
@return `true` if the \\x00-byte indicating the end of the string was
|
||||
encountered before the EOF; false` indicates an unexpected EOF.
|
||||
*/
|
||||
@@ -554,6 +556,42 @@ class binary_reader
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief skip a C-style string that error_handler_t::strict must check
|
||||
|
||||
The names of an array's elements are not passed on. On contiguous input,
|
||||
a well-formed name is checked in place and skipped without being copied.
|
||||
Otherwise (no \\x00-byte in the input that can be scanned, or ill-formed
|
||||
UTF-8), it is read by @ref get_bson_cstr, which reports the error.
|
||||
|
||||
@param[in,out] result an empty string, which may receive the name
|
||||
@return whether the name was read and is well-formed
|
||||
*/
|
||||
bool check_bson_cstr(string_t& result, std::true_type /*bulk*/)
|
||||
{
|
||||
const std::size_t remaining = ia.bulk_remaining();
|
||||
if (remaining != 0)
|
||||
{
|
||||
const auto* const data = reinterpret_cast<const unsigned char*>(ia.bulk_data());
|
||||
const std::size_t length = find_zero_byte(data, remaining);
|
||||
if (length != remaining && JSON_HEDLEY_LIKELY(valid_utf8_string(data, length)))
|
||||
{
|
||||
// consume the string and its \x00-byte, as get_bson_cstr does
|
||||
ia.bulk_skip(length + 1);
|
||||
chars_read += length + 1;
|
||||
current = 0x00;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return get_bson_cstr(result);
|
||||
}
|
||||
|
||||
/// input that is not contiguous: the name is read and checked byte by byte
|
||||
bool check_bson_cstr(string_t& result, std::false_type /*bulk*/)
|
||||
{
|
||||
return get_bson_cstr(result);
|
||||
}
|
||||
|
||||
/// input that is not contiguous: C-style strings are read byte by byte
|
||||
bool get_bson_cstr_bulk(string_t& /*result*/, const bool /*store*/, std::false_type /*bulk*/) const noexcept
|
||||
{
|
||||
@@ -1818,14 +1856,18 @@ class binary_reader
|
||||
|
||||
Only the start of an array is tried, which covers arrays of numbers
|
||||
(e.g. coordinates) but costs arrays of other values only one call, not one
|
||||
per element.
|
||||
per element. An array of one element is not tried at all: that element is
|
||||
mostly an object or an array (`[[...]]`, the single ring of a GeoJSON
|
||||
polygon), for which the call would find no scalar, while a single scalar,
|
||||
which the run would read faster, is rare. The benchmarks
|
||||
`FromBinaryShape/nested` and `FromBinaryShape/singles` show both sides.
|
||||
|
||||
@param[in] len the number of elements
|
||||
@return whether the SAX parser accepted the array and the values read
|
||||
*/
|
||||
bool enter_cbor_array(const std::size_t len)
|
||||
{
|
||||
return enter_array(len) && (len == 0 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
return enter_array(len) && (len <= 1 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
}
|
||||
|
||||
/// input that is not contiguous: every value is read by parse_cbor_value
|
||||
@@ -2726,12 +2768,16 @@ class binary_reader
|
||||
/*!
|
||||
@brief open a MessagePack array and read the scalars it begins with (see
|
||||
@ref parse_msgpack_scalar_run)
|
||||
|
||||
An array of one element is not tried, for the reason given at
|
||||
@ref enter_cbor_array.
|
||||
|
||||
@param[in] len the number of elements
|
||||
@return whether the SAX parser accepted the array and the values read
|
||||
*/
|
||||
bool enter_msgpack_array(const std::size_t len)
|
||||
{
|
||||
return enter_array(len) && (len == 0 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
return enter_array(len) && (len <= 1 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
}
|
||||
|
||||
/// input that is not contiguous: every value is read by parse_msgpack_value
|
||||
|
||||
Generated
+53
-7
@@ -18474,11 +18474,13 @@ class binary_reader
|
||||
|
||||
const std::size_t element_type_parse_position = chars_read;
|
||||
// an array's elements are named "0", "1", ... in the wire format,
|
||||
// and those names are not passed on: they are skipped unless
|
||||
// error_handler_t::strict must reject ill-formed UTF-8 in them
|
||||
// and those names are not passed on: they are skipped, and only
|
||||
// checked if error_handler_t::strict must reject ill-formed UTF-8
|
||||
const bool is_object = container_stack.back().is_object;
|
||||
key.clear();
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key, is_object || error_handler == error_handler_t::strict)))
|
||||
if (JSON_HEDLEY_UNLIKELY(!(is_object || error_handler != error_handler_t::strict
|
||||
? get_bson_cstr(key, is_object)
|
||||
: check_bson_cstr(key, std::integral_constant<bool, bulk_scan> {}))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -18502,7 +18504,7 @@ class binary_reader
|
||||
@param[in] store whether the characters are needed; if not (the names of
|
||||
an array's elements), they are skipped and @a result may
|
||||
be left unchanged, and they are not checked against
|
||||
@ref error_handler
|
||||
@ref error_handler (@ref check_bson_cstr checks them)
|
||||
@return `true` if the \\x00-byte indicating the end of the string was
|
||||
encountered before the EOF; false` indicates an unexpected EOF.
|
||||
*/
|
||||
@@ -18561,6 +18563,42 @@ class binary_reader
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief skip a C-style string that error_handler_t::strict must check
|
||||
|
||||
The names of an array's elements are not passed on. On contiguous input,
|
||||
a well-formed name is checked in place and skipped without being copied.
|
||||
Otherwise (no \\x00-byte in the input that can be scanned, or ill-formed
|
||||
UTF-8), it is read by @ref get_bson_cstr, which reports the error.
|
||||
|
||||
@param[in,out] result an empty string, which may receive the name
|
||||
@return whether the name was read and is well-formed
|
||||
*/
|
||||
bool check_bson_cstr(string_t& result, std::true_type /*bulk*/)
|
||||
{
|
||||
const std::size_t remaining = ia.bulk_remaining();
|
||||
if (remaining != 0)
|
||||
{
|
||||
const auto* const data = reinterpret_cast<const unsigned char*>(ia.bulk_data());
|
||||
const std::size_t length = find_zero_byte(data, remaining);
|
||||
if (length != remaining && JSON_HEDLEY_LIKELY(valid_utf8_string(data, length)))
|
||||
{
|
||||
// consume the string and its \x00-byte, as get_bson_cstr does
|
||||
ia.bulk_skip(length + 1);
|
||||
chars_read += length + 1;
|
||||
current = 0x00;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return get_bson_cstr(result);
|
||||
}
|
||||
|
||||
/// input that is not contiguous: the name is read and checked byte by byte
|
||||
bool check_bson_cstr(string_t& result, std::false_type /*bulk*/)
|
||||
{
|
||||
return get_bson_cstr(result);
|
||||
}
|
||||
|
||||
/// input that is not contiguous: C-style strings are read byte by byte
|
||||
bool get_bson_cstr_bulk(string_t& /*result*/, const bool /*store*/, std::false_type /*bulk*/) const noexcept
|
||||
{
|
||||
@@ -19825,14 +19863,18 @@ class binary_reader
|
||||
|
||||
Only the start of an array is tried, which covers arrays of numbers
|
||||
(e.g. coordinates) but costs arrays of other values only one call, not one
|
||||
per element.
|
||||
per element. An array of one element is not tried at all: that element is
|
||||
mostly an object or an array (`[[...]]`, the single ring of a GeoJSON
|
||||
polygon), for which the call would find no scalar, while a single scalar,
|
||||
which the run would read faster, is rare. The benchmarks
|
||||
`FromBinaryShape/nested` and `FromBinaryShape/singles` show both sides.
|
||||
|
||||
@param[in] len the number of elements
|
||||
@return whether the SAX parser accepted the array and the values read
|
||||
*/
|
||||
bool enter_cbor_array(const std::size_t len)
|
||||
{
|
||||
return enter_array(len) && (len == 0 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
return enter_array(len) && (len <= 1 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
}
|
||||
|
||||
/// input that is not contiguous: every value is read by parse_cbor_value
|
||||
@@ -20733,12 +20775,16 @@ class binary_reader
|
||||
/*!
|
||||
@brief open a MessagePack array and read the scalars it begins with (see
|
||||
@ref parse_msgpack_scalar_run)
|
||||
|
||||
An array of one element is not tried, for the reason given at
|
||||
@ref enter_cbor_array.
|
||||
|
||||
@param[in] len the number of elements
|
||||
@return whether the SAX parser accepted the array and the values read
|
||||
*/
|
||||
bool enter_msgpack_array(const std::size_t len)
|
||||
{
|
||||
return enter_array(len) && (len == 0 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
return enter_array(len) && (len <= 1 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
}
|
||||
|
||||
/// input that is not contiguous: every value is read by parse_msgpack_value
|
||||
|
||||
@@ -629,6 +629,22 @@ static json make_containers()
|
||||
return j;
|
||||
}
|
||||
|
||||
/// many arrays of one number each: one-element arrays are left to the general
|
||||
/// path (CBOR and MessagePack), which reads a lone number slower than the loop
|
||||
/// for arrays of scalars would
|
||||
static json make_singles()
|
||||
{
|
||||
json data = json::array();
|
||||
for (std::size_t i = 0; i < 100000; ++i)
|
||||
{
|
||||
data.push_back(json::array({i}));
|
||||
}
|
||||
|
||||
json j = json::object();
|
||||
j["data"] = std::move(data);
|
||||
return j;
|
||||
}
|
||||
|
||||
/// one flat array of numbers: the scalar decoding path, which must not move
|
||||
static json make_scalars()
|
||||
{
|
||||
@@ -676,6 +692,8 @@ BENCHMARK_CAPTURE(FromBinaryShape, containers / ubjson_optimized, make_container
|
||||
BENCHMARK_CAPTURE(FromBinaryShape, containers / bjdata, make_containers, binary_format::bjdata);
|
||||
BENCHMARK_CAPTURE(FromBinaryShape, containers / bson, make_containers, binary_format::bson);
|
||||
BENCHMARK_CAPTURE(FromBinaryShape, containers / bon8, make_containers, binary_format::bon8);
|
||||
BENCHMARK_CAPTURE(FromBinaryShape, singles / cbor, make_singles, binary_format::cbor);
|
||||
BENCHMARK_CAPTURE(FromBinaryShape, singles / msgpack, make_singles, binary_format::msgpack);
|
||||
// BSON names every array element, so a large array measures key generation
|
||||
// rather than scalar decoding and is left out here
|
||||
BENCHMARK_CAPTURE(FromBinaryShape, scalars / cbor, make_scalars, binary_format::cbor);
|
||||
|
||||
@@ -23,6 +23,7 @@ using nlohmann::json;
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "make_test_data_available.hpp"
|
||||
@@ -1199,6 +1200,31 @@ TEST_CASE("BSON keys from contiguous and stream input")
|
||||
from_stream = e.what();
|
||||
}
|
||||
CHECK(from_vector == from_stream);
|
||||
|
||||
// error_handler_t::strict checks the array element names in place on
|
||||
// contiguous input and byte by byte otherwise; the names are
|
||||
// well-formed, so both give the same value or error as above
|
||||
std::string strict_from_vector;
|
||||
std::string strict_from_list;
|
||||
try
|
||||
{
|
||||
strict_from_vector = json::from_bson(input, true, true, json::error_handler_t::strict).dump();
|
||||
}
|
||||
catch (const json::parse_error& e)
|
||||
{
|
||||
strict_from_vector = e.what();
|
||||
}
|
||||
try
|
||||
{
|
||||
const std::list<std::uint8_t> list(input.begin(), input.end());
|
||||
strict_from_list = json::from_bson(list.begin(), list.end(), true, true, json::error_handler_t::strict).dump();
|
||||
}
|
||||
catch (const json::parse_error& e)
|
||||
{
|
||||
strict_from_list = e.what();
|
||||
}
|
||||
CHECK(strict_from_vector == from_vector);
|
||||
CHECK(strict_from_list == from_vector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1227,6 +1253,18 @@ TEST_CASE("BSON array element names")
|
||||
|
||||
std::istringstream stream(std::string(reinterpret_cast<const char*>(bson.data()), bson.size()));
|
||||
CHECK(json::from_bson(stream) == expected);
|
||||
|
||||
// input that is not contiguous reads the names byte by byte and must reject
|
||||
// the same name
|
||||
const std::list<std::uint8_t> list(bson.begin(), bson.end());
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(list.begin(), list.end(), true, true, json::error_handler_t::strict), "[json.exception.parse_error.113] parse error at byte 14: syntax error while parsing BSON key: invalid string: ill-formed UTF-8 byte", json::parse_error&);
|
||||
|
||||
// without exceptions, the rejected name ends the parse
|
||||
CHECK(json::from_bson(bson, true, false, json::error_handler_t::strict).is_discarded());
|
||||
|
||||
// well-formed names pass the check without being stored
|
||||
const json valid = {{"a", {true, false, {{"k", json::array({1, 2})}}}}};
|
||||
CHECK(json::from_bson(json::to_bson(valid), true, true, json::error_handler_t::strict) == valid);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2520,6 +2520,34 @@ TEST_CASE("CBOR arrays of scalars from contiguous and non-contiguous input")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CBOR arrays of one element from contiguous and non-contiguous input")
|
||||
{
|
||||
// contiguous input leaves an array of one element to the general path
|
||||
// rather than to the loop that reads arrays of scalars; both inputs must
|
||||
// still give the same events, value, or error for the complete document
|
||||
// and for every truncation of it, with enough bytes after each array that
|
||||
// the loop could have been entered
|
||||
const json j = json::parse(R"({"a": [[[[1.5]]]], "b": [7], "c": [{"x": 2.5}], "d": ["s"], "e": [[1, 2]], "f": [null], "g": 1.25})");
|
||||
const std::vector<std::uint8_t> bytes = json::to_cbor(j);
|
||||
|
||||
CHECK(json::from_cbor(bytes) == j);
|
||||
|
||||
for (std::size_t length = 0; length <= bytes.size(); ++length)
|
||||
{
|
||||
CAPTURE(length)
|
||||
const std::vector<std::uint8_t> contiguous(bytes.begin(), bytes.begin() + static_cast<std::ptrdiff_t>(length));
|
||||
const std::list<std::uint8_t> bytewise(contiguous.begin(), contiguous.end());
|
||||
|
||||
CHECK(json::from_cbor(contiguous, true, false).dump() == json::from_cbor(bytewise.begin(), bytewise.end(), true, false).dump());
|
||||
|
||||
SaxEventLogger from_contiguous;
|
||||
SaxEventLogger from_bytewise;
|
||||
CHECK(json::sax_parse(contiguous, &from_contiguous, json::input_format_t::cbor, true, false)
|
||||
== json::sax_parse(bytewise.begin(), bytewise.end(), &from_bytewise, json::input_format_t::cbor, true, false));
|
||||
CHECK(from_contiguous.events == from_bytewise.events);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CBOR indefinite-length strings do not recurse per chunk")
|
||||
{
|
||||
// Reading an indefinite-length string or byte array used to call itself
|
||||
|
||||
@@ -692,7 +692,7 @@ TEST_CASE("json_view builder: fraction digits")
|
||||
check_same(number);
|
||||
check_same("[" + number + "]");
|
||||
std::string pair;
|
||||
pair.reserve(number.size() * 2 + 3);
|
||||
pair.reserve((number.size() * 2) + 3);
|
||||
pair += '[';
|
||||
pair += number;
|
||||
pair += ',';
|
||||
|
||||
@@ -521,7 +521,8 @@ TEST_CASE("json_view exceptions name the path and the bytes of the value")
|
||||
std::string text = "7";
|
||||
for (int level = 0; level < 40; ++level)
|
||||
{
|
||||
text = R"([[1, [2]], )" + text + R"(, {"k": [3, {"l": [4]}]}, [5, [6, [7]]]])";
|
||||
text.insert(0, R"([[1, [2]], )");
|
||||
text += R"(, {"k": [3, {"l": [4]}]}, [5, [6, [7]]]])";
|
||||
}
|
||||
CAPTURE(text)
|
||||
const json j = json::parse(text);
|
||||
|
||||
@@ -2311,3 +2311,31 @@ TEST_CASE("MessagePack arrays of scalars from contiguous and non-contiguous inpu
|
||||
== json::sax_parse(bytewise.begin(), bytewise.end(), &from_bytewise, json::input_format_t::msgpack));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MessagePack arrays of one element from contiguous and non-contiguous input")
|
||||
{
|
||||
// contiguous input leaves an array of one element to the general path
|
||||
// rather than to the loop that reads arrays of scalars; both inputs must
|
||||
// still give the same events, value, or error for the complete document
|
||||
// and for every truncation of it, with enough bytes after each array that
|
||||
// the loop could have been entered
|
||||
const json j = json::parse(R"({"a": [[[[1.5]]]], "b": [7], "c": [{"x": 2.5}], "d": ["s"], "e": [[1, 2]], "f": [null], "g": 1.25})");
|
||||
const std::vector<std::uint8_t> bytes = json::to_msgpack(j);
|
||||
|
||||
CHECK(json::from_msgpack(bytes) == j);
|
||||
|
||||
for (std::size_t length = 0; length <= bytes.size(); ++length)
|
||||
{
|
||||
CAPTURE(length)
|
||||
const std::vector<std::uint8_t> contiguous(bytes.begin(), bytes.begin() + static_cast<std::ptrdiff_t>(length));
|
||||
const std::list<std::uint8_t> bytewise(contiguous.begin(), contiguous.end());
|
||||
|
||||
CHECK(json::from_msgpack(contiguous, true, false).dump() == json::from_msgpack(bytewise.begin(), bytewise.end(), true, false).dump());
|
||||
|
||||
SaxEventLogger from_contiguous;
|
||||
SaxEventLogger from_bytewise;
|
||||
CHECK(json::sax_parse(contiguous, &from_contiguous, json::input_format_t::msgpack, true, false)
|
||||
== json::sax_parse(bytewise.begin(), bytewise.end(), &from_bytewise, json::input_format_t::msgpack, true, false));
|
||||
CHECK(from_contiguous.events == from_bytewise.events);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user