mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
376ef7e8e9
* Add tests for dumping out NaN/Infinity to the json builder * If SIMDJSON_ENABLE_NAN_INF is set, write out NaN and Infinity * Add tests for dumping out NaN/Infinity when serializing DOM * If SIMDJSON_ENABLE_NAN_INF, use 'NaN' and 'Infinity' for nan/inf * Fix bug where 'Inf' as a root atom + spaces of padding parses incorrectly * Update FracturedJson printers so tables containing NaN/Infinity are aligned
816 lines
22 KiB
C++
816 lines
22 KiB
C++
#include "simdjson.h"
|
|
#include "test_builder.h"
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
#if SIMDJSON_SUPPORTS_RANGES
|
|
#include <ranges>
|
|
#endif
|
|
|
|
using namespace simdjson;
|
|
|
|
struct Car {
|
|
std::string make;
|
|
std::string model;
|
|
int64_t year;
|
|
std::vector<double> tire_pressure;
|
|
}; // Car
|
|
|
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
|
struct Car2549 {
|
|
std::string make;
|
|
std::string model;
|
|
int64_t year;
|
|
std::vector<float> tire_pressure;
|
|
};
|
|
namespace simdjson {
|
|
// we intentionally pass by non-const reference to car.
|
|
template <typename builder_type>
|
|
void tag_invoke(serialize_tag, builder_type &builder, Car2549 &car) {
|
|
builder.start_object();
|
|
builder.append_key_value("make", car.make);
|
|
builder.append_comma();
|
|
builder.append_key_value("model", car.model);
|
|
builder.append_comma();
|
|
builder.append_key_value("year", car.year);
|
|
builder.append_comma();
|
|
builder.append_key_value("tire_pressure", car.tire_pressure);
|
|
builder.end_object();
|
|
}
|
|
} // namespace simdjson
|
|
|
|
static_assert(simdjson::require_custom_serialization<Car2549>);
|
|
#endif
|
|
|
|
namespace builder_tests {
|
|
using namespace std;
|
|
|
|
bool allchar_test() {
|
|
TEST_START();
|
|
auto get_utf8_codepoints = []() -> std::string {
|
|
std::string result;
|
|
for (char32_t cp = 0; cp <= 0x10FFFF; ++cp) {
|
|
if ((cp >= 0xD800 && cp <= 0xDFFF) || cp > 0x10FFFF) {
|
|
continue; // Skip surrogate pairs and invalid codepoints
|
|
}
|
|
if (cp < 0x80) {
|
|
result += static_cast<char>(cp);
|
|
} else if (cp < 0x800) {
|
|
result += static_cast<char>(0xC0 | (cp >> 6));
|
|
result += static_cast<char>(0x80 | (cp & 0x3F));
|
|
} else if (cp < 0x10000) {
|
|
result += static_cast<char>(0xE0 | (cp >> 12));
|
|
result += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
|
result += static_cast<char>(0x80 | (cp & 0x3F));
|
|
} else {
|
|
result += static_cast<char>(0xF0 | (cp >> 18));
|
|
result += static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
|
|
result += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
|
result += static_cast<char>(0x80 | (cp & 0x3F));
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
auto allutf8 = get_utf8_codepoints();
|
|
simdjson::builder::string_builder sb;
|
|
sb.start_object();
|
|
sb.append_key_value("input", allutf8);
|
|
sb.end_object();
|
|
std::string_view p;
|
|
ASSERT_TRUE(sb.validate_unicode());
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
simdjson::padded_string output = p;
|
|
simdjson::ondemand::parser parser;
|
|
simdjson::ondemand::document doc;
|
|
ASSERT_SUCCESS(parser.iterate(output).get(doc));
|
|
std::string_view recovered;
|
|
ASSERT_SUCCESS(doc["input"].get(recovered));
|
|
ASSERT_EQUAL(recovered, allutf8);
|
|
simdjson::dom::parser domparser;
|
|
simdjson::dom::element elem;
|
|
ASSERT_SUCCESS(domparser.parse(output).get(elem));
|
|
ASSERT_SUCCESS(elem["input"].get(recovered));
|
|
ASSERT_EQUAL(recovered, allutf8);
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool bad_utf8_test() {
|
|
TEST_START();
|
|
std::string bad_utf8 = "\xFF";
|
|
simdjson::builder::string_builder sb;
|
|
sb.start_object();
|
|
sb.append_key_value("input", bad_utf8);
|
|
sb.end_object();
|
|
ASSERT_FALSE(sb.validate_unicode())
|
|
TEST_SUCCEED();
|
|
}
|
|
#if SIMDJSON_EXCEPTIONS
|
|
bool string_convertion_except() {
|
|
TEST_START();
|
|
simdjson::ondemand::parser p;
|
|
simdjson::builder::string_builder sb;
|
|
sb.append('a');
|
|
std::string r(sb);
|
|
ASSERT_EQUAL(r, "a");
|
|
|
|
// forcing call to `operator std::string()`
|
|
r = [](std::string x) { return x; }(sb);
|
|
ASSERT_EQUAL(r, "a");
|
|
|
|
TEST_SUCCEED();
|
|
}
|
|
#endif
|
|
|
|
bool append_char() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append('a');
|
|
ASSERT_EQUAL(sb.size(), 1);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "a");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool append_integer() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(42);
|
|
ASSERT_EQUAL(sb.size(), 2);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "42");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool append_float() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(1.1);
|
|
ASSERT_EQUAL(sb.size(), 3);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "1.1");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
#if SIMDJSON_ENABLE_NAN_INF
|
|
bool append_nan() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(std::numeric_limits<double>::quiet_NaN());
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
ASSERT_EQUAL(p, "NaN");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool append_positive_infinity() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(std::numeric_limits<double>::infinity());
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
ASSERT_EQUAL(p, "Infinity");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool append_negative_infinity() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(-std::numeric_limits<double>::infinity());
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
ASSERT_EQUAL(p, "-Infinity");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool append_float_nan_inf() {
|
|
TEST_START();
|
|
{
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(std::numeric_limits<float>::quiet_NaN());
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
ASSERT_EQUAL(p, "NaN");
|
|
}
|
|
{
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(std::numeric_limits<float>::infinity());
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
ASSERT_EQUAL(p, "Infinity");
|
|
}
|
|
{
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(-std::numeric_limits<float>::infinity());
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
ASSERT_EQUAL(p, "-Infinity");
|
|
}
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool nan_inf_in_array() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.start_array();
|
|
sb.append(1.5);
|
|
sb.append_comma();
|
|
sb.append(std::numeric_limits<double>::quiet_NaN());
|
|
sb.append_comma();
|
|
sb.append(std::numeric_limits<double>::infinity());
|
|
sb.append_comma();
|
|
sb.append(-std::numeric_limits<double>::infinity());
|
|
sb.append_comma();
|
|
sb.append(2.5);
|
|
sb.end_array();
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
ASSERT_EQUAL(p, "[1.5,NaN,Infinity,-Infinity,2.5]");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool nan_inf_in_object() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.start_object();
|
|
sb.append_key_value("a", std::numeric_limits<double>::quiet_NaN());
|
|
sb.append_comma();
|
|
sb.append_key_value("b", std::numeric_limits<double>::infinity());
|
|
sb.append_comma();
|
|
sb.append_key_value("c", -std::numeric_limits<double>::infinity());
|
|
sb.end_object();
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
ASSERT_EQUAL(p, "{\"a\":NaN,\"b\":Infinity,\"c\":-Infinity}");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool nan_inf_roundtrip() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.start_array();
|
|
sb.append(std::numeric_limits<double>::quiet_NaN());
|
|
sb.append_comma();
|
|
sb.append(std::numeric_limits<double>::infinity());
|
|
sb.append_comma();
|
|
sb.append(-std::numeric_limits<double>::infinity());
|
|
sb.end_array();
|
|
std::string_view p;
|
|
ASSERT_SUCCESS(sb.view().get(p));
|
|
|
|
simdjson::padded_string output{p};
|
|
simdjson::dom::parser parser;
|
|
simdjson::dom::element doc;
|
|
ASSERT_SUCCESS(parser.parse(output).get(doc));
|
|
simdjson::dom::array arr;
|
|
ASSERT_SUCCESS(doc.get_array().get(arr));
|
|
|
|
std::array<double, 3> expected{
|
|
std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::infinity(),
|
|
-std::numeric_limits<double>::infinity(),
|
|
};
|
|
size_t index = 0;
|
|
for (auto val : arr) {
|
|
double parsed;
|
|
ASSERT_SUCCESS(val.get_double().get(parsed));
|
|
if (std::isnan(expected[index])) {
|
|
ASSERT_TRUE(std::isnan(parsed));
|
|
} else {
|
|
ASSERT_EQUAL(parsed, expected[index]);
|
|
}
|
|
index++;
|
|
}
|
|
ASSERT_EQUAL(index, expected.size());
|
|
TEST_SUCCEED();
|
|
}
|
|
#endif // SIMDJSON_ENABLE_NAN_INF
|
|
|
|
bool append_null() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append_null();
|
|
ASSERT_EQUAL(sb.size(), 4);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "null");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool clear() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append('a');
|
|
sb.clear();
|
|
ASSERT_EQUAL(sb.size(), 0);
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool escape_and_append() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.escape_and_append("Hello, \"world\"!");
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "Hello, \\\"world\\\"!");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool escape_and_append_with_quotes() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.escape_and_append_with_quotes("Hello, \"world\"!");
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "\"Hello, \\\"world\\\"!\"");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool various_integers() {
|
|
TEST_START();
|
|
std::vector<std::pair<int64_t, std::string_view>> test_cases = {
|
|
{0, "0"},
|
|
{1, "1"},
|
|
{-1, "-1"},
|
|
{42, "42"},
|
|
{-42, "-42"},
|
|
{100, "100"},
|
|
{-100, "-100"},
|
|
{999, "999"},
|
|
{-999, "-999"},
|
|
{2147483647, "2147483647"}, // max 32-bit integer
|
|
{-2147483648, "-2147483648"}, // min 32-bit integer
|
|
{4294967296ULL, "4294967296"}, // 2^32
|
|
{-4294967296LL, "-4294967296"},
|
|
{10000000000LL, "10000000000"}, // 10 billion
|
|
{-10000000000LL, "-10000000000"},
|
|
{9223372036854775807LL, "9223372036854775807"}, // max 64-bit integer
|
|
{-9223372036854775807LL - 1,
|
|
"-9223372036854775808"}, // min 64-bit integer
|
|
{1234567890123LL, "1234567890123"},
|
|
{-1234567890123LL, "-1234567890123"},
|
|
};
|
|
for (const auto &[value, expected] : test_cases) {
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(value);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, expected);
|
|
}
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool various_unsigned_integers() {
|
|
TEST_START();
|
|
std::vector<std::pair<uint64_t, std::string_view>> test_cases = {
|
|
{0, "0"},
|
|
{1, "1"},
|
|
{42, "42"},
|
|
{100, "100"},
|
|
{999, "999"},
|
|
{2147483647, "2147483647"}, // max 32-bit integer
|
|
{4294967296ULL, "4294967296"}, // 2^32
|
|
{10000000000LL, "10000000000"}, // 10 billion
|
|
{9223372036854775807LL, "9223372036854775807"}, // max 64-bit integer
|
|
{1234567890123LL, "1234567890123"},
|
|
};
|
|
for (const auto &[value, expected] : test_cases) {
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(value);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, expected);
|
|
}
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool append_raw() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append_raw("Test");
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "Test");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool raw_with_length() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append_raw("Test String", 4);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "Test");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool string_convertion() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append('a');
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "a");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool unicode_validation() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
sb.append('a');
|
|
ASSERT_TRUE(sb.validate_unicode());
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool buffer_growth() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
for (int i = 0; i < 3; ++i) {
|
|
sb.append('a');
|
|
}
|
|
ASSERT_EQUAL(sb.size(), 3);
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
void serialize_car_long(const Car &car,
|
|
simdjson::builder::string_builder &builder) {
|
|
// start of JSON
|
|
builder.append_raw("{");
|
|
|
|
// "make"
|
|
builder.escape_and_append_with_quotes("make");
|
|
builder.append_raw(":");
|
|
builder.escape_and_append_with_quotes(car.make);
|
|
|
|
// "model"
|
|
builder.append_raw(",");
|
|
builder.escape_and_append_with_quotes("model");
|
|
builder.append_raw(":");
|
|
builder.escape_and_append_with_quotes(car.model);
|
|
|
|
// "year"
|
|
builder.append_raw(",");
|
|
builder.escape_and_append_with_quotes("year");
|
|
builder.append_raw(":");
|
|
builder.append(car.year);
|
|
|
|
// "tire_pressure"
|
|
builder.append_raw(",");
|
|
builder.escape_and_append_with_quotes("tire_pressure");
|
|
builder.append_raw(":[");
|
|
|
|
// vector tire_pressure
|
|
for (size_t i = 0; i < car.tire_pressure.size(); ++i) {
|
|
builder.append(car.tire_pressure[i]);
|
|
if (i < car.tire_pressure.size() - 1) {
|
|
builder.append_raw(",");
|
|
}
|
|
}
|
|
// end of array
|
|
builder.append_raw("]");
|
|
|
|
// end of object
|
|
builder.append_raw("}");
|
|
}
|
|
|
|
bool car_test_long() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
Car c = {"Toyota", "Corolla", 2017, {30.0, 30.2, 30.513, 30.79}};
|
|
serialize_car_long(c, sb);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,"
|
|
"\"tire_pressure\":[30.0,30.2,30.513,30.79]}");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
void serialize_car(const Car &car, simdjson::builder::string_builder &builder) {
|
|
// start of JSON
|
|
builder.start_object();
|
|
|
|
// "make"
|
|
builder.append_key_value("make", car.make);
|
|
builder.append_comma();
|
|
|
|
// "model"
|
|
builder.append_key_value("model", car.model);
|
|
|
|
builder.append_comma();
|
|
|
|
// "year"
|
|
builder.append_key_value("year", car.year);
|
|
|
|
builder.append_comma();
|
|
|
|
// "tire_pressure"
|
|
builder.escape_and_append_with_quotes("tire_pressure");
|
|
builder.append_colon();
|
|
builder.start_array();
|
|
// vector tire_pressure
|
|
for (size_t i = 0; i < car.tire_pressure.size(); ++i) {
|
|
builder.append(car.tire_pressure[i]);
|
|
if (i < car.tire_pressure.size() - 1) {
|
|
builder.append_comma();
|
|
}
|
|
}
|
|
// end of array
|
|
builder.end_array();
|
|
|
|
// end of object
|
|
builder.end_object();
|
|
}
|
|
|
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
|
void serialize_car_template(const Car &car,
|
|
simdjson::builder::string_builder &builder) {
|
|
// start of JSON
|
|
builder.start_object();
|
|
|
|
// "make"
|
|
builder.append_key_value<"make">(car.make);
|
|
builder.append_comma();
|
|
|
|
// "model"
|
|
builder.append_key_value<"model">(car.model);
|
|
|
|
builder.append_comma();
|
|
|
|
// "year"
|
|
builder.append_key_value<"year">(car.year);
|
|
|
|
builder.append_comma();
|
|
|
|
// "tire_pressure"
|
|
builder.escape_and_append_with_quotes<"tire_pressure">();
|
|
builder.append_colon();
|
|
builder.start_array();
|
|
// vector tire_pressure
|
|
for (size_t i = 0; i < car.tire_pressure.size(); ++i) {
|
|
builder.append(car.tire_pressure[i]);
|
|
if (i < car.tire_pressure.size() - 1) {
|
|
builder.append_comma();
|
|
}
|
|
}
|
|
// end of array
|
|
builder.end_array();
|
|
|
|
// end of object
|
|
builder.end_object();
|
|
}
|
|
#endif
|
|
bool car_test() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
Car c = {"Toyota", "Corolla", 2017, {30.0, 30.2, 30.513, 30.79}};
|
|
serialize_car(c, sb);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,"
|
|
"\"tire_pressure\":[30.0,30.2,30.513,30.79]}");
|
|
TEST_SUCCEED();
|
|
}
|
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
|
|
|
bool issue2549() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
Car2549 c = {"Toyota", "Corolla", 2017, {1.0f, 2.0f, 3.0f}};
|
|
sb.start_object();
|
|
sb.append_key_value("car", c);
|
|
sb.end_object();
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "{\"car\":{\"make\":\"Toyota\",\"model\":\"Corolla\","
|
|
"\"year\":2017,\"tire_pressure\":[1.0,2.0,3.0]}}");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool car_test_template() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
Car c = {"Toyota", "Corolla", 2017, {30.0, 30.2, 30.513, 30.79}};
|
|
serialize_car_template(c, sb);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,"
|
|
"\"tire_pressure\":[30.0,30.2,30.513,30.79]}");
|
|
TEST_SUCCEED();
|
|
}
|
|
bool serialize_optional() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
std::optional<std::string> optional_string = "Hello, World!";
|
|
sb.append(optional_string);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "\"Hello, World!\"");
|
|
sb.clear();
|
|
std::optional<std::string> optional_string_null = std::nullopt;
|
|
sb.append(optional_string_null);
|
|
result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "null");
|
|
TEST_SUCCEED();
|
|
}
|
|
#endif
|
|
|
|
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
|
void serialize_car_simple(const Car &car,
|
|
simdjson::builder::string_builder &builder) {
|
|
builder.start_object();
|
|
builder.append_key_value("make", car.make);
|
|
builder.append_comma();
|
|
builder.append_key_value("model", car.model);
|
|
builder.append_comma();
|
|
builder.append_key_value("year", car.year);
|
|
builder.append_comma();
|
|
builder.append_key_value("tire_pressure", car.tire_pressure);
|
|
builder.end_object();
|
|
}
|
|
bool car_test_simple() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
Car c = {"Toyota", "Corolla", 2017, {30.0, 30.2, 30.513, 30.79}};
|
|
serialize_car(c, sb);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,"
|
|
"\"tire_pressure\":[30.0,30.2,30.513,30.79]}");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool car_test_simple_complete() {
|
|
TEST_START();
|
|
Car c = {"Toyota", "Corolla", 2017, {30.0, 30.2, 30.513, 30.79}};
|
|
simdjson::builder::string_builder sb;
|
|
sb.start_object();
|
|
sb.append_key_value("make", c.make);
|
|
sb.append_comma();
|
|
sb.append_key_value("model", c.model);
|
|
sb.append_comma();
|
|
sb.append_key_value("year", c.year);
|
|
sb.append_comma();
|
|
sb.append_key_value("tire_pressure", c.tire_pressure);
|
|
sb.end_object();
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,"
|
|
"\"tire_pressure\":[30.0,30.2,30.513,30.79]}");
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool map_test() {
|
|
TEST_START();
|
|
std::map<std::string, double> c = {{"key1", 1}, {"key2", 1}};
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(c);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "{\"key1\":1.0,\"key2\":1.0}");
|
|
std::string s;
|
|
|
|
ASSERT_SUCCESS(simdjson::to_json(c).get(s));
|
|
ASSERT_EQUAL(s, "{\"key1\":1.0,\"key2\":1.0}");
|
|
TEST_SUCCEED();
|
|
}
|
|
bool ranges_test() {
|
|
TEST_START();
|
|
struct Foo {
|
|
int a;
|
|
float b;
|
|
};
|
|
std::vector<Foo> c = {{1, 2.0f}, {3, 4.0f}, {5, 6.0f}, {7, 8.0f}};
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(c | std::views::transform(&Foo::b));
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "[2.0,4.0,6.0,8.0]");
|
|
std::string s;
|
|
ASSERT_SUCCESS(simdjson::to_json(c | std::views::transform(&Foo::b)).get(s));
|
|
ASSERT_EQUAL(s, "[2.0,4.0,6.0,8.0]");
|
|
TEST_SUCCEED();
|
|
}
|
|
bool double_double_test() {
|
|
TEST_START();
|
|
std::vector<std::vector<double>> c = {{1.0, 2.0}, {3.0, 4.0}};
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(c);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "[[1.0,2.0],[3.0,4.0]]");
|
|
std::string s;
|
|
ASSERT_SUCCESS(simdjson::to_json(c).get(s));
|
|
ASSERT_EQUAL(s, "[[1.0,2.0],[3.0,4.0]]");
|
|
TEST_SUCCEED();
|
|
}
|
|
bool double_double_test_to_string() {
|
|
TEST_START();
|
|
std::vector<std::vector<double>> c = {{1.0, 2.0}, {3.0, 4.0}};
|
|
simdjson::builder::string_builder sb;
|
|
sb.append(c);
|
|
std::string_view p;
|
|
auto result = sb.view().get(p);
|
|
ASSERT_SUCCESS(result);
|
|
ASSERT_EQUAL(p, "[[1.0,2.0],[3.0,4.0]]");
|
|
std::string s;
|
|
simdjson::simdjson_error ec = simdjson::to_json(c, s);
|
|
ASSERT_EQUAL(s, "[[1.0,2.0],[3.0,4.0]]");
|
|
TEST_SUCCEED();
|
|
}
|
|
#if SIMDJSON_EXCEPTIONS
|
|
bool car_test_simple_complete_exceptions() {
|
|
TEST_START();
|
|
Car c = {"Toyota", "Corolla", 2017, {30.0, 30.2, 30.513, 30.79}};
|
|
simdjson::builder::string_builder sb;
|
|
sb.start_object();
|
|
sb.append_key_value("make", c.make);
|
|
sb.append_comma();
|
|
sb.append_key_value("model", c.model);
|
|
sb.append_comma();
|
|
sb.append_key_value("year", c.year);
|
|
sb.append_comma();
|
|
sb.append_key_value("tire_pressure", c.tire_pressure);
|
|
sb.end_object();
|
|
std::string_view p = sb.view();
|
|
ASSERT_EQUAL(p, "{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,"
|
|
"\"tire_pressure\":[30.0,30.2,30.513,30.79]}");
|
|
TEST_SUCCEED();
|
|
}
|
|
#endif // SIMDJSON_EXCEPTIONS
|
|
#endif // SIMDJSONS_SUPPORT_RANGES
|
|
|
|
#if SIMDJSON_EXCEPTIONS
|
|
bool car_test_exception() {
|
|
TEST_START();
|
|
simdjson::builder::string_builder sb;
|
|
Car c = {"Toyota", "Corolla", 2017, {30.0, 30.2, 30.513, 30.79}};
|
|
serialize_car_long(c, sb);
|
|
std::string_view p{sb};
|
|
ASSERT_EQUAL(p, "{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,"
|
|
"\"tire_pressure\":[30.0,30.2,30.513,30.79]}");
|
|
TEST_SUCCEED();
|
|
}
|
|
#endif
|
|
bool run() {
|
|
return allchar_test() && bad_utf8_test() && various_integers() &&
|
|
various_unsigned_integers() && car_test_long() && car_test() &&
|
|
#if SIMDJSON_EXCEPTIONS
|
|
car_test_exception() && string_convertion_except() &&
|
|
#endif
|
|
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
|
map_test() && ranges_test() && double_double_test() &&
|
|
double_double_test_to_string() && car_test_simple() &&
|
|
car_test_simple_complete() &&
|
|
#if SIMDJSON_EXCEPTIONS
|
|
car_test_simple_complete_exceptions() &&
|
|
#endif
|
|
#endif
|
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
|
issue2549() && car_test_template() && serialize_optional() &&
|
|
#endif
|
|
append_char() && append_integer() && append_float() && append_null() &&
|
|
#if SIMDJSON_ENABLE_NAN_INF
|
|
append_nan() && append_positive_infinity() &&
|
|
append_negative_infinity() && append_float_nan_inf() &&
|
|
nan_inf_in_array() && nan_inf_in_object() && nan_inf_roundtrip() &&
|
|
#endif
|
|
clear() && escape_and_append() && escape_and_append_with_quotes() &&
|
|
append_raw() && raw_with_length() && string_convertion() &&
|
|
buffer_growth() && unicode_validation() && true;
|
|
}
|
|
|
|
} // namespace builder_tests
|
|
|
|
int main(int argc, char *argv[]) {
|
|
return test_main(argc, argv, builder_tests::run);
|
|
}
|