Make ParsedJson::Iterator backcompat test

This commit is contained in:
John Keiser 2020-03-27 08:31:47 -07:00
parent c95e45d283
commit f0f111b387
4 changed files with 280 additions and 268 deletions

View File

@ -73,8 +73,12 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
#define unlikely(x) x
#endif
#define SIMDJSON_PUSH_DISABLE_WARNINGS __pragma(warning( push ))
#define SIMDJSON_DISABLE_VS_WARNING(WARNING_NUMBER) __pragma(warning( disable : WARNING_NUMBER ))
#define SIMDJSON_DISABLE_DEPRECATED_WARNING SIMDJSON_DISABLE_VS_WARNING(4996)
#define SIMDJSON_POP_DISABLE_WARNINGS __pragma(warning( pop ))
#else
#else // MSC_VER
#define really_inline inline __attribute__((always_inline, unused))
@ -90,6 +94,12 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#define SIMDJSON_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
#define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
#define SIMDJSON_DISABLE_DEPRECATED_WARNING SIMDJSON_DISABLE_GCC_WARNING(-Wdeprecated-declarations)
#define SIMDJSON_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop")
#endif // MSC_VER
#endif // SIMDJSON_COMMON_DEFS_H

View File

@ -180,20 +180,6 @@ public:
*/
inline element_result at_key(std::string_view s) const noexcept;
/**
* Get the value associated with the given key.
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *s) const noexcept;
std::unique_ptr<uint64_t[]> tape;
std::unique_ptr<uint8_t[]> string_buf;// should be at least byte_capacity
@ -256,6 +242,11 @@ public:
*/
inline array_result as_array() const noexcept;
/**
* Get the root element of this document.
*/
inline element_result root() const noexcept;
/**
* Get the value associated with the given JSON pointer.
*
@ -644,18 +635,14 @@ public:
inline element_result at_key(std::string_view s) const noexcept;
/**
* Get the value associated with the given key.
* Get the value associated with the given key in a case-insensitive manner.
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* Note: The key will be matched against **unescaped** JSON.
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *s) const noexcept;
inline element_result at_key_case_insensitive(std::string_view s) const noexcept;
private:
really_inline element(const document *_doc, size_t _json_index) noexcept;
@ -889,7 +876,7 @@ public:
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(std::string_view s) const noexcept;
inline element_result at_key(std::string_view key) const noexcept;
/**
* Get the value associated with the given key.
@ -899,18 +886,8 @@ public:
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *s) const noexcept;
inline element_result at_key(const char *key) const noexcept;
/**
* Get the value associated with the given key, the provided key is
* considered to have length characters.
*
* Note: The key will be matched against **unescaped** JSON.
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *s, size_t length) const noexcept;
/**
* Get the value associated with the given key in a case-insensitive manner.
*
@ -919,7 +896,17 @@ public:
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key_case_insensitive(const char *s) const noexcept;
inline element_result at_key_case_insensitive(std::string_view key) const noexcept;
/**
* Get the value associated with the given key in a case-insensitive manner.
*
* Note: The key will be matched against **unescaped** JSON.
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key_case_insensitive(const char *key) const noexcept;
private:
really_inline object(const document *_doc, size_t _json_index) noexcept;
@ -967,6 +954,8 @@ public:
inline element_result at(size_t index) const noexcept;
inline element_result at_key(std::string_view key) const noexcept;
inline element_result at_key(const char *key) const noexcept;
inline element_result at_key_case_insensitive(std::string_view key) const noexcept;
inline element_result at_key_case_insensitive(const char *key) const noexcept;
#if SIMDJSON_EXCEPTIONS
inline operator bool() const noexcept(false);
@ -1009,7 +998,7 @@ public:
inline element_result operator[](const char *json_pointer) const noexcept;
inline element_result at(std::string_view json_pointer) const noexcept;
inline element_result at_key(std::string_view key) const noexcept;
inline element_result at_key(const char *key) const noexcept;
inline element_result at_key_case_insensitive(std::string_view key) const noexcept;
#if SIMDJSON_EXCEPTIONS
inline object::iterator begin() const noexcept(false);

View File

@ -75,9 +75,9 @@ inline document::element_result document::element_result::at_key(std::string_vie
if (error()) { return *this; }
return first.at_key(key);
}
inline document::element_result document::element_result::at_key(const char *key) const noexcept {
inline document::element_result document::element_result::at_key_case_insensitive(std::string_view key) const noexcept {
if (error()) { return *this; }
return first.at_key(key);
return first.at_key_case_insensitive(key);
}
#if SIMDJSON_EXCEPTIONS
@ -167,9 +167,9 @@ inline document::element_result document::object_result::at_key(std::string_view
if (error()) { return error(); }
return first.at_key(key);
}
inline document::element_result document::object_result::at_key(const char *key) const noexcept {
inline document::element_result document::object_result::at_key_case_insensitive(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at_key(key);
return first.at_key_case_insensitive(key);
}
#if SIMDJSON_EXCEPTIONS
@ -227,9 +227,6 @@ inline document::element_result document::at(size_t index) const noexcept {
inline document::element_result document::at_key(std::string_view key) const noexcept {
return as_object().at_key(key);
}
inline document::element_result document::at_key(const char *key) const noexcept {
return as_object().at_key(key);
}
inline document::element_result document::operator[](std::string_view json_pointer) const noexcept {
return at(json_pointer);
}
@ -359,12 +356,14 @@ inline bool document::dump_raw_tape(std::ostream &os) const noexcept {
inline document::doc_result::doc_result(document &doc, error_code error) noexcept : simdjson_result<document&>(doc, error) { }
inline document::array_result document::doc_result::as_array() const noexcept {
if (error()) { return error(); }
return first.root().as_array();
return root().as_array();
}
inline document::object_result document::doc_result::as_object() const noexcept {
return root().as_object();
}
inline document::element_result document::doc_result::root() const noexcept {
if (error()) { return error(); }
return first.root().as_object();
return first.root();
}
inline document::element_result document::doc_result::operator[](std::string_view key) const noexcept {
@ -783,16 +782,6 @@ inline document::element_result document::object::at(std::string_view json_point
return child;
}
inline document::element_result document::object::at_key(const char *key, size_t length) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
std::string_view v{field.key()};
if ((v.size() == length) && (!memcmp(v.data(), key, length))) {
return field.value();
}
}
return NO_SUCH_FIELD;
}
inline document::element_result document::object::at_key(std::string_view key) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
@ -802,27 +791,21 @@ inline document::element_result document::object::at_key(std::string_view key) c
}
return NO_SUCH_FIELD;
}
inline document::element_result document::object::at_key(const char *key) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
if (!strcmp(key, field.key_c_str())) {
return field.value();
}
}
return NO_SUCH_FIELD;
}
// In case you wonder why we need this, please see
// https://github.com/simdjson/simdjson/issues/323
// People do seek keys in a case-insensitive manner.
inline document::element_result document::object::at_key_case_insensitive(const char *key) const noexcept {
inline document::element_result document::object::at_key_case_insensitive(std::string_view key) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
if (!simdjson_strcasecmp(key, field.key_c_str())) {
if (std::equal(key.begin(), key.end(), field.key().begin(), [](char a, char b) {
return std::tolower(a) == std::tolower(b);
})) {
return field.value();
}
}
return NO_SUCH_FIELD;
}
//
// document::object::iterator inline implementation
//
@ -1021,8 +1004,8 @@ inline document::element_result document::element::at(size_t index) const noexce
inline document::element_result document::element::at_key(std::string_view key) const noexcept {
return as_object().at_key(key);
}
inline document::element_result document::element::at_key(const char *key) const noexcept {
return as_object().at_key(key);
inline document::element_result document::element::at_key_case_insensitive(std::string_view key) const noexcept {
return as_object().at_key_case_insensitive(key);
}
//

View File

@ -48,22 +48,11 @@ namespace number_tests {
auto n = sprintf(buf, "%*d", m, i);
buf[n] = '\0';
fflush(NULL);
auto [pj, error] = parser.parse(buf, n);
if (error) {
printf("Could not parse '%s': %s\n", buf, simdjson::error_message(error));
return false;
}
if(!pj.root().is_number()) {
printf("Root should be number\n");
return false;
}
if(!pj.root().is_integer()) {
printf("Root should be an integer\n");
return false;
}
int64_t x = pj.root().as_int64_t();
if(x != i) {
printf("failed to parse %s. \n", buf);
auto [actual, error] = parser.parse(buf, n).root().as_int64_t();
if (error) { std::cerr << error << std::endl; return false; }
if (actual != i) {
std::cerr << "JSON '" << buf << " parsed to " << actual << " instead of " << i << std::endl;
return false;
}
}
@ -83,55 +72,16 @@ namespace number_tests {
auto n = sprintf(buf, "%.*e", std::numeric_limits<double>::max_digits10 - 1, expected);
buf[n] = '\0';
fflush(NULL);
auto [pj, error] = parser.parse(buf, n);
if (error) {
printf("Could not parse '%s': %s\n", buf, simdjson::error_message(error));
return false;
}
if(!pj.root().is_number()) {
printf("Root should be number\n");
return false;
}
if(pj.root().is_unsigned_integer()) {
uint64_t x = pj.root().as_uint64_t();
int power = 0;
while(x > 1) {
if((x % 2) != 0) {
printf("failed to parse %s. \n", buf);
return false;
}
x = x / 2;
power ++;
}
if(power != i) {
printf("failed to parse %s. \n", buf);
return false;
}
} else if(pj.root().is_integer()) {
int64_t x = pj.root().as_int64_t();
int power = 0;
while(x > 1) {
if((x % 2) != 0) {
printf("failed to parse %s. \n", buf);
return false;
}
x = x / 2;
power ++;
}
if(power != i) {
printf("failed to parse %s. \n", buf);
return false;
}
} else {
double x = pj.root().as_double();
int ulp = f64_ulp_dist(x,expected);
auto [actual, error] = parser.parse(buf, n).root().as_double();
if (error) { std::cerr << error << std::endl; return false; }
int ulp = f64_ulp_dist(actual,expected);
if(ulp > maxulp) maxulp = ulp;
if(ulp > 0) {
printf("failed to parse %s. ULP = %d i = %d \n", buf, ulp, i);
std::cerr << "JSON '" << buf << " parsed to " << actual << " instead of " << expected << std::endl;
return false;
}
}
}
printf("Powers of 2 can be parsed, maxulp = %d.\n", maxulp);
return true;
}
@ -212,62 +162,21 @@ namespace number_tests {
bool powers_of_ten() {
std::cout << __func__ << std::endl;
char buf[1024];
simdjson::document::parser parser;
for (int i = -1000000; i <= 308; ++i) {// large negative values should be zero.
auto n = sprintf(buf,"1e%d", i);
buf[n] = '\0';
fflush(NULL);
simdjson::document::parser parser;
auto [pj, error] = parser.parse(buf, n);
if (error) {
printf("Could not parse '%s': %s\n", buf, simdjson::error_message(error));
return false;
}
if(!pj.root().is_number()) {
printf("Root should be number\n");
return false;
}
if(pj.root().is_unsigned_integer()) {
uint64_t x = pj.root().as_uint64_t();
int power = 0;
while(x > 1) {
if((x % 10) != 0) {
printf("failed to parse %s. \n", buf);
return false;
}
x = x / 10;
power ++;
}
if(power != i) {
printf("failed to parse %s. \n", buf);
return false;
}
} if(pj.root().is_integer()) {
int64_t x = pj.root().as_int64_t();
int power = 0;
while(x > 1) {
if((x % 10) != 0) {
printf("failed to parse %s. \n", buf);
return false;
}
x = x / 10;
power ++;
}
if(power != i) {
printf("failed to parse %s. \n", buf);
return false;
}
} else {
double x = pj.root().as_double();
auto [actual, error] = parser.parse(buf, n).root().as_double();
if (error) { std::cerr << error << std::endl; return false; }
double expected = ((i >= -307) ? testing_power_of_ten[i + 307]: std::pow(10, i));
int ulp = (int) f64_ulp_dist(x, expected);
int ulp = (int) f64_ulp_dist(actual, expected);
if(ulp > 0) {
printf("failed to parse %s. \n", buf);
printf("actual: %.20g expected: %.20g \n", x, expected);
printf("ULP: %d \n", ulp);
std::cerr << "JSON '" << buf << " parsed to " << actual << " instead of " << expected << std::endl;
return false;
}
}
}
printf("Powers of 10 can be parsed.\n");
return true;
}
@ -309,9 +218,8 @@ namespace document_tests {
"}"
"}"_padded;
simdjson::document::parser parser;
auto [pj, error] = parser.parse(json);
std::ostringstream myStream;
myStream << pj;
myStream << parser.parse(json);
std::string newjson = myStream.str();
if(static_cast<std::string>(json) != newjson) {
std::cout << "serialized json differs!" << std::endl;
@ -659,110 +567,129 @@ namespace parse_api_tests {
}
}
namespace dom_api_tests {
namespace deprecated_tests {
using namespace std;
using namespace simdjson;
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
// returns true if successful
bool document_iterator_test() {
bool ParsedJson_Iterator_test() {
std::cout << "Running " << __func__ << std::endl;
simdjson::padded_string json = "{"
"\"Image\": {"
"\"Width\": 800,"
"\"Height\": 600,"
"\"Title\": \"View from 15th Floor\","
"\"Thumbnail\": {"
" \"Url\": \"http://www.example.com/image/481989943\","
" \"Height\": 125,"
" \"Width\": 100"
"},"
"\"Animated\" : false,"
"\"IDs\": [116, 943, 234, 38793]"
"}"
"}"_padded;
simdjson::document::parser parser;
auto [pj, error] = parser.parse(json);
if (error) {
printf("Could not parse '%s': %s\n", json.data(), simdjson::error_message(error));
simdjson::padded_string json = R"({
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": 100
},
"Animated" : false,
"IDs": [116, 943, 234, 38793]
}
})"_padded;
simdjson::ParsedJson pj = build_parsed_json(json);
if (pj.error) {
printf("Could not parse '%s': %s\n", json.data(), simdjson::error_message(pj.error));
return false;
}
if(!pj.root().is_object()) {
simdjson::ParsedJson::Iterator iter(pj);
if (!iter.is_object()) {
printf("Root should be object\n");
return false;
}
auto [object, err] = pj.root().as_object();
if(err) {
printf("can't convert to object?\n");
return false;
}
auto [b1, e1] = object.at_key("bad key");
if(!e1) {
if (iter.move_to_key("bad key")) {
printf("We should not move to a non-existing key\n");
return false;
}
auto [b2, e2] = object.at_key_case_insensitive("bad key");
if(!e2) {
printf("We should not move to a non-existing key\n");
return false;
}
if(!pj.root().is_object()) {
if (!iter.is_object()) {
printf("We should have remained at the object.\n");
return false;
}
auto [b3, e3] = object.at_key("bad key", 7);
if(!e3) {
if (iter.move_to_key_insensitive("bad key")) {
printf("We should not move to a non-existing key\n");
return false;
}
if(!pj.root().is_object()) {
if (!iter.is_object()) {
printf("We should have remained at the object.\n");
return false;
}
auto img_element = object.at_key("Image");
if(!img_element.get().is_object()) {
if (!iter.down()) {
printf("Root should not be emtpy\n");
return false;
}
if (!iter.is_string()) {
printf("Object should start with string key\n");
return false;
}
if (iter.prev()) {
printf("We should not be able to go back from the start of the scope.\n");
return false;
}
if (strcmp(iter.get_string(),"Image")!=0) {
printf("There should be a single key, image.\n");
return false;
}
iter.move_to_value();
if(!iter.is_object()) {
printf("Value of image should be object\n");
return false;
}
auto root_object = pj.root().as_object();
auto img_object = img_element.get().as_object();
size_t co = 0;
for(auto [k,v]: root_object) {
co++;
if(strcmp(k.data(),"Image")!=0) {
printf("There should be a single key, Image.\n");
if(!iter.down()) {
printf("Image key should not be emtpy\n");
return false;
}
}
if( co != 1 ) {
printf("There should be a single key, Image, I found %zu.\n", co);
if(!iter.next()) {
printf("key should have a value\n");
return false;
}
if( img_object.at_key("Width").as_int64_t() != 800) {
printf("There should be a Width element and its value should be 800\n");
if(!iter.prev()) {
printf("We should go back to the key.\n");
return false;
}
auto ids_element = img_object.at_key("IDs");
if(!ids_element.get().is_array()) {
printf("Value of IDs should be array.\n");
if (strcmp(iter.get_string(),"Width")!=0) {
printf("There should be a key Width.\n");
return false;
}
std::vector<int64_t> val;
for(int64_t v : ids_element.as_array()) {
val.push_back(v);
if (!iter.up()) {
return false;
}
std::vector<int64_t> tv = {116, 943, 234, 38793};
if(val != tv) {
printf("The values do not match.\n");
if (!iter.move_to_key("IDs")) {
printf("We should be able to move to an existing key\n");
return false;
}
if (!iter.is_array()) {
printf("Value of IDs should be array, it is %c \n", iter.get_type());
return false;
}
if (iter.move_to_index(4)) {
printf("We should not be able to move to a non-existing index\n");
return false;
}
if (!iter.is_array()) {
printf("We should have remained at the array\n");
return false;
}
return true;
}
SIMDJSON_POP_DISABLE_WARNINGS
bool run() {
return ParsedJson_Iterator_test() &&
true;
}
}
namespace dom_api_tests {
using namespace std;
using namespace simdjson;
bool object_iterator() {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "a": 1, "b": 2, "c": 3 })");
auto json = R"({ "a": 1, "b": 2, "c": 3 })"_padded;
const char* expected_key[] = { "a", "b", "c" };
uint64_t expected_value[] = { 1, 2, 3 };
int i = 0;
@ -780,7 +707,7 @@ namespace dom_api_tests {
bool array_iterator() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ 1, 10, 100 ])");
auto json = R"([ 1, 10, 100 ])"_padded;
uint64_t expected_value[] = { 1, 10, 100 };
int i=0;
@ -797,7 +724,7 @@ namespace dom_api_tests {
bool object_iterator_empty() {
std::cout << "Running " << __func__ << std::endl;
string json(R"({})");
auto json = R"({})"_padded;
int i = 0;
document::parser parser;
@ -813,7 +740,7 @@ namespace dom_api_tests {
bool array_iterator_empty() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([])");
auto json = R"([])"_padded;
int i=0;
document::parser parser;
@ -827,9 +754,108 @@ namespace dom_api_tests {
return true;
}
bool array_at() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ 1, 10, 100 ])"_padded;
uint64_t expected[] = { 1, 10, 100 };
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
uint64_t actual;
{
int i = 2;
array.at(i).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected[i]) { cerr << "Got [" << i << "] = " << actual << ", expected " << expected[i] << endl; return false; }
}
{
int i = 0;
array.at(i).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected[i]) { cerr << "Got [" << i << "] = " << actual << ", expected " << expected[i] << endl; return false; }
}
{
int i = 1;
array.at(i).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected[i]) { cerr << "Got [" << i << "] = " << actual << ", expected " << expected[i] << endl; return false; }
}
{
int i = 3;
array.at(i).as_uint64_t().tie(actual, error);
if (!error) { cerr << "Expected error accessing [" << i << "], got " << actual << " instead!" << endl; return false; }
}
return true;
}
bool object_at_key() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "foo": 1, "bar": 2 })"_padded;
document::parser parser;
auto [object, error] = parser.parse(json).as_object();
uint64_t actual;
{
string key = "bar";
uint64_t expected = 2;
object.at_key(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "foo";
uint64_t expected = 1;
object.at_key(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "baz";
object.at_key(key).as_uint64_t().tie(actual, error);
if (!error) { cerr << "Expected error accessing " << key << ", got " << actual << " instead!" << endl; return false; }
}
return true;
}
bool object_at_key_case_insensitive() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "foo": 1, "Bar": 2 })"_padded;
document::parser parser;
auto [object, error] = parser.parse(json).as_object();
uint64_t actual;
{
string key = "bar";
uint64_t expected = 2;
object.at_key_case_insensitive(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "BAR";
uint64_t expected = 2;
object.at_key_case_insensitive(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "Bar";
uint64_t expected = 2;
object.at_key_case_insensitive(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "baz";
object.at_key_case_insensitive(key).as_uint64_t().tie(actual, error);
if (!error) { cerr << "Expected error accessing " << key << ", got " << actual << " instead!" << endl; return false; }
}
return true;
}
bool string_value() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ "hi", "has backslash\\" ])");
auto json = R"([ "hi", "has backslash\\" ])"_padded;
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
if (error) { cerr << "Error: " << error << endl; return false; }
@ -843,7 +869,7 @@ namespace dom_api_tests {
bool numeric_values() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ 0, 1, -1, 1.1 ])");
auto json = R"([ 0, 1, -1, 1.1 ])"_padded;
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
if (error) { cerr << "Error: " << error << endl; return false; }
@ -866,7 +892,7 @@ namespace dom_api_tests {
bool boolean_values() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ true, false ])");
auto json = R"([ true, false ])"_padded;
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
if (error) { cerr << "Error: " << error << endl; return false; }
@ -880,7 +906,7 @@ namespace dom_api_tests {
bool null_value() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ null ])");
auto json = R"([ null ])"_padded;
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
if (error) { cerr << "Error: " << error << endl; return false; }
@ -891,7 +917,7 @@ namespace dom_api_tests {
bool document_object_index() {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "a": 1, "b": 2, "c": 3})");
auto json = R"({ "a": 1, "b": 2, "c": 3})"_padded;
document::parser parser;
auto [doc, error] = parser.parse(json);
if (doc["a"].as_uint64_t().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; }
@ -911,7 +937,7 @@ namespace dom_api_tests {
bool object_index() {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "obj": { "a": 1, "b": 2, "c": 3 } })");
auto json = R"({ "obj": { "a": 1, "b": 2, "c": 3 } })"_padded;
document::parser parser;
auto [doc, error] = parser.parse(json);
if (error) { cerr << "Error: " << error << endl; return false; }
@ -1005,7 +1031,7 @@ namespace dom_api_tests {
bool object_iterator_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "a": 1, "b": 2, "c": 3 })");
auto json = R"({ "a": 1, "b": 2, "c": 3 })"_padded;
const char* expected_key[] = { "a", "b", "c" };
uint64_t expected_value[] = { 1, 2, 3 };
int i = 0;
@ -1022,7 +1048,7 @@ namespace dom_api_tests {
bool array_iterator_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ 1, 10, 100 ])");
auto json = R"([ 1, 10, 100 ])"_padded;
uint64_t expected_value[] = { 1, 10, 100 };
int i=0;
@ -1038,7 +1064,7 @@ namespace dom_api_tests {
bool string_value_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ "hi", "has backslash\\" ])");
auto json = R"([ "hi", "has backslash\\" ])"_padded;
document::parser parser;
document::array array = parser.parse(json).as_array();
auto val = array.begin();
@ -1053,7 +1079,7 @@ namespace dom_api_tests {
bool numeric_values_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ 0, 1, -1, 1.1 ])");
auto json = R"([ 0, 1, -1, 1.1 ])"_padded;
document::parser parser;
document::array array = parser.parse(json).as_array();
auto val = array.begin();
@ -1075,7 +1101,7 @@ namespace dom_api_tests {
bool boolean_values_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ true, false ])");
auto json = R"([ true, false ])"_padded;
document::parser parser;
document::array array = parser.parse(json).as_array();
auto val = array.begin();
@ -1088,7 +1114,7 @@ namespace dom_api_tests {
bool null_value_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ null ])");
auto json = R"([ null ])"_padded;
document::parser parser;
document::array array = parser.parse(json).as_array();
auto val = array.begin();
@ -1099,7 +1125,7 @@ namespace dom_api_tests {
bool document_object_index_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "a": 1, "b": 2, "c": 3})");
auto json = R"({ "a": 1, "b": 2, "c": 3})"_padded;
document::parser parser;
document &doc = parser.parse(json);
if (uint64_t(doc["a"]) != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << uint64_t(doc["a"]) << endl; return false; }
@ -1108,7 +1134,7 @@ namespace dom_api_tests {
bool object_index_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "obj": { "a": 1, "b": 2, "c": 3 } })");
auto json = R"({ "obj": { "a": 1, "b": 2, "c": 3 } })"_padded;
document::parser parser;
document::object obj = parser.parse(json)["obj"];
if (uint64_t(obj["a"]) != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << uint64_t(obj["a"]) << endl; return false; }
@ -1164,11 +1190,13 @@ namespace dom_api_tests {
#endif
bool run() {
return document_iterator_test() &&
object_iterator() &&
return object_iterator() &&
array_iterator() &&
object_iterator_empty() &&
array_iterator_empty() &&
array_at() &&
object_at_key() &&
object_at_key_case_insensitive() &&
string_value() &&
numeric_values() &&
boolean_values() &&
@ -1478,8 +1506,10 @@ int main(int argc, char *argv[]) {
format_tests::run() &&
document_tests::run() &&
number_tests::run() &&
error_messages_in_correct_order() &&
deprecated_tests::run() &&
document_stream_tests::run() &&
error_messages_in_correct_order()
true
) {
std::cout << "Basic tests are ok." << std::endl;
return EXIT_SUCCESS;