diff --git a/tests/src/unit-allocator.cpp b/tests/src/unit-allocator.cpp index e1dee5509..8fa9034b5 100644 --- a/tests/src/unit-allocator.cpp +++ b/tests/src/unit-allocator.cpp @@ -1038,6 +1038,14 @@ template struct sweep_allocator { using value_type = T; + // GCC 4.8's std::map takes these from the allocator instead of from + // std::allocator_traits + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; sweep_allocator() = default; template sweep_allocator(const sweep_allocator& /*unused*/) noexcept {} @@ -1155,9 +1163,14 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)") // With iterator debugging (MSVC STL debug builds, also used by clang-cl), // containers allocate a debug proxy through the allocator inside their - // noexcept move constructors, so failing that allocation terminates the - // program instead of throwing std::bad_alloc. Nothing to check there. + // noexcept default and move constructors, so failing that allocation + // terminates the program instead of throwing std::bad_alloc. Nothing to + // check there. #if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0) + // Clang 3.4 and 3.5 leak memory when an element constructor throws + // inside libstdc++'s containers (a std::map copy, a std::vector + // reallocation), without any json value involved. +#if !(defined(__clang__) && !defined(__apple_build_version__) && __clang_major__ == 3 && __clang_minor__ < 6) SECTION("parser callback") { const auto keep_all = [](int /*depth*/, sweep_json::parse_event_t /*event*/, sweep_json& /*parsed*/) noexcept @@ -1178,7 +1191,6 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)") return sweep_json::parse(text, drop_d); }); } -#endif SECTION("sax_parse into an existing value") { @@ -1192,5 +1204,7 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)") return value; }); } +#endif +#endif } #endif diff --git a/tests/src/unit-class_lexer.cpp b/tests/src/unit-class_lexer.cpp index 0e8b22317..616999896 100644 --- a/tests/src/unit-class_lexer.cpp +++ b/tests/src/unit-class_lexer.cpp @@ -2222,9 +2222,10 @@ TEST_CASE("serialization of short strings") { CAPTURE(s) const json j = s; - CHECK(j.dump() == "\"" + s + "\""); - CHECK(j.dump(-1, ' ', true) == "\"" + s + "\""); - CHECK(json({{s, s}}).dump() == "{\"" + s + "\":\"" + s + "\"}"); + const std::string quoted = "\"" + s + "\""; // NOLINT(performance-inefficient-string-concatenation) + CHECK(j.dump() == quoted); + CHECK(j.dump(-1, ' ', true) == quoted); + CHECK(json({{s, s}}).dump() == "{" + quoted + ":" + quoted + "}"); // NOLINT(performance-inefficient-string-concatenation) } // a character that needs an escape diff --git a/tests/src/unit-custom-object-key-type.cpp b/tests/src/unit-custom-object-key-type.cpp index acb78d628..9149bbfb6 100644 --- a/tests/src/unit-custom-object-key-type.cpp +++ b/tests/src/unit-custom-object-key-type.cpp @@ -160,12 +160,12 @@ class strict_key } private: - std::string m_value{}; + std::string m_value; }; strict_key make_strict_key(const std::string& key) { - return strict_key(key.c_str()); + return {key.c_str()}; } template @@ -224,7 +224,9 @@ TEST_CASE("converting a value with keys that cannot be made from a std::string n } } - const strict_json converted = value; + // direct-initialization: a copy-initialization makes GCC 4.8 instantiate the + // copy constructor, which needs a range constructor strict_object lacks + const strict_json converted(value); // at() needs to make a std::string of a key for its error message const auto member = [](const strict_json & object, const char* name) -> const strict_json & diff --git a/tests/src/unit-json_view.cpp b/tests/src/unit-json_view.cpp index e383dbdac..65180ef55 100644 --- a/tests/src/unit-json_view.cpp +++ b/tests/src/unit-json_view.cpp @@ -105,19 +105,53 @@ template struct failing_allocator { using value_type = T; + // GCC 4.8's std::map takes these from the allocator instead of from + // std::allocator_traits + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + template + struct rebind + { + using other = failing_allocator; + }; failing_allocator() = default; template explicit failing_allocator(const failing_allocator& /*other*/) noexcept {} - T* allocate(std::size_t /*n*/) // NOLINT(readability-convert-member-functions-to-static) + [[noreturn]] T* allocate(std::size_t /*n*/) // NOLINT(readability-convert-member-functions-to-static) { throw std::bad_alloc(); } void deallocate(T* /*p*/, std::size_t /*n*/) noexcept {} // NOLINT(readability-convert-member-functions-to-static) + // GCC 4.8's std::map calls these on the allocator directly instead of + // going through std::allocator_traits + std::size_t max_size() const noexcept // NOLINT(readability-convert-member-functions-to-static) + { + return (std::numeric_limits::max)() / sizeof(T); + } + + template + void construct(U* p, Args&& ... args) // NOLINT(readability-convert-member-functions-to-static) + { + ::new (static_cast(p)) U(std::forward(args)...); + } + + template + void destroy(U* p) noexcept // NOLINT(readability-convert-member-functions-to-static) + { + static_cast(p); // unused for trivially destructible types + p->~U(); + } + template bool operator==(const failing_allocator& /*other*/) const noexcept { @@ -270,7 +304,7 @@ TEST_CASE("json_view") "\"", "\"abc", "\"\\x\"", "\"\\u12\"", "\"\\ud800\"", "\"\\udc00\"", "\"\x01\"", "\"\xff\"", "\"\xc3\"", "[1]x", "/", "/*", "[\n 1,\n x\n]", // NOLINT(modernize-raw-string-literal) "1e400", "-1e400", "[1.7976931348623159e308]", "{\"a\":\n{\"b\": [1, 2,\n 3 x]}}", // (an error after every kind of value: the error is found by replaying the parser) - "[null, true, -1, 1, 1.5, \"s\", {\"a\": 1} 2]", "{\"a\": null, \"b\": -1, \"c\": 1.5, \"d\": \"s\", \"e\": {}, 1}" + R"([null, true, -1, 1, 1.5, "s", {"a": 1} 2])", R"({"a": null, "b": -1, "c": 1.5, "d": "s", "e": {}, 1})" }) { CAPTURE(text) @@ -1556,7 +1590,7 @@ TEST_CASE("json_view values") CHECK_THROWS_WITH_AS(not_an_object.root().get(), json_view_test::message("type_error.302", "", 0, 5, "type must be object, but is array").c_str(), json::type_error&); #if !defined(JSON_NOEXCEPTION) // (and one that cannot allocate its nodes) - using failing_map = std::map, failing_allocator>>; + using failing_map = std::map, failing_allocator>>; // NOLINT(modernize-use-transparent-functors) const json_document one_member = json_document::parse(R"({"a":1})"); CHECK_THROWS_AS(one_member.root().get(), std::bad_alloc&); #endif diff --git a/tests/src/unit-locale-cpp.cpp b/tests/src/unit-locale-cpp.cpp index 9a6ad8de2..10143326a 100644 --- a/tests/src/unit-locale-cpp.cpp +++ b/tests/src/unit-locale-cpp.cpp @@ -533,7 +533,7 @@ struct locale_switching_token { switched = std::setlocale(LC_NUMERIC, switch_to.c_str()) != nullptr; } - return &text[0]; + return &text[0]; // NOLINT(readability-container-data-pointer): std::string::data() is const before C++17 } std::string text; @@ -655,7 +655,7 @@ TEST_CASE("convert_float_locale_aware") // "C" -> comma locale: strtod stops at the '.', so the conversion is repeated { - locale_switching_token token("1.5", comma_locale.c_str()); + locale_switching_token token("1.5", comma_locale); double value = 0; nlohmann::detail::convert_float_locale_aware(token, 1, value); if (token.switched) @@ -668,7 +668,7 @@ TEST_CASE("convert_float_locale_aware") // the same for the other floating-point types REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr); { - locale_switching_token token("2.25", comma_locale.c_str()); + locale_switching_token token("2.25", comma_locale); float value = 0; nlohmann::detail::convert_float_locale_aware(token, 1, value); if (token.switched) @@ -678,7 +678,7 @@ TEST_CASE("convert_float_locale_aware") } REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr); { - locale_switching_token token("2.25", comma_locale.c_str()); + locale_switching_token token("2.25", comma_locale); long double value = 0; nlohmann::detail::convert_float_locale_aware(token, 1, value); if (token.switched) diff --git a/tests/src/unit-msgpack-cpp17.cpp b/tests/src/unit-msgpack-cpp17.cpp index 6b6b207bf..8b2349b90 100644 --- a/tests/src/unit-msgpack-cpp17.cpp +++ b/tests/src/unit-msgpack-cpp17.cpp @@ -122,7 +122,8 @@ TEST_CASE("JSON text with std::byte") SECTION("invalid text") { CHECK_FALSE(json::accept(to_bytes("[1,\n2,"))); - CHECK_THROWS_WITH_AS(json::parse(to_bytes("[1,\n2,")), + json _; + 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&); } } diff --git a/tests/src/unit-ordered_json.cpp b/tests/src/unit-ordered_json.cpp index 8c07ffa16..4d894e649 100644 --- a/tests/src/unit-ordered_json.cpp +++ b/tests/src/unit-ordered_json.cpp @@ -541,6 +541,7 @@ TEST_CASE("object_key_index") }; std::vector hashes; + hashes.reserve(initial); for (std::size_t i = 0; i < initial; ++i) { hashes.push_back(hash_of(i)); diff --git a/tests/src/unit-regression1.cpp b/tests/src/unit-regression1.cpp index 53f501f07..367f52dfa 100644 --- a/tests/src/unit-regression1.cpp +++ b/tests/src/unit-regression1.cpp @@ -1533,7 +1533,7 @@ TEST_CASE("regression tests 1") { my_json::object_t top = orig.get_ref(); top.at("x") = my_json::parse(R"({"a":{"b":1},"n":null,"arr":[10,20],"objs":[{"m":5},{"m":6}]})"); - return my_json(std::move(top)); + return my_json(std::move(top)); // NOLINT(modernize-return-braced-init-list): {top} would be an array }; SECTION("existing members") diff --git a/tests/src/unit-stream-bulk-scan.cpp b/tests/src/unit-stream-bulk-scan.cpp index 0e0fbd72e..f6869847d 100644 --- a/tests/src/unit-stream-bulk-scan.cpp +++ b/tests/src/unit-stream-bulk-scan.cpp @@ -120,6 +120,7 @@ class oversized_get_area_streambuf : public std::streambuf private: std::array m_data{{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}; }; + #endif // how a test reads from the stream @@ -463,15 +464,18 @@ TEST_CASE("parsing from a std::istream scans the get area in bulk") CHECK(token.empty()); } +#if SIZE_MAX > UINT32_MAX + // a get area larger than an int needs a 64-bit std::size_t (checked by the + // preprocessor, as a constant condition triggers MSVC's C4127) SECTION("skipping more characters than gbump() takes at once") { // gbump() takes an int, but a get area can be larger - const std::size_t claimed = sizeof(std::size_t) < 8 ? 0 : std::size_t{3} << 30u; + const std::size_t claimed = std::size_t{3} << 30u; oversized_get_area_streambuf buf(claimed); - if (claimed == 0 || static_cast(buf.in_avail()) != claimed) + if (static_cast(buf.in_avail()) != claimed) { - // a 32-bit size_t, or a standard library whose streambuf stores - // the size of the get area in an int (MSVC) + // 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 @@ -491,6 +495,7 @@ TEST_CASE("parsing from a std::istream scans the get area in bulk") buf.restore_get_area(); } } +#endif #endif SECTION("SAX parsing from a stream")