mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
348 lines
12 KiB
C++
348 lines
12 KiB
C++
#include "simdjson.h"
|
|
#include "test_ondemand.h"
|
|
|
|
using namespace simdjson;
|
|
|
|
namespace object_tests {
|
|
using namespace std;
|
|
using simdjson::ondemand::json_type;
|
|
|
|
bool iterate_object() {
|
|
TEST_START();
|
|
auto json = R"({ "a": 1, "b": 2, "c": 3 })"_padded;
|
|
const char* expected_key[] = { "a", "b", "c" };
|
|
const uint64_t expected_value[] = { 1, 2, 3 };
|
|
SUBTEST("ondemand::object", test_ondemand_doc(json, [&](auto doc_result) {
|
|
ondemand::object object;
|
|
ASSERT_RESULT( doc_result.type(), json_type::object );
|
|
ASSERT_SUCCESS( doc_result.get(object) );
|
|
size_t i = 0;
|
|
for (auto [ field, error ] : object) {
|
|
ASSERT_SUCCESS(error);
|
|
ASSERT_EQUAL( field.key(), expected_key[i]);
|
|
ASSERT_EQUAL( field.value().get_uint64().value_unsafe(), expected_value[i] );
|
|
i++;
|
|
}
|
|
ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) );
|
|
return true;
|
|
}));
|
|
SUBTEST("simdjson_result<ondemand::object>", test_ondemand_doc(json, [&](auto doc_result) {
|
|
simdjson_result<ondemand::object> object_result = doc_result.get_object();
|
|
size_t i = 0;
|
|
for (auto [ field, error ] : object_result) {
|
|
ASSERT_SUCCESS(error);
|
|
ASSERT_EQUAL( field.key(), expected_key[i] );
|
|
ASSERT_EQUAL( field.value().get_uint64().value_unsafe(), expected_value[i] );
|
|
i++;
|
|
}
|
|
ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) );
|
|
return true;
|
|
}));
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool iterate_object_partial_children() {
|
|
TEST_START();
|
|
auto json = R"(
|
|
{
|
|
"scalar_ignore": 0,
|
|
"empty_array_ignore": [],
|
|
"empty_object_ignore": {},
|
|
"object_break": { "x": 3, "y": 33 },
|
|
"object_break_unused": { "x": 4, "y": 44 },
|
|
"object_index": { "x": 5, "y": 55 },
|
|
"object_index_unused": { "x": 6, "y": 66 },
|
|
"array_break": [ 7, 77, 777 ],
|
|
"array_break_unused": [ 8, 88, 888 ],
|
|
"quadruple_nested_break": { "a": [ { "b": [ 9, 99 ], "c": 999 }, 9999 ], "d": 99999 },
|
|
"actual_value": 10
|
|
}
|
|
)"_padded;
|
|
SUBTEST("ondemand::object", test_ondemand_doc(json, [&](auto doc_result) {
|
|
ondemand::object object;
|
|
ASSERT_SUCCESS( doc_result.get(object) );
|
|
size_t i = 0;
|
|
for (auto field : object) {
|
|
ondemand::raw_json_string key;
|
|
ASSERT_SUCCESS( field.key().get(key) );
|
|
|
|
switch (i) {
|
|
case 0: {
|
|
ASSERT_EQUAL(key, "scalar_ignore");
|
|
std::cout << " - After ignoring empty scalar ..." << std::endl;
|
|
break;
|
|
}
|
|
case 1: {
|
|
ASSERT_EQUAL(key, "empty_array_ignore");
|
|
std::cout << " - After ignoring empty array ..." << std::endl;
|
|
break;
|
|
}
|
|
case 2: {
|
|
ASSERT_EQUAL(key, "empty_object_ignore");
|
|
std::cout << " - After ignoring empty object ..." << std::endl;
|
|
break;
|
|
}
|
|
// Break after using first value in child object
|
|
case 3: {
|
|
ASSERT_EQUAL(key, "object_break");
|
|
|
|
for (auto [ child_field, error ] : field.value().get_object()) {
|
|
ASSERT_SUCCESS(error);
|
|
ASSERT_EQUAL(child_field.key(), "x");
|
|
uint64_t x;
|
|
ASSERT_SUCCESS( child_field.value().get(x) );
|
|
ASSERT_EQUAL(x, 3);
|
|
break; // Break after the first value
|
|
}
|
|
std::cout << " - After using first value in child object ..." << std::endl;
|
|
break;
|
|
}
|
|
|
|
// Break without using first value in child object
|
|
case 4: {
|
|
ASSERT_EQUAL(key, "object_break_unused");
|
|
|
|
for (auto [ child_field, error ] : field.value().get_object()) {
|
|
ASSERT_SUCCESS(error);
|
|
ASSERT_EQUAL(child_field.key(), "x");
|
|
break;
|
|
}
|
|
std::cout << " - After reaching (but not using) first value in child object ..." << std::endl;
|
|
break;
|
|
}
|
|
|
|
// Only look up one field in child object
|
|
case 5: {
|
|
ASSERT_EQUAL(key, "object_index");
|
|
|
|
uint64_t x;
|
|
ASSERT_SUCCESS( field.value()["x"].get(x) );
|
|
ASSERT_EQUAL( x, 5 );
|
|
std::cout << " - After looking up one field in child object ..." << std::endl;
|
|
break;
|
|
}
|
|
|
|
// Only look up one field in child object, but don't use it
|
|
case 6: {
|
|
ASSERT_EQUAL(key, "object_index_unused");
|
|
|
|
ASSERT_SUCCESS( field.value()["x"] );
|
|
std::cout << " - After looking up (but not using) one field in child object ..." << std::endl;
|
|
break;
|
|
}
|
|
|
|
// Break after first value in child array
|
|
case 7: {
|
|
ASSERT_EQUAL(key, "array_break");
|
|
for (auto child_value : field.value()) {
|
|
uint64_t x;
|
|
ASSERT_SUCCESS( child_value.get(x) );
|
|
ASSERT_EQUAL( x, 7 );
|
|
break;
|
|
}
|
|
std::cout << " - After using first value in child array ..." << std::endl;
|
|
break;
|
|
}
|
|
|
|
// Break without using first value in child array
|
|
case 8: {
|
|
ASSERT_EQUAL(key, "array_break_unused");
|
|
for (auto child_value : field.value()) {
|
|
ASSERT_SUCCESS(child_value);
|
|
break;
|
|
}
|
|
std::cout << " - After reaching (but not using) first value in child array ..." << std::endl;
|
|
break;
|
|
}
|
|
|
|
// Break out of multiple child loops
|
|
case 9: {
|
|
ASSERT_EQUAL(key, "quadruple_nested_break");
|
|
for (auto child1 : field.value().get_object()) {
|
|
for (auto child2 : child1.value().get_array()) {
|
|
for (auto child3 : child2.get_object()) {
|
|
for (auto child4 : child3.value().get_array()) {
|
|
uint64_t x;
|
|
ASSERT_SUCCESS( child4.get(x) );
|
|
ASSERT_EQUAL( x, 9 );
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
std::cout << " - After breaking out of quadruply-nested arrays and objects ..." << std::endl;
|
|
break;
|
|
}
|
|
|
|
// Test the actual value
|
|
case 10: {
|
|
ASSERT_EQUAL(key, "actual_value");
|
|
uint64_t actual_value;
|
|
ASSERT_SUCCESS( field.value().get(actual_value) );
|
|
ASSERT_EQUAL( actual_value, 10 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
ASSERT_EQUAL( i, 11 ); // Make sure we found all the keys we expected
|
|
return true;
|
|
}));
|
|
return true;
|
|
}
|
|
|
|
bool iterate_empty_object() {
|
|
TEST_START();
|
|
auto json = R"({})"_padded;
|
|
|
|
SUBTEST("ondemand::object", test_ondemand_doc(json, [&](auto doc_result) {
|
|
ondemand::object object;
|
|
ASSERT_SUCCESS( doc_result.get(object) );
|
|
for (simdjson_unused auto field : object) {
|
|
TEST_FAIL("Unexpected field");
|
|
}
|
|
return true;
|
|
}));
|
|
SUBTEST("simdjson_result<ondemand::object>", test_ondemand_doc(json, [&](auto doc_result) {
|
|
simdjson_result<ondemand::object> object_result = doc_result.get_object();
|
|
for (simdjson_unused auto field : object_result) {
|
|
TEST_FAIL("Unexpected field");
|
|
}
|
|
return true;
|
|
}));
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool issue_1480() {
|
|
TEST_START();
|
|
auto json = R"({ "name" : "something", "version": "0.13.2", "version_major": 0})"_padded;
|
|
|
|
SUBTEST("ondemand::issue_1480::object", test_ondemand_doc(json, [&](auto doc_result) {
|
|
ondemand::object object;
|
|
ASSERT_SUCCESS( doc_result.get(object) );
|
|
ASSERT_EQUAL( object.find_field_unordered("version_major").get_uint64().value_unsafe(), 0 );
|
|
ASSERT_EQUAL( object.find_field_unordered("version").get_string().value_unsafe(), "0.13.2");
|
|
return true;
|
|
}));
|
|
SUBTEST("ondemand::issue_1480::big-key", test_ondemand_doc(json, [&](auto doc_result) {
|
|
ondemand::object object;
|
|
ASSERT_SUCCESS( doc_result.get(object) );
|
|
std::vector<char> large_buf(512,' ');
|
|
std::string_view lb{large_buf.data(), large_buf.size()};
|
|
ASSERT_ERROR( object.find_field(lb), NO_SUCH_FIELD );
|
|
return true;
|
|
}));
|
|
|
|
#if SIMDJSON_EXCEPTIONS
|
|
SUBTEST("ondemand::issue_1480::object-iteration", test_ondemand_doc(json, [&](auto doc_result) {
|
|
ondemand::object object;
|
|
ASSERT_SUCCESS( doc_result.get(object) );
|
|
size_t counter_version{0};
|
|
size_t counter_version_major{0};
|
|
for(auto field : object) {
|
|
std::string_view keyv = field.unescaped_key();
|
|
if(keyv == "version") { counter_version++; }
|
|
if(keyv == "version_major") { counter_version_major++; }
|
|
}
|
|
ASSERT_EQUAL( counter_version, 1 );
|
|
ASSERT_EQUAL( counter_version_major, 1 );
|
|
return true;
|
|
}));
|
|
SUBTEST("ondemand::issue_1480::object-iteration-string-view", test_ondemand_doc(json, [&](auto doc_result) {
|
|
ondemand::object object;
|
|
ASSERT_SUCCESS( doc_result.get(object) );
|
|
size_t counter_version{0};
|
|
size_t counter_version_major{0};
|
|
const char * bufv = "version";
|
|
const char * bufvm = "version_major";
|
|
|
|
std::string_view v{bufv};
|
|
std::string_view vm{bufvm};
|
|
|
|
for(auto field : object) {
|
|
std::string_view keyv = field.unescaped_key();
|
|
if(keyv == v) { counter_version++; }
|
|
if(keyv == vm) { counter_version_major++; }
|
|
}
|
|
ASSERT_EQUAL( counter_version, 1 );
|
|
ASSERT_EQUAL( counter_version_major, 1 );
|
|
return true;
|
|
}));
|
|
SUBTEST("ondemand::issue_1480::original", test_ondemand_doc(json, [&](auto doc_result) {
|
|
size_t counter{0};
|
|
for (auto field : doc_result.get_object()) {
|
|
auto key = field.key().value();
|
|
if (key == "version") { counter++; }
|
|
}
|
|
ASSERT_EQUAL( counter, 1 );
|
|
return true;
|
|
}));
|
|
SUBTEST("ondemand::issue_1480::object-operator", test_ondemand_doc(json, [&](auto doc_result) {
|
|
ondemand::object object;
|
|
ASSERT_SUCCESS( doc_result.get(object) );
|
|
ASSERT_EQUAL( std::string_view(object["version"]), "0.13.2" );
|
|
ASSERT_EQUAL( uint64_t(object["version_major"]), 0 );
|
|
return true;
|
|
}));
|
|
#endif
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
#if SIMDJSON_EXCEPTIONS
|
|
|
|
bool iterate_object_exception() {
|
|
TEST_START();
|
|
auto json = R"({ "a": 1, "b": 2, "c": 3 })"_padded;
|
|
const char* expected_key[] = { "a", "b", "c" };
|
|
const uint64_t expected_value[] = { 1, 2, 3 };
|
|
ASSERT_TRUE(test_ondemand_doc(json, [&](auto doc_result) {
|
|
size_t i = 0;
|
|
for (ondemand::field field : doc_result.get_object()) {
|
|
ASSERT_EQUAL( field.key(), expected_key[i] );
|
|
ASSERT_EQUAL( uint64_t(field.value()), expected_value[i] );
|
|
i++;
|
|
}
|
|
ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) );
|
|
return true;
|
|
}));
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool iterate_empty_object_exception() {
|
|
TEST_START();
|
|
auto json = R"({})"_padded;
|
|
|
|
ASSERT_TRUE(test_ondemand_doc(json, [&](auto doc_result) {
|
|
for (simdjson_unused ondemand::field field : doc_result.get_object()) {
|
|
TEST_FAIL("Unexpected field");
|
|
}
|
|
return true;
|
|
}));
|
|
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
#endif // SIMDJSON_EXCEPTIONS
|
|
|
|
bool run() {
|
|
return
|
|
iterate_object() &&
|
|
iterate_empty_object() &&
|
|
iterate_object_partial_children() &&
|
|
issue_1480() &&
|
|
#if SIMDJSON_EXCEPTIONS
|
|
iterate_object_exception() &&
|
|
#endif // SIMDJSON_EXCEPTIONS
|
|
true;
|
|
}
|
|
|
|
} // namespace object_tests
|
|
|
|
int main(int argc, char *argv[]) {
|
|
return test_main(argc, argv, object_tests::run);
|
|
}
|