simdjson/tests/ondemand/ondemand_tostring_tests.cpp

444 lines
14 KiB
C++

#include <cinttypes>
#include <ciso646>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include <unistd.h>
#include <utility>
#include <vector>
#include "simdjson.h"
using namespace simdjson;
#include "test_ondemand.h"
namespace tostring_tests {
const char *test_files[] = {
TWITTER_JSON, TWITTER_TIMELINE_JSON, REPEAT_JSON, CANADA_JSON,
MESH_JSON, APACHE_JSON, GSOC_JSON};
#if SIMDJSON_EXCEPTIONS
bool issue1607() {
TEST_START();
auto silly_json = R"( { "test": "result" } )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(silly_json);
std::string_view expected = R"("result")";
std::string_view result = simdjson::to_json_string(doc["test"]);
std::cout << "'"<< result << "'" << std::endl;
ASSERT_EQUAL(result, expected);
TEST_SUCCEED();
}
bool minify_demo() {
TEST_START();
ondemand::parser parser;
auto silly_json = R"( { "test": "result" } )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(silly_json).get(doc) );
std::cout << simdjson::to_json_string(doc["test"]) << std::endl;
TEST_SUCCEED();
}
bool minify_demo2() {
TEST_START();
ondemand::parser parser;
auto silly_json = R"( { "test": "result" } )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(silly_json).get(doc) );
std::cout << std::string_view(doc["test"]) << std::endl;
TEST_SUCCEED();
}
bool car_example() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
std::vector<std::string_view> arrays;
// We are going to collect string_view instances which point inside the `cars_json` string
// and are therefore valid as long as `cars_json` remains in scope.
{
ondemand::parser parser;
for (ondemand::object car : parser.iterate(cars_json)) {
if(uint64_t(car["year"]) > 2000) { // Pick the recent cars only!
arrays.push_back(simdjson::to_json_string(car["tire_pressure"]));
}
}
}
// We can now convert to a JSON string:
std::ostringstream oss;
oss << "[";
for(size_t i = 0; i < arrays.size(); i++) {
if(i>0) { oss << ","; }
oss << arrays[i];
}
oss << "]";
auto json_string = oss.str();
ASSERT_EQUAL(json_string, "[[ 40.1, 39.9, 37.7, 40.4 ],[ 30.1, 31.0, 28.6, 28.7 ]]");
TEST_SUCCEED();
}
/**
* The general idea of these tests if that if you take a JSON file,
* load it, then convert it into a string, then parse that, and
* convert it again into a second string, then the two strings should
* be identifical. If not, then something was lost or added in the
* process.
*/
bool load_to_string(const char *filename) {
simdjson::ondemand::parser parser;
std::cout << "Loading " << filename << std::endl;
simdjson::padded_string docdata;
auto error = simdjson::padded_string::load(filename).get(docdata);
if (error) {
std::cerr << "could not load " << filename << " got " << error << std::endl;
return false;
}
std::cout << "file loaded: " << docdata.size() << " bytes." << std::endl;
simdjson::ondemand::document doc;
auto silly_json = R"( { "test": "result" } )"_padded;
error = parser.iterate(silly_json).get(doc);
if (error) {
std::cerr << error << std::endl;
return false;
}
std::cout << "serializing once." << std::endl;
std::string_view serial1 = simdjson::to_json_string(doc);
error = parser.iterate(serial1, serial1.size() + simdjson::SIMDJSON_PADDING).get(doc);
if (error) {
std::cerr << error << std::endl;
return false;
}
std::cout << "serializing twice." << std::endl;
std::string_view serial2 = simdjson::to_json_string(doc);
bool match = (serial1 == serial2);
if (match) {
std::cout << "Parsing to_string and calling to_string again results in the "
"same content. "
<< "Got " << serial1.size() << " bytes." << std::endl;
}
return match;
}
bool minify_test() {
TEST_START();
for (size_t i = 0; i < sizeof(test_files) / sizeof(test_files[0]); i++) {
bool ok = load_to_string(test_files[i]);
if (!ok) {
return false;
}
}
TEST_SUCCEED();
}
#endif // SIMDJSON_EXCEPTIONS
bool load_to_string_exceptionless(const char *filename) {
simdjson::ondemand::parser parser;
std::cout << "Loading " << filename << std::endl;
simdjson::padded_string docdata;
auto error = simdjson::padded_string::load(filename).get(docdata);
if (error) {
std::cerr << "could not load " << filename << " got " << error << std::endl;
return false;
}
std::cout << "file loaded: " << docdata.size() << " bytes." << std::endl;
simdjson::ondemand::document doc;
error = parser.iterate(docdata).get(doc);
if (error) {
std::cerr << error << std::endl;
return false;
}
std::cout << "serializing once." << std::endl;
std::string_view serial1;
error = simdjson::to_json_string(doc).get(serial1);
if (error) {
std::cerr << error << std::endl;
return false;
}
error = parser.iterate(serial1, serial1.size() + simdjson::SIMDJSON_PADDING).get(doc);
if (error) {
std::cerr << error << std::endl;
return false;
}
std::cout << "serializing twice." << std::endl;
std::string_view serial2;
error = simdjson::to_json_string(doc).get(serial2);
if (error) {
std::cerr << error << std::endl;
return false;
}
bool match = (serial1 == serial2);
if (match) {
std::cout << "Parsing to_string and calling to_string again results in the "
"same content. "
<< "Got " << serial1.size() << " bytes." << std::endl;
}
return match;
}
bool minify_exceptionless_test() {
TEST_START();
for (size_t i = 0; i < sizeof(test_files) / sizeof(test_files[0]); i++) {
bool ok = load_to_string_exceptionless(test_files[i]);
if (!ok) {
return false;
}
}
return true;
}
bool empty_object() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"({})"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc));
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, R"({})");
TEST_SUCCEED();
}
bool empty_array() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"([])"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc));
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, R"([])");
TEST_SUCCEED();
}
bool single_digit_document() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"(9)"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, R"(9)");
TEST_SUCCEED();
}
bool single_string_document() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"("")"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, R"("")");
TEST_SUCCEED();
}
bool at_start_array() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"( [111,2,3,5] )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
ondemand::array array;
ASSERT_SUCCESS( doc.get_array().get(array) );
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(array).get(serial));
ASSERT_EQUAL(serial, "[111,2,3,5]");
TEST_SUCCEED();
}
bool at_start_object() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"( {"a":1, "b":2, "c": 3 } )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
ondemand::object object;
ASSERT_SUCCESS( doc.get_object().get(object) );
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
TEST_SUCCEED();
}
bool in_middle_array() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"( [111,{"a":1},3,5] )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
ondemand::array array;
ASSERT_SUCCESS( doc.get_array().get(array) );
auto i = array.begin();
int64_t x;
ASSERT_SUCCESS( (*i).get_int64().get(x) );
ASSERT_EQUAL(x, 111);
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(array).get(serial));
ASSERT_EQUAL(serial, "[111,{\"a\":1},3,5]");
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, "[111,{\"a\":1},3,5]");
TEST_SUCCEED();
}
bool at_middle_object() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"( {"a":1, "b":2, "c": 3 } )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
ondemand::object object;
ASSERT_SUCCESS( doc.get_object().get(object) );
int64_t x;
ASSERT_SUCCESS(object["b"].get_int64().get(x));
ASSERT_EQUAL(x,2);
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
TEST_SUCCEED();
}
bool at_middle_object_just_key() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"( {"a":1, "b":2, "c": 3 } )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
ondemand::object object;
ASSERT_SUCCESS( doc.get_object().get(object) );
ondemand::value x;
ASSERT_SUCCESS(object["b"].get(x));
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
TEST_SUCCEED();
}
bool at_end_object() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"( {"a":1, "b":2, "c": 3 } )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
ondemand::object object;
ASSERT_SUCCESS( doc.get_object().get(object) );
int64_t x;
ASSERT_ERROR(object["bcc"].get_int64().get(x), NO_SUCH_FIELD);
std::string_view serial;
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
TEST_SUCCEED();
}
bool at_array_end() {
TEST_START();
ondemand::parser parser;
std::string_view serial;
auto arr_json = R"( [111,2,3,5] )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
ondemand::array array;
ASSERT_SUCCESS( doc.get_array().get(array) );
auto i = array.begin();
int64_t x;
ASSERT_SUCCESS( (*i).get_int64().get(x) );
ASSERT_EQUAL(x, 111);
++i;
ASSERT_SUCCESS( (*i).get_int64().get(x) );
ASSERT_EQUAL(x, 2);
++i;
ASSERT_SUCCESS( (*i).get_int64().get(x) );
ASSERT_EQUAL(x, 3);
++i;
ASSERT_SUCCESS( (*i).get_int64().get(x) );
ASSERT_EQUAL(x, 5);
ASSERT_SUCCESS( simdjson::to_json_string(array).get(serial));
ASSERT_EQUAL(serial, "[111,2,3,5]");
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, "[111,2,3,5]");
TEST_SUCCEED();
}
bool complex_case() {
TEST_START();
ondemand::parser parser;
auto arr_json = R"( {"array":[1,2,3], "objects":[{"id":1}, {"id":2}, {"id":3}]} )"_padded;
ondemand::document doc;
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
ondemand::object obj;
ASSERT_SUCCESS( doc.get_object().get(obj) );
ondemand::array array;
ASSERT_SUCCESS( obj["objects"].get_array().get(array) );
std::string_view serial;
for(auto v : array) {
ondemand::object object;
ASSERT_SUCCESS( v.get_object().get(object) );
int64_t x;
ASSERT_SUCCESS(object["id"].get_int64().get(x));
if(x / 2 * 2 != x) {
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
ASSERT_EQUAL(serial, "{\"id\":"+std::to_string(x)+"}");
}
}
ASSERT_SUCCESS( simdjson::to_json_string(array).get(serial));
ASSERT_EQUAL(serial, R"([{"id":1}, {"id":2}, {"id":3}])");
ASSERT_SUCCESS( simdjson::to_json_string(obj).get(serial));
ASSERT_EQUAL(serial, R"({"array":[1,2,3], "objects":[{"id":1}, {"id":2}, {"id":3}]})");
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
ASSERT_EQUAL(serial, R"({"array":[1,2,3], "objects":[{"id":1}, {"id":2}, {"id":3}]})");
TEST_SUCCEED();
}
bool run() {
return
empty_object() &&
empty_array() &&
single_digit_document() &&
single_string_document() &&
complex_case() &&
at_start_object() &&
at_middle_object() &&
at_middle_object_just_key() &&
at_end_object() &&
at_start_array() &&
in_middle_array() &&
at_array_end() &&
#if SIMDJSON_EXCEPTIONS
issue1607() &&
minify_demo() &&
minify_demo2() &&
minify_test() &&
car_example() &&
#endif // SIMDJSON_EXCEPTIONS
minify_exceptionless_test() &&
true;
}
} // namespace tostring_tests
int main(int argc, char *argv[]) {
return test_main(argc, argv, tostring_tests::run);
}