mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
e2ea5fb8de
improves slightly the documentation.
450 lines
16 KiB
C++
450 lines
16 KiB
C++
#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 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<ondemand::value>", test_ondemand_doc(json, [&](auto doc) {
|
|
simdjson_result<ondemand::value> 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_object(), 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_object(), 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<ondemand::document>", test_ondemand_doc(json, [&](simdjson_result<ondemand::document> 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_object(), 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_object(), 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<ondemand::value>", test_ondemand_doc(json, [&](auto doc) {
|
|
simdjson_result<ondemand::value> 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_object(), 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_object(), 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<ondemand::document>", test_ondemand_doc(json, [&](simdjson_result<ondemand::document> 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_object(), 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_object(), 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<double>();
|
|
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() &&
|
|
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);
|
|
}
|