Support JSON pointer in DOM navigation model

This commit is contained in:
John Keiser
2020-03-23 14:49:10 -07:00
parent 3e39a998ce
commit 0bcda5e384
6 changed files with 700 additions and 132 deletions
+67 -33
View File
@@ -6,43 +6,77 @@
#ifndef ASSERT
#define ASSERT(x) \
{ if (!(x)) { \
char buf[4096]; \
snprintf (buf, 4096, "Failure in \"%s\", line %d\n", \
__FILE__, __LINE__); \
abort (); \
std::cerr << "Failed assertion " << #x << std::endl; \
return false; \
} \
}
#endif
int main() {
// {"/~01abc": [0, {"\\\" 0": ["value0", "value1"]}]}"
std::string json =
"{\"/~01abc\": [0, {\"\\\\\\\" 0\": [\"value0\", \"value1\"]}]}";
simdjson::ParsedJson pj;
simdjson::json_parse(json.c_str(), json.length(), pj);
ASSERT(pj.is_valid());
simdjson::ParsedJson::Iterator it(pj.doc);
using namespace simdjson;
// valid JSON String Representation pointer
std::string pointer1("/~1~001abc/1/\\\\\\\" 0/0");
ASSERT(it.move_to(pointer1.c_str(), pointer1.length()));
ASSERT(it.is_string());
ASSERT(it.get_string() == std::string("value0"));
const padded_string TEST_JSON = R"(
{
"/~01abc": [
0,
{
"\\\" 0": [
"value0",
"value1"
]
}
],
"0": "0 ok",
"01": "01 ok",
"": "empty ok",
"arr": []
}
)"_padded;
// valid URI Fragment Identifier Representation pointer
std::string pointer2("#/~1~001abc/1/%x5C%x22%x200/1");
ASSERT(it.move_to(pointer2.c_str(), pointer2.length()));
ASSERT(it.is_string());
ASSERT(it.get_string() == std::string("value1"));
// invalid pointer with leading 0 in index
std::string pointer3("#/~1~001abc/01");
ASSERT(!it.move_to(pointer3.c_str(), pointer3.length())); // failed
ASSERT(it.is_string()); // has probably not moved
ASSERT(it.get_string() == std::string("value1")); // has not move
// "the (nonexistent) member after the last array element"
std::string pointer4("/~1~001abc/-");
ASSERT(it.move_to(pointer4.c_str(), pointer4.length()));
ASSERT(it.get_type() == ']');
bool json_pointer_success_test(const char *json_pointer, std::string_view expected_value) {
std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl;
auto doc = document::parse(TEST_JSON);
auto [value, error] = doc[json_pointer].as_string();
if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; }
ASSERT(value == expected_value);
return true;
}
bool json_pointer_success_test(const char *json_pointer) {
std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl;
auto doc = document::parse(TEST_JSON);
auto [value, error] = doc[json_pointer];
if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; }
return true;
}
bool json_pointer_failure_test(const char *json_pointer, error_code expected_failure_test) {
std::cout << "Running invalid JSON pointer test '" << json_pointer << "' ..." << std::endl;
auto doc = document::parse(TEST_JSON);
auto [value, error] = doc[json_pointer];
ASSERT(error == expected_failure_test);
return true;
}
int main() {
if (
json_pointer_success_test(R"(/~1~001abc/1/\\\" 0/0)", "value0") &&
json_pointer_success_test(R"(/~1~001abc/1/\\\" 0/1)", "value1") &&
json_pointer_failure_test(R"(/~1~001abc/1/\\\" 0/2)", INDEX_OUT_OF_BOUNDS) && // index actually out of bounds
json_pointer_success_test("/arr") && // get array
json_pointer_failure_test("/arr/0", INDEX_OUT_OF_BOUNDS) && // array index 0 out of bounds on empty array
json_pointer_success_test("/~1~001abc") && // get object
json_pointer_success_test("/0", "0 ok") && // object index with integer-ish key
json_pointer_success_test("/01", "01 ok") && // object index with key that would be an invalid integer
json_pointer_success_test("/", "empty ok") && // object index with empty key
json_pointer_failure_test("/~01abc", NO_SUCH_FIELD) && // Test that we don't try to compare the literal key
json_pointer_failure_test("/~1~001abc/01", INVALID_JSON_POINTER) && // Leading 0 in integer index
json_pointer_failure_test("/~1~001abc/", INVALID_JSON_POINTER) && // Empty index to array
json_pointer_failure_test("/~1~001abc/-", INDEX_OUT_OF_BOUNDS) && // End index is always out of bounds
true
) {
std::cout << "Success!" << std::endl;
} else {
std::cerr << "Failed!" << std::endl;
}
}