#include "simdjson.h" #include "test_ondemand.h" using namespace simdjson; namespace error_tests { using namespace std; bool issue2120() { TEST_START(); ondemand::parser parser; size_t bad_capacity = 0; ondemand::document doc; ASSERT_ERROR( parser.iterate("{\"a\": 0 }", bad_capacity).get(doc), INSUFFICIENT_PADDING); TEST_SUCCEED(); } bool badbadjson() { TEST_START(); ondemand::parser parser; auto json_string = R"({ "main": "therain"_"in_spain"_ })"_padded; ondemand::document document; auto error = parser.iterate(json_string).get(document); if(error != simdjson::SUCCESS) { return false; } ondemand::object obj; error = document.get_object().get(obj); if(error != simdjson::SUCCESS) { return false; } std::string_view name_value{}; error = obj["name"].get_string().get(name_value); ASSERT_ERROR(error,TAPE_ERROR); // Check for "main" field std::string_view main_value{}; error = obj["main"].get_string().get(main_value); ASSERT_ERROR(error,TAPE_ERROR); TEST_SUCCEED(); } bool badbadjson2() { TEST_START(); ondemand::parser parser; auto json_string = R"({ "main": "therain"_"in_spain"_ })"_padded; ondemand::document document; auto error = parser.iterate(json_string).get(document); if(error != simdjson::SUCCESS) { return false; } ondemand::object obj; error = document.get_object().get(obj); if(error != simdjson::SUCCESS) { return false; } std::string_view main_value{}; error = obj["main"].get_string().get(main_value); ASSERT_ERROR(error, simdjson::SUCCESS); std::string_view name_value{}; error = obj["name"].get_string().get(name_value); ASSERT_ERROR(error,TAPE_ERROR); TEST_SUCCEED(); } bool issue1834() { TEST_START(); ondemand::parser parser; auto json = "[[]"_padded; json.data()[json.size()] = ']'; auto doc = parser.iterate(json); size_t cnt{}; auto error = doc.count_elements().get(cnt); return error != simdjson::SUCCESS; } bool issue1834_2() { TEST_START(); ondemand::parser parser; auto json = "{\"a\":{}"_padded; json.data()[json.size()] = '}'; auto doc = parser.iterate(json); size_t cnt{}; auto error = doc.count_fields().get(cnt); return error != simdjson::SUCCESS; } bool empty_document_error() { TEST_START(); ondemand::parser parser; auto json = ""_padded; ASSERT_ERROR( parser.iterate(json), EMPTY ); TEST_SUCCEED(); } bool raw_json_string_error() { TEST_START(); ondemand::parser parser; auto json = "{\"haha\":{\"df2\":3.5, \"df3\": \"fd\"}}"_padded; ondemand::document doc; ASSERT_SUCCESS( parser.iterate(json).get(doc) ); ondemand::raw_json_string rawjson; ASSERT_ERROR( doc.get_raw_json_string().get(rawjson), INCORRECT_TYPE ); TEST_SUCCEED(); } #if SIMDJSON_EXCEPTIONS // This is a compile-only test struct Class { Class(std::string text) : parser() , doc(parser.iterate(text)) { } simdjson::ondemand::parser parser; simdjson::ondemand::document doc; }; bool document_in_class() { TEST_START(); std::string text = "{}"; Class c(text); TEST_SUCCEED(); } bool direct_document() { TEST_START(); std::string text = "{}"; simdjson::ondemand::parser parser; simdjson::ondemand::document doc(parser.iterate(text)); TEST_SUCCEED(); } bool raw_json_string_except() { TEST_START(); ondemand::parser parser; auto json = "{\"haha\":{\"df2\":3.5, \"df3\": \"fd\"}}"_padded; ondemand::document doc; ASSERT_SUCCESS( parser.iterate(json).get(doc) ); try { ondemand::raw_json_string rawjson = doc.get_raw_json_string(); (void)rawjson; TEST_FAIL("Should have thrown an exception!") } catch(simdjson_error& e) { ASSERT_ERROR(e.error(), INCORRECT_TYPE); TEST_SUCCEED(); } } bool raw_json_string_except_with_io() { TEST_START(); ondemand::parser parser; auto json = "{\"haha\":{\"df2\":3.5, \"df3\": \"fd\"}}"_padded; ondemand::document doc; ASSERT_SUCCESS( parser.iterate(json).get(doc) ); try { auto rawjson = doc.get_raw_json_string(); std::cout << rawjson; TEST_FAIL("Should have thrown an exception!") } catch(simdjson_error& e) { ASSERT_ERROR(e.error(), INCORRECT_TYPE); TEST_SUCCEED(); } } #endif bool parser_max_capacity() { TEST_START(); ondemand::parser parser(1); // max_capacity set to 1 byte padded_string json; ASSERT_SUCCESS( padded_string::load(TWITTER_JSON).get(json) ); auto error = parser.iterate(json); ASSERT_ERROR(error,CAPACITY); TEST_SUCCEED(); } bool parser_set_max_capacity() { TEST_START(); ondemand::parser parser; parser.set_max_capacity(1024 * 1024); ASSERT_EQUAL(parser.max_capacity(), size_t(1024 * 1024)); auto json = R"({"k":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"})"_padded; ondemand::document doc; ASSERT_SUCCESS(parser.iterate(json).get(doc)); TEST_SUCCEED(); } bool simple_error_example() { TEST_START(); ondemand::parser parser; auto json = R"({"bad number":3.14.1 })"_padded; ondemand::document doc; ASSERT_SUCCESS( parser.iterate(json).get(doc) ); double x; ASSERT_ERROR( doc["bad number"].get_double().get(x), NUMBER_ERROR ); TEST_SUCCEED(); } #if SIMDJSON_EXCEPTIONS bool simple_error_example_except() { TEST_START(); ondemand::parser parser; auto json = R"({"bad number":3.14.1 })"_padded; try { ondemand::document doc = parser.iterate(json); double x = doc["bad number"].get_double(); TEST_FAIL("should throw got: "+std::to_string(x)) } catch(simdjson_error& e) { ASSERT_ERROR(e.error(), NUMBER_ERROR); } TEST_SUCCEED(); } #endif bool get_fail_then_succeed_bool() { TEST_START(); auto json = R"({ "val" : true })"_padded; SUBTEST("simdjson_result", test_ondemand_doc(json, [&](auto doc) { simdjson_result val = doc["val"]; // Get everything that can fail in both forward and backwards order bool is_null_value; ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, false ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_object(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, false ); TEST_SUCCEED(); })); SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) { ondemand::value val; ASSERT_SUCCESS( doc["val"].get(val) ); // Get everything that can fail in both forward and backwards order bool is_null_value; ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, false ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_object(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, false ); TEST_SUCCEED(); })); json = R"(true)"_padded; SUBTEST("simdjson_result", test_ondemand_doc(json, [&](simdjson_result val) { // Get everything that can fail in both forward and backwards order bool is_null_value; ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, false ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_object(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_SUCCESS( val.get_bool()); ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, false ); TEST_SUCCEED(); })); SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) { ondemand::document val; ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order bool is_null_value; ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, false ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_object(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, false ); TEST_SUCCEED(); })); TEST_SUCCEED(); } bool get_fail_then_succeed_null() { TEST_START(); auto json = R"({ "val" : null })"_padded; SUBTEST("simdjson_result", test_ondemand_doc(json, [&](auto doc) { simdjson_result val = doc["val"]; // Get everything that can fail in both forward and backwards order ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_object(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); bool is_null_value; ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, true ); TEST_SUCCEED(); })); SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) { ondemand::value val; ASSERT_SUCCESS( doc["val"].get(val) ); // Get everything that can fail in both forward and backwards order ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_object(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); bool is_null_value; ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, true ); TEST_SUCCEED(); })); json = R"(null)"_padded; SUBTEST("simdjson_result", test_ondemand_doc(json, [&](simdjson_result val) { // Get everything that can fail in both forward and backwards order ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_object(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); bool is_null_value; ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, true ); TEST_SUCCEED(); })); SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) { ondemand::document val; ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_object(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); bool is_null_value; ASSERT_SUCCESS( val.is_null().get(is_null_value) ); ASSERT_EQUAL( is_null_value, true ); TEST_SUCCEED(); })); TEST_SUCCEED(); } #if SIMDJSON_EXCEPTIONS bool invalid_type() { TEST_START(); ONDEMAND_SUBTEST("]", "]", doc.type() == ondemand::json_type::unknown); ONDEMAND_SUBTEST("}", "}", doc.type() == ondemand::json_type::unknown); ONDEMAND_SUBTEST(":", ":", doc.type() == ondemand::json_type::unknown); ONDEMAND_SUBTEST(",", ",", doc.type() == ondemand::json_type::unknown); ONDEMAND_SUBTEST("+", "+", doc.type() == ondemand::json_type::unknown); TEST_SUCCEED(); } #endif // SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS bool operator_tests() { TEST_START(); ondemand::parser parser; // Test successful case auto json = R"({ "key": "value", "number": 42 })"_padded; parser.iterate(json).value(); // Test operator* *parser.iterate(json); // Test operator* auto doc_result = parser.iterate(json); ASSERT_SUCCESS(doc_result.error()); ASSERT_TRUE(doc_result.has_value()); double x = doc_result->find_field("number").get(); ASSERT_EQUAL(x, 42.0); TEST_SUCCEED(); } #endif // SIMDJSON_EXCEPTIONS bool run() { return issue2120() && badbadjson() && badbadjson2() && issue1834() && issue1834_2() && #if SIMDJSON_EXCEPTIONS document_in_class() && direct_document() && raw_json_string_except() && raw_json_string_except_with_io() && #endif raw_json_string_error() && empty_document_error() && parser_max_capacity() && parser_set_max_capacity() && get_fail_then_succeed_bool() && get_fail_then_succeed_null() && simple_error_example() && #if SIMDJSON_EXCEPTIONS invalid_type() && simple_error_example_except() && operator_tests() && #endif true; } } int main(int argc, char *argv[]) { return test_main(argc, argv, error_tests::run); }