Repository: nlohmann/json
File: tests/src/unit-deserialization.cpp (C++)

Code before:
    {
        if (elements == static_cast<std::size_t>(-1))
        {
            events.emplace_back("start_array()");
        }
        else
        {
            events.push_back("start_array(" + std::to_string(elements) + ")");
        }
        return false;
    }
};
} // namespace

// Passing a NULL pointer to the input adapter violates its NON_NULL attribute which is detected by UBSAN.
// To still test whether exceptions are thrown, we need to exclude these tests from UBSAN which can only
// be done with a function attribute. See
// https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#disabling-instrumentation-with-attribute-no-sanitize-undefined
#if defined(__clang__)
    __attribute__((no_sanitize("undefined")))
#endif
void test_file_exception();

#if defined(__clang__)
    __attribute__((no_sanitize("undefined")))
#endif
void test_file_exception()
{
    std::FILE* f = std::fopen("nonexisting_file", "r"); // NOLINT(cppcoreguidelines-owning-memory)
    json _;
    CHECK_THROWS_WITH_AS(_ = json::parse(f), "[json.exception.parse_error.116] parse error: input file is invalid", json::parse_error&);
    CHECK_THROWS_WITH_AS(_ = json::accept(f), "[json.exception.parse_error.116] parse error: input file is invalid", json::parse_error&);
}

TEST_CASE("deserialization")
{
    SECTION("successful deserialization")
    {
        SECTION("stream")
        {
            std::stringstream ss1;
            std::stringstream ss2;
            std::stringstream ss3;
            ss1 << R"(["foo",1,2,3,false,{"one":1}])";
            ss2 << R"(["foo",1,2,3,false,{"one":1}])";
            ss3 << R"(["foo",1,2,3,false,{"one":1}])";
            json j = json::parse(ss1);
            CHECK(json::accept(ss2));
            CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));

            SaxEventLogger l;

Review comment (suggestion):
I don't think you need to repeat the attribute, i.e., keep it on the prototype. Not 100% sure though.

Code after:
    {
        if (elements == static_cast<std::size_t>(-1))
        {
            events.emplace_back("start_array()");
        }
        else
        {
            events.push_back("start_array(" + std::to_string(elements) + ")");
        }
        return false;
    }
};
} // namespace

TEST_CASE("deserialization")
{
    SECTION("successful deserialization")
    {
        SECTION("stream")
        {
            std::stringstream ss1;
            std::stringstream ss2;
            std::stringstream ss3;
            ss1 << R"(["foo",1,2,3,false,{"one":1}])";
            ss2 << R"(["foo",1,2,3,false,{"one":1}])";
            ss3 << R"(["foo",1,2,3,false,{"one":1}])";
            json j = json::parse(ss1);
            CHECK(json::accept(ss2));
            CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));

            SaxEventLogger l;
            CHECK(json::sax_parse(ss3, &l));
            CHECK(l.events.size() == 11);
            CHECK(l.events == std::vector<std::string>(
            {
                "start_array()", "string(foo)", "number_unsigned(1)",
                "number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
                "start_object()", "key(one)", "number_unsigned(1)",
                "end_object()", "end_array()"
            }));
        }

        SECTION("string literal")
        {
            const auto* s = R"(["foo",1,2,3,false,{"one":1}])";
            json j = json::parse(s);
            CHECK(json::accept(s));
            CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));

            SaxEventLogger l;
            CHECK(json::sax_parse(s, &l));