diff --git a/include/simdjson/common_defs.h b/include/simdjson/common_defs.h index ddb5e9c4..ddacf8c1 100644 --- a/include/simdjson/common_defs.h +++ b/include/simdjson/common_defs.h @@ -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 diff --git a/include/simdjson/document.h b/include/simdjson/document.h index 6602ee93..935a0d4e 100644 --- a/include/simdjson/document.h +++ b/include/simdjson/document.h @@ -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 tape; std::unique_ptr 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); diff --git a/include/simdjson/inline/document.h b/include/simdjson/inline/document.h index 4afbab4b..dc0bd479 100644 --- a/include/simdjson/inline/document.h +++ b/include/simdjson/inline/document.h @@ -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(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); } // diff --git a/tests/basictests.cpp b/tests/basictests.cpp index 131e301e..cedddf62 100644 --- a/tests/basictests.cpp +++ b/tests/basictests.cpp @@ -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,54 +72,15 @@ namespace number_tests { auto n = sprintf(buf, "%.*e", std::numeric_limits::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)); + + 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) { + std::cerr << "JSON '" << buf << " parsed to " << actual << " instead of " << expected << std::endl; 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); - if(ulp > maxulp) maxulp = ulp; - if(ulp > 0) { - printf("failed to parse %s. ULP = %d i = %d \n", buf, ulp, i); - return false; - } - } } printf("Powers of 2 can be parsed, maxulp = %d.\n", maxulp); return true; @@ -212,61 +162,20 @@ 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)); + + 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(actual, expected); + if(ulp > 0) { + std::cerr << "JSON '" << buf << " parsed to " << actual << " instead of " << expected << std::endl; 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(); - double expected = ((i >= -307) ? testing_power_of_ten[i + 307]: std::pow(10, i)); - int ulp = (int) f64_ulp_dist(x, expected); - if(ulp > 0) { - printf("failed to parse %s. \n", buf); - printf("actual: %.20g expected: %.20g \n", x, expected); - printf("ULP: %d \n", ulp); - 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(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"); + if (iter.move_to_key("bad key")) { + printf("We should not move to a non-existing key\n"); return false; } - auto [b1, e1] = object.at_key("bad key"); - if(!e1) { - 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"); - return false; - } - } - if( co != 1 ) { - printf("There should be a single key, Image, I found %zu.\n", co); + if(!iter.down()) { + printf("Image key should not be emtpy\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.next()) { + printf("key should have a value\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(!iter.prev()) { + printf("We should go back to the key.\n"); return false; } - std::vector val; - for(int64_t v : ids_element.as_array()) { - val.push_back(v); + if (strcmp(iter.get_string(),"Width")!=0) { + printf("There should be a key Width.\n"); + return false; } - std::vector tv = {116, 943, 234, 38793}; - if(val != tv) { - printf("The values do not match.\n"); + if (!iter.up()) { + return false; + } + 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;