From 6fa5abcd7e481738c5588a286a02ad59d3a506c0 Mon Sep 17 00:00:00 2001 From: John Keiser Date: Sun, 21 Jun 2020 14:36:38 -0700 Subject: [PATCH] Replace x.get() with x.get(v) or T(x) --- benchmark/bench_dom_api.cpp | 6 +- benchmark/distinctuseridcompetition.cpp | 11 +- benchmark/parseandstatcompetition.cpp | 4 +- doc/basics.md | 19 +- include/simdjson/dom/element.h | 12 +- include/simdjson/dom/object.h | 12 +- tests/basictests.cpp | 531 +++++++++++------------- tests/errortests.cpp | 36 +- tests/integer_tests.cpp | 66 +-- tests/pointercheck.cpp | 52 ++- tests/readme_examples.cpp | 12 +- tests/test_macros.h | 18 +- 12 files changed, 366 insertions(+), 413 deletions(-) diff --git a/benchmark/bench_dom_api.cpp b/benchmark/bench_dom_api.cpp index 1440942c7..294977e25 100644 --- a/benchmark/bench_dom_api.cpp +++ b/benchmark/bench_dom_api.cpp @@ -407,7 +407,7 @@ static void iterator_twitter_default_profile(State& state) { set default_users; ParsedJson::Iterator iter(pj); - // for (dom::object tweet : doc["statuses"].get()) { + // for (dom::object tweet : doc["statuses"]) { if (!(iter.move_to_key("statuses") && iter.is_array())) { return; } if (iter.down()) { // first status do { @@ -480,7 +480,7 @@ static void iterator_twitter_image_sizes(State& state) { set> image_sizes; ParsedJson::Iterator iter(pj); - // for (dom::object tweet : doc["statuses"].get()) { + // for (dom::object tweet : doc["statuses"]) { if (!(iter.move_to_key("statuses") && iter.is_array())) { return; } if (iter.down()) { // first status do { @@ -492,7 +492,7 @@ static void iterator_twitter_image_sizes(State& state) { if (iter.move_to_key("media")) { if (!iter.is_array()) { return; } - // for (dom::object image : media.get()) { + // for (dom::object image : media) { if (iter.down()) { // first media do { diff --git a/benchmark/distinctuseridcompetition.cpp b/benchmark/distinctuseridcompetition.cpp index 100c48f66..a9bb86dc6 100644 --- a/benchmark/distinctuseridcompetition.cpp +++ b/benchmark/distinctuseridcompetition.cpp @@ -40,17 +40,18 @@ void print_vec(const std::vector &v) { // simdjson_recurse below come be implemented like so but it is slow: /*void simdjson_recurse(std::vector & v, simdjson::dom::element element) { - if (element.is()) { - auto [array, array_error] = element.get(); + error_code error; + if (element.is_array()) { + dom::array array; + error = element.get(array); for (auto child : array) { if (child.is() || child.is()) { simdjson_recurse(v, child); } } - } else if (element.is()) { - auto [object, error] = element.get(); + } else if (element.is_object()) { int64_t id; - error = object["user"]["id"].get(id); + error = element["user"]["id"].get(id); if(!error) { v.push_back(id); } diff --git a/benchmark/parseandstatcompetition.cpp b/benchmark/parseandstatcompetition.cpp index eb017ebd9..d18ffc992 100644 --- a/benchmark/parseandstatcompetition.cpp +++ b/benchmark/parseandstatcompetition.cpp @@ -154,11 +154,11 @@ static void GenStatPlus(Stat &stat, const dom::element &v) { break; case dom::element_type::STRING: { stat.stringCount++; - std::string_view sv = v.get(); + auto sv = std::string_view(v); stat.stringLength += sv.size(); } break; case dom::element_type::BOOL: - if (v.get()) { + if (bool(v)) { stat.trueCount++; } else { stat.falseCount++; diff --git a/doc/basics.md b/doc/basics.md index e1bb0708c..0f5c5d541 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -164,7 +164,7 @@ And another one: auto abstract_json = R"( { "str" : { "123" : {"abc" : 3.14 } } } )"_padded; dom::parser parser; - double v = parser.parse(abstract_json)["str"]["123"]["abc"].get(); + double v = parser.parse(abstract_json)["str"]["123"]["abc"]; cout << "number: " << v << endl; ``` @@ -191,14 +191,13 @@ Though it does not validate the JSON input, it will detect when the document end C++17 Support ------------- -While the simdjson library can be used in any project using C++ 11 and above, it has special support -for C++ 17. The APIs for field iteration and error handling in particular are designed to work -nicely with C++17's destructuring syntax. For example: +While the simdjson library can be used in any project using C++ 11 and above, field iteration has special support C++ 17's destructuring syntax. For example: ```c++ -dom::parser parser; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; -auto [object, error] = parser.parse(json).get(); +dom::parser parser; +dom::object object; +auto error = parser.parse(json).get(object); if (error) { cerr << error << endl; return; } for (auto [key, value] : object) { cout << key << " = " << value << endl; @@ -209,11 +208,10 @@ For comparison, here is the C++ 11 version of the same code: ```c++ // C++ 11 version for comparison -dom::parser parser; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; -simdjson::error_code error; +dom::parser parser; dom::object object; -error = parser.parse(json).get(object); +auto error = parser.parse(json).get(object); if (!error) { cerr << error << endl; return; } for (dom::key_value_pair field : object) { cout << field.key << " = " << field.value << endl; @@ -378,8 +376,7 @@ And another one: cout << "number: " << v << endl; ``` -Notice how we can string several operation (`parser.parse(abstract_json)["str"]["123"]["abc"].get()`) and only check for the error once, a strategy we call *error chaining*. - +Notice how we can string several operations (`parser.parse(abstract_json)["str"]["123"]["abc"].get(v)`) and only check for the error once, a strategy we call *error chaining*. The next two functions will take as input a JSON document containing an array with a single element, either a string or a number. They return true upon success. diff --git a/include/simdjson/dom/element.h b/include/simdjson/dom/element.h index 6d9af51dd..9a9ce6f13 100644 --- a/include/simdjson/dom/element.h +++ b/include/simdjson/dom/element.h @@ -336,8 +336,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })")["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object @@ -351,8 +351,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })")["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object @@ -391,8 +391,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })")["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object diff --git a/include/simdjson/dom/object.h b/include/simdjson/dom/object.h index 9316914d9..301dad945 100644 --- a/include/simdjson/dom/object.h +++ b/include/simdjson/dom/object.h @@ -101,8 +101,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })")["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error() == NO_SUCH_FIELD * * This function has linear-time complexity: the keys are checked one by one. * @@ -118,8 +118,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })")["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error() == NO_SUCH_FIELD * * This function has linear-time complexity: the keys are checked one by one. * @@ -151,8 +151,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })")["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error() == NO_SUCH_FIELD * * This function has linear-time complexity: the keys are checked one by one. * diff --git a/tests/basictests.cpp b/tests/basictests.cpp index 80dc3d745..e5f3d8e85 100644 --- a/tests/basictests.cpp +++ b/tests/basictests.cpp @@ -17,6 +17,8 @@ #include "cast_tester.h" #include "test_macros.h" +const size_t AMAZON_CELLPHONES_NDJSON_DOC_COUNT = 793; + namespace number_tests { // ulp distance @@ -39,8 +41,8 @@ namespace number_tests { for (int m = 10; m < 20; m++) { for (int i = -1024; i < 1024; i++) { auto str = std::to_string(i); - auto [actual, error] = parser.parse(str).get(); - if (error) { std::cerr << error << std::endl; return false; } + int64_t actual; + ASSERT_SUCCESS(parser.parse(str).get(actual)); if (actual != i) { std::cerr << "JSON '" << str << "' parsed to " << actual << " instead of " << i << std::endl; return false; @@ -60,7 +62,8 @@ namespace number_tests { size_t n = snprintf(buf, sizeof(buf), "%.*e", std::numeric_limits::max_digits10 - 1, expected); if (n >= sizeof(buf)) { abort(); } fflush(NULL); - auto [actual, error] = parser.parse(buf, n).get(); + double actual; + auto error = parser.parse(buf, n).get(actual); if (error) { std::cerr << error << std::endl; return false; } uint64_t ulp = f64_ulp_dist(actual,expected); if(ulp > maxulp) maxulp = ulp; @@ -154,7 +157,8 @@ namespace number_tests { if (n >= sizeof(buf)) { abort(); } fflush(NULL); - auto [actual, error] = parser.parse(buf, n).get(); + double actual; + auto error = parser.parse(buf, n).get(actual); 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); @@ -229,41 +233,27 @@ namespace document_tests { std::cout << __func__ << std::endl; simdjson::padded_string smalljson = "[1,2,3]"_padded; simdjson::dom::parser parser; - auto [doc, error] = parser.parse(smalljson).get(); - if (error) { - printf("This json should be valid %s.\n", smalljson.data()); - return false; - } - if(doc.size() != 3) { - printf("This json should have size three but found %zu : %s.\n", doc.size(), smalljson.data()); - return false; - } + simdjson::dom::array array; + ASSERT_SUCCESS( parser.parse(smalljson).get(array) ); + ASSERT_EQUAL( array.size(), 3 ); return true; } bool count_object_example() { std::cout << __func__ << std::endl; simdjson::padded_string smalljson = "{\"1\":1,\"2\":1,\"3\":1}"_padded; simdjson::dom::parser parser; - auto [doc, error] = parser.parse(smalljson).get(); - if (error) { - printf("This json should be valid %s.\n", smalljson.data()); - return false; - } - if(doc.size() != 3) { - printf("This json should have size three but found %zu : %s.\n", doc.size(), smalljson.data()); - return false; - } + simdjson::dom::object object; + ASSERT_SUCCESS( parser.parse(smalljson).get(object) ); + ASSERT_EQUAL( object.size(), 3 ); return true; } bool padded_with_open_bracket() { std::cout << __func__ << std::endl; simdjson::dom::parser parser; // This is an invalid document padded with open braces. - auto error1 = parser.parse("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error(); - if (!error1) { std::cerr << "We expected an error but got: " << error1 << std::endl; return false; } + ASSERT_ERROR( parser.parse("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error(), simdjson::TAPE_ERROR); // This is a valid document padded with open braces. - auto error2 = parser.parse("[][[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error(); - if (error2) { std::cerr << "Error: " << error2 << std::endl; return false; } + ASSERT_SUCCESS( parser.parse("[][[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error() ); return true; } // returns true if successful @@ -524,16 +514,9 @@ namespace document_stream_tests { return false; } - auto [keyid, error2] = doc["id"].get(); - if (error2) { - printf("Error getting id as int64 on document %zd at batch size %zu: %s\n", count, batch_size, simdjson::error_message(error2)); - return false; - } - - if (keyid != int64_t(count)) { - printf("key does not match %" PRId64 ", expected %zd on document %zd at batch size %zu\n", keyid, count, count, batch_size); - return false; - } + int64_t keyid; + ASSERT_SUCCESS( doc["id"].get(keyid) ); + ASSERT_EQUAL( keyid, int64_t(count) ); count++; } @@ -576,23 +559,13 @@ namespace document_stream_tests { return false; } - auto [keyid, error2] = doc["id"].get(); - if (error2) { - printf("Error getting id as int64 on document %zd at batch size %zu: %s\n", count, batch_size, simdjson::error_message(error2)); - return false; - } - - if (keyid != int64_t(count)) { - printf("key does not match %" PRId64 ", expected %zd on document %zd at batch size %zu\n", keyid, count, count, batch_size); - return false; - } + int64_t keyid; + ASSERT_SUCCESS( doc["id"].get(keyid) ); + ASSERT_EQUAL( keyid, int64_t(count) ); count++; } - if(count != n_records) { - printf("Found wrong number of documents %zd, expected %zd at batch size %zu\n", count, n_records, batch_size); - return false; - } + ASSERT_EQUAL( count, n_records ) } printf("ok\n"); return true; @@ -662,10 +635,10 @@ namespace parse_api_tests { simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.parse_many(EMPTY_NDJSON).get(stream) ); for (auto doc : stream) { - if (doc.error()) { cerr << "Error in parse_many: " << doc.error() << endl; return false; } + ASSERT_SUCCESS(doc.error()); count++; } - if (count != 0) { cerr << "parse_many returned " << count << " documents, expected 0" << endl; return false; } + ASSERT_EQUAL(count, 0); return true; } @@ -682,22 +655,21 @@ namespace parse_api_tests { simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.parse_many(empty_batches_ndjson, BATCH_SIZE*16).get(stream) ); for (auto [doc, error] : stream) { - if (error) { cerr << "Error in parse_many: " << error << endl; return false; } + ASSERT_SUCCESS(error); count++; - auto [val, val_error] = doc.get(); - if (val_error) { cerr << "Document is not an unsigned int: " << val_error << endl; return false; } - if (val != count) { cerr << "Expected document #" << count << " to equal " << count << ", but got " << val << " instead!" << endl; return false; } + uint64_t val; + ASSERT_SUCCESS( doc.get(val) ); + ASSERT_EQUAL( val, count ); } - if (count != 3) { cerr << "parse_many returned " << count << " documents, expected 0" << endl; return false; } + ASSERT_EQUAL(count, 3); return true; } bool parser_load() { std::cout << "Running " << __func__ << " on " << TWITTER_JSON << std::endl; dom::parser parser; - auto [doc, error] = parser.load(TWITTER_JSON); - if (error) { cerr << error << endl; return false; } - if (!doc.is()) { cerr << "Document did not parse as an object" << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.load(TWITTER_JSON).get(object) ); return true; } bool parser_load_many() { @@ -707,21 +679,19 @@ namespace parse_api_tests { simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.load_many(AMAZON_CELLPHONES_NDJSON).get(stream) ); for (auto [doc, error] : stream) { - if (error) { cerr << error << endl; return false; } + ASSERT_SUCCESS( error ); dom::array arr; - error = doc.get(arr); // let us get the array - if (error) { cerr << error << endl; return false; } + ASSERT_SUCCESS( doc.get(arr) ); // let us get the array + ASSERT_EQUAL(arr.size(), 9); - if(arr.size() != 9) { cerr << "bad array size"<< endl; return false; } - - size_t c = 0; - for(auto v : arr) { c++; (void)v; } - if(c != 9) { cerr << "mismatched array size"<< endl; return false; } + size_t arr_count = 0; + for (auto v : arr) { arr_count++; (void)v; } + ASSERT_EQUAL(arr_count, 9); count++; } - if (count != 793) { cerr << "Expected 793 documents, but load_many loaded " << count << " documents." << endl; return false; } + ASSERT_EQUAL(count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT); return true; } @@ -735,18 +705,16 @@ namespace parse_api_tests { if (error) { cerr << error << endl; return false; } dom::array arr; - error = doc.get(arr); // let us get the array - if (error) { cerr << error << endl; return false; } + ASSERT_SUCCESS( doc.get(arr) ); + ASSERT_EQUAL( arr.size(), 9 ); - if(arr.size() != 9) { cerr << "bad array size"<< endl; return false; } - - size_t c = 0; - for(auto v : arr) { c++; (void)v; } - if(c != 9) { cerr << "mismatched array size"<< endl; return false; } + size_t arr_count = 0; + for (auto v : arr) { arr_count++; (void)v; } + ASSERT_EQUAL( arr_count, 9 ); count++; } - if (count != 793) { cerr << "Expected 793 documents, but load_many loaded " << count << " documents." << endl; return false; } + ASSERT_EQUAL( count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT ); return true; } SIMDJSON_POP_DISABLE_WARNINGS @@ -756,45 +724,39 @@ namespace parse_api_tests { bool parser_parse_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(BASIC_JSON); - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + UNUSED dom::array array = parser.parse(BASIC_JSON); return true; } bool parser_parse_many_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; int count = 0; - for (const element doc : parser.parse_many(BASIC_NDJSON)) { - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + for (UNUSED dom::array doc : parser.parse_many(BASIC_NDJSON)) { count++; } - if (count != 2) { cerr << "parse_many returned " << count << " documents, expected 2" << endl; return false; } + ASSERT_EQUAL(count, 2); return true; } bool parser_load_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - const element doc = parser.load(TWITTER_JSON); - if (!doc.is()) { cerr << "Document did not parse as an object" << endl; return false; } - size_t c = 0; - dom::object obj = doc.get().value(); // let us get the object - for (auto x : obj) { - c++; - (void) x; + size_t count = 0; + dom::object object = parser.load(TWITTER_JSON); + for (UNUSED auto field : object) { + count++; } - if(c != obj.size()) { cerr << "Mismatched size" << endl; return false; } + ASSERT_EQUAL( count, object.size() ); return true; } bool parser_load_many_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; int count = 0; - for (const element doc : parser.load_many(AMAZON_CELLPHONES_NDJSON)) { - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + for (UNUSED dom::array doc : parser.load_many(AMAZON_CELLPHONES_NDJSON)) { count++; } - if (count != 793) { cerr << "Expected 1 document, but load_many loaded " << count << " documents." << endl; return false; } + ASSERT_EQUAL( count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT ); return true; } #endif @@ -933,16 +895,17 @@ namespace dom_api_tests { string json(R"({ "a": 1, "b": 2, "c": 3 })"); const char* expected_key[] = { "a", "b", "c" }; uint64_t expected_value[] = { 1, 2, 3 }; - int i = 0; dom::parser parser; - auto [object, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.parse(json).get(object) ); + int i = 0; for (auto [key, value] : object) { - if (key != expected_key[i] || value.get().first != expected_value[i]) { cerr << "Expected " << expected_key[i] << " = " << expected_value[i] << ", got " << key << "=" << value << endl; return false; } + ASSERT_EQUAL( key, expected_key[i] ); + ASSERT_EQUAL( value.get().value(), expected_value[i] ); i++; } - if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; } + ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) ); return true; } @@ -950,16 +913,18 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ 1, 10, 100 ])"); uint64_t expected_value[] = { 1, 10, 100 }; - int i=0; dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + int i=0; for (auto value : array) { - if (value.get().first != expected_value[i]) { cerr << "Expected " << expected_value[i] << ", got " << value << endl; return false; } + uint64_t v; + ASSERT_SUCCESS( value.get(v) ); + ASSERT_EQUAL( v, expected_value[i] ); i++; } - if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; } + ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) ); return true; } @@ -969,13 +934,13 @@ namespace dom_api_tests { int i = 0; dom::parser parser; - auto [object, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - for (auto [key, value] : object) { - cout << "Unexpected " << key << " = " << value << endl; + dom::object object; + ASSERT_SUCCESS( parser.parse(json).get(object) ); + for (UNUSED auto field : object) { + TEST_FAIL("Unexpected field"); i++; } - if (i > 0) { cout << "Expected 0 values, got " << i << endl; return false; } + ASSERT_EQUAL(i, 0); return true; } @@ -985,13 +950,13 @@ namespace dom_api_tests { int i=0; dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - for (auto value : array) { - cout << "Unexpected value " << value << endl; + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + for (UNUSED auto value : array) { + TEST_FAIL("Unexpected value"); i++; } - if (i > 0) { cout << "Expected 0 values, got " << i << endl; return false; } + ASSERT_EQUAL(i, 0); return true; } @@ -999,13 +964,18 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ "hi", "has backslash\\" ])"); dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - auto val = array.begin(); + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + + auto iter = array.begin(); + std::string_view val; + ASSERT_SUCCESS( (*iter).get(val) ); + ASSERT_EQUAL( val, "hi" ); + + ++iter; + ASSERT_SUCCESS( (*iter).get(val) ); + ASSERT_EQUAL( val, "has backslash\\" ); - if ((*val).get().first != "hi") { cerr << "Expected value to be \"hi\", was " << (*val).get().first << endl; return false; } - ++val; - if ((*val).get().first != "has backslash\\") { cerr << "Expected string_view(\"has backslash\\\\\") to be \"has backslash\\\", was " << (*val).get().first << endl; return false; } return true; } @@ -1013,22 +983,22 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ 0, 1, -1, 1.1 ])"); dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - auto val = array.begin(); + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); - if ((*val).get().first != 0) { cerr << "Expected uint64_t(0) to be 0, was " << (*val) << endl; return false; } - if ((*val).get().first != 0) { cerr << "Expected int64_t(0) to be 0, was " << (*val).get().first << endl; return false; } - if ((*val).get().first != 0) { cerr << "Expected double(0) to be 0, was " << (*val).get().first << endl; return false; } - ++val; - if ((*val).get().first != 1) { cerr << "Expected uint64_t(1) to be 1, was " << (*val) << endl; return false; } - if ((*val).get().first != 1) { cerr << "Expected int64_t(1) to be 1, was " << (*val).get().first << endl; return false; } - if ((*val).get().first != 1) { cerr << "Expected double(1) to be 1, was " << (*val).get().first << endl; return false; } - ++val; - if ((*val).get().first != -1) { cerr << "Expected int64_t(-1) to be -1, was " << (*val).get().first << endl; return false; } - if ((*val).get().first != -1) { cerr << "Expected double(-1) to be -1, was " << (*val).get().first << endl; return false; } - ++val; - if ((*val).get().first != 1.1) { cerr << "Expected double(1.1) to be 1.1, was " << (*val).get().first << endl; return false; } + auto iter = array.begin(); + ASSERT_EQUAL( (*iter).get().value(), 0 ); + ASSERT_EQUAL( (*iter).get().value(), 0 ); + ASSERT_EQUAL( (*iter).get().value(), 0 ); + ++iter; + ASSERT_EQUAL( (*iter).get().value(), 1 ); + ASSERT_EQUAL( (*iter).get().value(), 1 ); + ASSERT_EQUAL( (*iter).get().value(), 1 ); + ++iter; + ASSERT_EQUAL( (*iter).get().value(), -1 ); + ASSERT_EQUAL( (*iter).get().value(), -1 ); + ++iter; + ASSERT_EQUAL( (*iter).get().value(), 1.1 ); return true; } @@ -1036,13 +1006,13 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ true, false ])"); dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - auto val = array.begin(); + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); - if ((*val).get().first != true) { cerr << "Expected bool(true) to be true, was " << (*val) << endl; return false; } + auto val = array.begin(); + ASSERT_EQUAL( (*val).get().first, true ); ++val; - if ((*val).get().first != false) { cerr << "Expected bool(false) to be false, was " << (*val) << endl; return false; } + ASSERT_EQUAL( (*val).get().first, false ); return true; } @@ -1050,10 +1020,11 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ null ])"); dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + auto val = array.begin(); - if (!(*val).is_null()) { cerr << "Expected null to be null!" << endl; return false; } + ASSERT_EQUAL( !(*val).is_null(), 0 ); return true; } @@ -1061,27 +1032,29 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"({ "a": 1, "b": 2, "c/d": 3})"); dom::parser parser; - auto [doc, error] = parser.parse(json); - if (doc["a"].get().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; } - if (doc["b"].get().first != 2) { cerr << "Expected uint64_t(doc[\"b\"]) to be 2, was " << doc["b"].first << endl; return false; } - if (doc["c/d"].get().first != 3) { cerr << "Expected uint64_t(doc[\"c/d\"]) to be 3, was " << doc["c"].first << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.parse(json).get(object) ); + ASSERT_EQUAL( object["a"].get().first, 1 ); + ASSERT_EQUAL( object["b"].get().first, 2 ); + ASSERT_EQUAL( object["c/d"].get().first, 3 ); // Check all three again in backwards order, to ensure we can go backwards - if (doc["c/d"].get().first != 3) { cerr << "Expected uint64_t(doc[\"c/d\"]) to be 3, was " << doc["c"].first << endl; return false; } - if (doc["b"].get().first != 2) { cerr << "Expected uint64_t(doc[\"b\"]) to be 2, was " << doc["b"].first << endl; return false; } - if (doc["a"].get().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; } + ASSERT_EQUAL( object["c/d"].get().first, 3 ); + ASSERT_EQUAL( object["b"].get().first, 2 ); + ASSERT_EQUAL( object["a"].get().first, 1 ); + simdjson::error_code error; UNUSED element val; #ifndef _LIBCPP_VERSION // should work everywhere but with libc++, must include the header. - std::tie(val,error) = doc["d"]; - if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } - std::tie(std::ignore,error) = doc["d"]; - if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } + std::tie(val,error) = object["d"]; + ASSERT_ERROR( error, NO_SUCH_FIELD ); + std::tie(std::ignore,error) = object["d"]; + ASSERT_ERROR( error, NO_SUCH_FIELD ); #endif - // tie(val, error) = doc["d"]; fails with "no viable overloaded '='" on Apple clang version 11.0.0 tie(val, error) = doc["d"]; - doc["d"].tie(val, error); - if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } - if (doc["d"].get(val) != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } - if (doc["d"].error() != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } + // tie(val, error) = object["d"]; fails with "no viable overloaded '='" on Apple clang version 11.0.0 tie(val, error) = doc["d"]; + object["d"].tie(val, error); + ASSERT_ERROR( error, NO_SUCH_FIELD ); + ASSERT_ERROR( object["d"].get(val), NO_SUCH_FIELD ); + ASSERT_ERROR( object["d"].error(), NO_SUCH_FIELD ); return true; } @@ -1089,26 +1062,25 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"({ "obj": { "a": 1, "b": 2, "c/d": 3 } })"); dom::parser parser; - auto [doc, error] = parser.parse(json); - if (error) { cerr << "Error: " << error << endl; return false; } - if (doc["obj"]["a"].get().first != 1) { cerr << "Expected uint64_t(doc[\"obj\"][\"a\"]) to be 1, was " << doc["obj"]["a"].first << endl; return false; } + dom::element doc; + ASSERT_SUCCESS( parser.parse(json).get(doc) ); + ASSERT_EQUAL( doc["obj"]["a"].get().first, 1); object obj; - error = doc.get(obj); - if (error) { cerr << "Error: " << error << endl; return false; } - if (obj["obj"]["a"].get().first != 1) { cerr << "Expected uint64_t(doc[\"obj\"][\"a\"]) to be 1, was " << doc["obj"]["a"].first << endl; return false; } + ASSERT_SUCCESS( doc.get(obj) ); + ASSERT_EQUAL( obj["obj"]["a"].get().first, 1); - error = obj["obj"].get(obj); - if (obj["a"].get().first != 1) { cerr << "Expected uint64_t(obj[\"a\"]) to be 1, was " << obj["a"].first << endl; return false; } - if (obj["b"].get().first != 2) { cerr << "Expected uint64_t(obj[\"b\"]) to be 2, was " << obj["b"].first << endl; return false; } - if (obj["c/d"].get().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; } + ASSERT_SUCCESS( obj["obj"].get(obj) ); + ASSERT_EQUAL( obj["a"].get().first, 1 ); + ASSERT_EQUAL( obj["b"].get().first, 2 ); + ASSERT_EQUAL( obj["c/d"].get().first, 3 ); // Check all three again in backwards order, to ensure we can go backwards - if (obj["c/d"].get().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; } - if (obj["b"].get().first != 2) { cerr << "Expected uint64_t(obj[\"b\"]) to be 2, was " << obj["b"].first << endl; return false; } - if (obj["a"].get().first != 1) { cerr << "Expected uint64_t(obj[\"a\"]) to be 1, was " << obj["a"].first << endl; return false; } + ASSERT_EQUAL( obj["c/d"].get().first, 3 ); + ASSERT_EQUAL( obj["b"].get().first, 2 ); + ASSERT_EQUAL( obj["a"].get().first, 1 ); UNUSED element val; - if (doc["d"].get(val) != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(obj[\"d\"]), got " << error << endl; return false; } + ASSERT_ERROR( doc["d"].get(val), NO_SUCH_FIELD); return true; } @@ -1116,9 +1088,9 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; // Prints the number of results in twitter.json dom::parser parser; - auto [result_count, error] = parser.load(TWITTER_JSON)["search_metadata"]["count"].get(); - if (error) { cerr << "Error: " << error << endl; return false; } - if (result_count != 100) { cerr << "Expected twitter.json[metadata_count][count] = 100, got " << result_count << endl; return false; } + uint64_t result_count; + ASSERT_SUCCESS( parser.load(TWITTER_JSON)["search_metadata"]["count"].get(result_count) ); + ASSERT_EQUAL( result_count, 100 ); return true; } @@ -1128,20 +1100,19 @@ namespace dom_api_tests { set default_users; dom::parser parser; dom::array tweets; - auto error = parser.load(TWITTER_JSON)["statuses"].get(tweets); - if (error) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( parser.load(TWITTER_JSON)["statuses"].get(tweets) ); for (auto tweet : tweets) { object user; - if ((error = tweet["user"].get(user))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( tweet["user"].get(user) ); bool default_profile; - if ((error = user["default_profile"].get(default_profile))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( user["default_profile"].get(default_profile) ); if (default_profile) { std::string_view screen_name; - if ((error = user["screen_name"].get(screen_name))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( user["screen_name"].get(screen_name) ); default_users.insert(screen_name); } } - if (default_users.size() != 86) { cerr << "Expected twitter.json[statuses][user] to contain 86 default_profile users, got " << default_users.size() << endl; return false; } + ASSERT_EQUAL( default_users.size(), 86 ); return true; } @@ -1149,26 +1120,26 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; // Print image names and sizes set> image_sizes; + simdjson::error_code error; dom::parser parser; dom::array tweets; - auto error = parser.load(TWITTER_JSON)["statuses"].get(tweets); - if (error) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( parser.load(TWITTER_JSON)["statuses"].get(tweets) ); for (auto tweet : tweets) { dom::array media; if (not (error = tweet["entities"]["media"].get(media))) { for (auto image : media) { object sizes; - if ((error = image["sizes"].get(sizes))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( image["sizes"].get(sizes) ); for (auto size : sizes) { uint64_t width, height; - if ((error = size.value["w"].get(width))) { cerr << "Error: " << error << endl; return false; } - if ((error = size.value["h"].get(height))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( size.value["w"].get(width) ); + ASSERT_SUCCESS( size.value["h"].get(height) ); image_sizes.insert(make_pair(width, height)); } } } } - if (image_sizes.size() != 15) { cerr << "Expected twitter.json[statuses][entities][media][sizes] to contain 15 different sizes, got " << image_sizes.size() << endl; return false; } + ASSERT_EQUAL( image_sizes.size(), 15 ); return true; } @@ -1182,12 +1153,12 @@ namespace dom_api_tests { int i = 0; dom::parser parser; - element doc = parser.parse(json); - for (auto [key, value] : doc.get()) { - if (key != expected_key[i] || uint64_t(value) != expected_value[i]) { cerr << "Expected " << expected_key[i] << " = " << expected_value[i] << ", got " << key << "=" << uint64_t(value) << endl; return false; } + for (auto [key, value] : dom::object(parser.parse(json))) { + ASSERT_EQUAL( key, expected_key[i]); + ASSERT_EQUAL( uint64_t(value), expected_value[i] ); i++; } - if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; } + ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) ); return true; } @@ -1198,69 +1169,61 @@ namespace dom_api_tests { int i=0; dom::parser parser; - element doc = parser.parse(json); - for (uint64_t value : doc.get()) { - if (value != expected_value[i]) { cerr << "Expected " << expected_value[i] << ", got " << value << endl; return false; } + for (uint64_t value : parser.parse(json)) { + ASSERT_EQUAL( value, expected_value[i] ); i++; } - if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; } + ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) ); return true; } bool string_value_exception() { std::cout << "Running " << __func__ << std::endl; - string json(R"([ "hi", "has backslash\\" ])"); dom::parser parser; - auto val = parser.parse(json).get().begin(); - - if (strcmp((const char*)*val, "hi")) { cerr << "Expected const char*(\"hi\") to be \"hi\", was " << (const char*)*val << endl; return false; } - if (string_view(*val) != "hi") { cerr << "Expected string_view(\"hi\") to be \"hi\", was " << string_view(*val) << endl; return false; } - ++val; - if (strcmp((const char*)*val, "has backslash\\")) { cerr << "Expected const char*(\"has backslash\\\\\") to be \"has backslash\\\", was " << (const char*)*val << endl; return false; } - if (string_view(*val) != "has backslash\\") { cerr << "Expected string_view(\"has backslash\\\\\") to be \"has backslash\\\", was " << string_view(*val) << endl; return false; } + ASSERT_EQUAL( (const char *)parser.parse(R"("hi")"_padded), "hi" ); + ASSERT_EQUAL( string_view(parser.parse(R"("hi")"_padded)), "hi" ); + ASSERT_EQUAL( (const char *)parser.parse(R"("has backslash\\")"_padded), "has backslash\\"); + ASSERT_EQUAL( string_view(parser.parse(R"("has backslash\\")"_padded)), "has backslash\\" ); return true; } bool numeric_values_exception() { std::cout << "Running " << __func__ << std::endl; - string json(R"([ 0, 1, -1, 1.1 ])"); dom::parser parser; - auto val = parser.parse(json).get().begin(); - if (uint64_t(*val) != 0) { cerr << "Expected uint64_t(0) to be 0, was " << uint64_t(*val) << endl; return false; } - if (int64_t(*val) != 0) { cerr << "Expected int64_t(0) to be 0, was " << int64_t(*val) << endl; return false; } - if (double(*val) != 0) { cerr << "Expected double(0) to be 0, was " << double(*val) << endl; return false; } - ++val; - if (uint64_t(*val) != 1) { cerr << "Expected uint64_t(1) to be 1, was " << uint64_t(*val) << endl; return false; } - if (int64_t(*val) != 1) { cerr << "Expected int64_t(1) to be 1, was " << int64_t(*val) << endl; return false; } - if (double(*val) != 1) { cerr << "Expected double(1) to be 1, was " << double(*val) << endl; return false; } - ++val; - if (int64_t(*val) != -1) { cerr << "Expected int64_t(-1) to be -1, was " << int64_t(*val) << endl; return false; } - if (double(*val) != -1) { cerr << "Expected double(-1) to be -1, was " << double(*val) << endl; return false; } - ++val; - if (double(*val) != 1.1) { cerr << "Expected double(1.1) to be 1.1, was " << double(*val) << endl; return false; } + ASSERT_EQUAL( uint64_t(parser.parse("0"_padded)), 0); + ASSERT_EQUAL( int64_t(parser.parse("0"_padded)), 0); + ASSERT_EQUAL( double(parser.parse("0"_padded)), 0); + + ASSERT_EQUAL( uint64_t(parser.parse("1"_padded)), 1); + ASSERT_EQUAL( int64_t(parser.parse("1"_padded)), 1); + ASSERT_EQUAL( double(parser.parse("1"_padded)), 1); + + ASSERT_EQUAL( int64_t(parser.parse("-1"_padded)), -1); + ASSERT_EQUAL( double(parser.parse("-1"_padded)), -1); + + ASSERT_EQUAL( double(parser.parse("1.1"_padded)), 1.1); + return true; } bool boolean_values_exception() { std::cout << "Running " << __func__ << std::endl; - string json(R"([ true, false ])"); dom::parser parser; - auto val = parser.parse(json).get().begin(); - if (bool(*val) != true) { cerr << "Expected bool(true) to be true, was " << bool(*val) << endl; return false; } - ++val; - if (bool(*val) != false) { cerr << "Expected bool(false) to be false, was " << bool(*val) << endl; return false; } + ASSERT_EQUAL( bool(parser.parse("true"_padded)), true); + + ASSERT_EQUAL( bool(parser.parse("false"_padded)), false); + return true; } bool null_value_exception() { std::cout << "Running " << __func__ << std::endl; - string json(R"([ null ])"); dom::parser parser; - auto val = parser.parse(json).get().begin(); - if (!(*val).is_null()) { cerr << "Expected null to be null!" << endl; return false; } + ASSERT_EQUAL( bool(parser.parse("null"_padded).is_null()), true ); + return true; } @@ -1268,8 +1231,10 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"({ "a": 1, "b": 2, "c": 3})"); dom::parser parser; - element 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; } + auto obj = parser.parse(json); + + ASSERT_EQUAL(uint64_t(obj["a"]), 1); + return true; } @@ -1278,7 +1243,9 @@ namespace dom_api_tests { string json(R"({ "obj": { "a": 1, "b": 2, "c": 3 } })"); dom::parser parser; 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; } + + ASSERT_EQUAL( uint64_t(obj["a"]), 1); + return true; } @@ -1313,18 +1280,17 @@ namespace dom_api_tests { // Print image names and sizes set> image_sizes; dom::parser parser; - element doc = parser.load(TWITTER_JSON); - for (object tweet : doc["statuses"].get()) { - auto [media, not_found] = tweet["entities"]["media"]; - if (!not_found) { - for (object image : media.get()) { - for (auto size : image["sizes"].get()) { + for (object tweet : parser.load(TWITTER_JSON)["statuses"]) { + auto media = tweet["entities"]["media"]; + if (!media.error()) { + for (object image : media) { + for (auto size : object(image["sizes"])) { image_sizes.insert(make_pair(size.value["w"], size.value["h"])); } } } } - if (image_sizes.size() != 15) { cerr << "Expected twitter.json[statuses][entities][media][sizes] to contain 15 different sizes, got " << image_sizes.size() << endl; return false; } + ASSERT_EQUAL( image_sizes.size(), 15 ); return true; } @@ -1721,21 +1687,10 @@ namespace minify_tests { return false; } size_t newlength{}; - auto error = simdjson::minify(input, length, buffer.get(), newlength); - if(error != simdjson::SUCCESS) { - std::cerr << "error " << error << std::endl; - return false; - } - // memcmp - if(newlength != expected_length) { - std::cerr << "lengths do not match " << std::endl; - return false; - } + ASSERT_SUCCESS( simdjson::minify(input, length, buffer.get(), newlength) ); + ASSERT_EQUAL( newlength, expected_length); for(size_t i = 0; i < newlength; i++) { - if(buffer.get()[i] != expected[i]) { - std::cerr << "Inputs do not match (but same length) " << std::endl; - return false; - } + ASSERT_EQUAL( buffer.get()[i], expected[i]); } return true; } @@ -1785,8 +1740,8 @@ namespace format_tests { bool print_parser_parse() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [doc, error] = parser.parse(DOCUMENT); - if (error) { cerr << error << endl; return false; } + dom::element doc; + ASSERT_SUCCESS( parser.parse(DOCUMENT).get(doc) ); ostringstream s; s << doc; return assert_minified(s); @@ -1794,8 +1749,8 @@ namespace format_tests { bool print_minify_parser_parse() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [doc, error] = parser.parse(DOCUMENT); - if (error) { cerr << error << endl; return false; } + dom::element doc; + ASSERT_SUCCESS( parser.parse(DOCUMENT).get(doc) ); ostringstream s; s << minify(doc); return assert_minified(s); @@ -1804,8 +1759,8 @@ namespace format_tests { bool print_element() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["foo"]; - if (error) { cerr << error << endl; return false; } + dom::element value; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["foo"].get(value) ); ostringstream s; s << value; return assert_minified(s, "1"); @@ -1813,8 +1768,8 @@ namespace format_tests { bool print_minify_element() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["foo"]; - if (error) { cerr << error << endl; return false; } + dom::element value; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["foo"].get(value) ); ostringstream s; s << minify(value); return assert_minified(s, "1"); @@ -1823,38 +1778,38 @@ namespace format_tests { bool print_array() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["bar"].get(); - if (error) { cerr << error << endl; return false; } + dom::array array; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["bar"].get(array) ); ostringstream s; - s << value; + s << array; return assert_minified(s, "[1,2,3]"); } bool print_minify_array() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["bar"].get(); - if (error) { cerr << error << endl; return false; } + dom::array array; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["bar"].get(array) ); ostringstream s; - s << minify(value); + s << minify(array); return assert_minified(s, "[1,2,3]"); } bool print_object() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["baz"].get(); - if (error) { cerr << error << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["baz"].get(object) ); ostringstream s; - s << value; + s << object; return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } bool print_minify_object() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["baz"].get(); - if (error) { cerr << error << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["baz"].get(object) ); ostringstream s; - s << minify(value); + s << minify(object); return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } @@ -1878,25 +1833,22 @@ namespace format_tests { bool print_element_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << doc["foo"]; + s << parser.parse(DOCUMENT)["foo"]; return assert_minified(s, "1"); } bool print_minify_element_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << minify(doc["foo"]); + s << minify(parser.parse(DOCUMENT)["foo"]); return assert_minified(s, "1"); } bool print_element_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); - element value = doc["foo"]; + element value = parser.parse(DOCUMENT)["foo"]; ostringstream s; s << value; return assert_minified(s, "1"); @@ -1904,8 +1856,7 @@ namespace format_tests { bool print_minify_element_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); - element value = doc["foo"]; + element value = parser.parse(DOCUMENT)["foo"]; ostringstream s; s << minify(value); return assert_minified(s, "1"); @@ -1914,66 +1865,64 @@ namespace format_tests { bool print_array_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << doc["bar"].get(); + s << parser.parse(DOCUMENT)["bar"].get(); return assert_minified(s, "[1,2,3]"); } bool print_minify_array_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << minify(doc["bar"].get()); + s << minify(parser.parse(DOCUMENT)["bar"].get()); return assert_minified(s, "[1,2,3]"); } bool print_object_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << doc["baz"].get(); + s << parser.parse(DOCUMENT)["baz"].get(); return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } bool print_minify_object_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << minify(doc["baz"].get()); + s << minify(parser.parse(DOCUMENT)["baz"].get()); return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } bool print_array_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; + dom::array array = parser.parse(DOCUMENT)["bar"]; ostringstream s; - s << parser.parse(DOCUMENT)["bar"]; + s << array; return assert_minified(s, "[1,2,3]"); } bool print_minify_array_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; + dom::array array = parser.parse(DOCUMENT)["bar"]; ostringstream s; - s << minify(parser.parse(DOCUMENT)["bar"]); + s << minify(array); return assert_minified(s, "[1,2,3]"); } bool print_object_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; + dom::object object = parser.parse(DOCUMENT)["baz"]; ostringstream s; - s << parser.parse(DOCUMENT)["baz"]; + s << object; return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } bool print_minify_object_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); - object value = doc["baz"]; + dom::object object = parser.parse(DOCUMENT)["baz"]; ostringstream s; - s << minify(value); + s << minify(object); return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } #endif // SIMDJSON_EXCEPTIONS diff --git a/tests/errortests.cpp b/tests/errortests.cpp index 3be94fcd0..f2050d5af 100644 --- a/tests/errortests.cpp +++ b/tests/errortests.cpp @@ -46,15 +46,16 @@ namespace parser_load { ASSERT_SUCCESS(parser.parse_many(DOC).get(docs)); for (auto doc : docs) { count++; - auto [val, error] = doc.get(); + uint64_t val; + auto error = doc.get(val); if (count == 3) { ASSERT_ERROR(error, TAPE_ERROR); } else { - if (error) { TEST_FAIL(error); } - if (val != count) { cerr << "FAIL: expected " << count << ", got " << val << endl; return false; } + ASSERT_SUCCESS(error); + ASSERT_EQUAL(val, count); } } - if (count != 3) { cerr << "FAIL: expected 2 documents and 1 error, got " << count << " total things" << endl; return false; } + ASSERT_EQUAL(count, 3); TEST_SUCCEED(); } @@ -69,7 +70,7 @@ namespace parser_load { count++; ASSERT_ERROR(doc.error(), TAPE_ERROR); } - if (count != 1) { cerr << "FAIL: expected no documents and 1 error, got " << count << " total things" << endl; return false; } + ASSERT_EQUAL(count, 1); TEST_SUCCEED(); } @@ -82,36 +83,34 @@ namespace parser_load { ASSERT_SUCCESS(parser.parse_many(DOC).get(docs)); for (auto doc : docs) { count++; - auto [val, error] = doc.get(); + uint64_t val; + auto error = doc.get(val); if (count == 3) { ASSERT_ERROR(error, TAPE_ERROR); } else { - if (error) { TEST_FAIL(error); } - if (val != count) { cerr << "FAIL: expected " << count << ", got " << val << endl; return false; } + ASSERT_SUCCESS(error); + ASSERT_EQUAL(val, count); } } - if (count != 3) { cerr << "FAIL: expected 2 documents and 1 error, got " << count << " total things" << endl; return false; } + ASSERT_EQUAL(count, 3); TEST_SUCCEED(); } bool parser_load_nonexistent() { TEST_START(); dom::parser parser; - auto error = parser.load(NONEXISTENT_FILE).error(); - ASSERT_ERROR(error, IO_ERROR); + ASSERT_ERROR( parser.load(NONEXISTENT_FILE).error(), IO_ERROR ); TEST_SUCCEED(); } bool parser_load_many_nonexistent() { TEST_START(); dom::parser parser; - dom::document_stream stream; - ASSERT_ERROR(parser.load_many(NONEXISTENT_FILE).get(stream), IO_ERROR); + ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).error(), IO_ERROR ); TEST_SUCCEED(); } bool padded_string_load_nonexistent() { TEST_START(); - auto error = padded_string::load(NONEXISTENT_FILE).error(); - ASSERT_ERROR(error, IO_ERROR); + ASSERT_ERROR(padded_string::load(NONEXISTENT_FILE).error(), IO_ERROR); TEST_SUCCEED(); } @@ -119,16 +118,17 @@ namespace parser_load { TEST_START(); dom::parser parser; UNUSED uint64_t foo; - ASSERT_ERROR( parser.load(NONEXISTENT_FILE)["foo"].get(foo) , IO_ERROR); + ASSERT_ERROR( parser.load(NONEXISTENT_FILE)["foo"].get(foo), IO_ERROR); TEST_SUCCEED(); } bool parser_load_many_chain() { TEST_START(); dom::parser parser; - dom::document_stream stream; - ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).get(stream) , IO_ERROR ); + UNUSED dom::document_stream stream; + ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).get(stream), IO_ERROR ); TEST_SUCCEED(); } + bool run() { return true && parser_load_capacity() diff --git a/tests/integer_tests.cpp b/tests/integer_tests.cpp index c072ac05f..c35d717c8 100644 --- a/tests/integer_tests.cpp +++ b/tests/integer_tests.cpp @@ -3,6 +3,7 @@ #include #include "simdjson.h" +#include "test_macros.h" // we define our own asserts to get around NDEBUG #ifndef ASSERT @@ -29,44 +30,43 @@ template static const std::string make_json(T value) { } template -static void parse_and_validate(const std::string src, T expected) { +static bool parse_and_validate(const std::string src, T expected) { std::cout << "src: " << src << ", "; const padded_string pstr{src}; simdjson::dom::parser parser; - bool result; if constexpr (std::is_same::value) { - auto [actual, error] = parser.parse(pstr).get()["key"].get(); - if (error) { std::cerr << error << std::endl; abort(); } - result = (expected == actual); + int64_t actual; + ASSERT_SUCCESS( parser.parse(pstr)["key"].get(actual) ); + std::cout << std::boolalpha << "test: " << (expected == actual) << std::endl; + ASSERT_EQUAL( expected, actual ); } else { - auto [actual, error] = parser.parse(pstr).get()["key"].get(); - if (error) { std::cerr << error << std::endl; abort(); } - result = (expected == actual); - } - std::cout << std::boolalpha << "test: " << result << std::endl; - if(!result) { - std::cerr << "bug detected" << std::endl; - exit(EXIT_FAILURE); + uint64_t actual; + ASSERT_SUCCESS( parser.parse(pstr)["key"].get(actual) ); + std::cout << std::boolalpha << "test: " << (expected == actual) << std::endl; + ASSERT_EQUAL( expected, actual ); } + return true; } static bool parse_and_check_signed(const std::string src) { std::cout << "src: " << src << ", expecting signed" << std::endl; const padded_string pstr{src}; simdjson::dom::parser parser; - auto [value, error] = parser.parse(pstr).get()["key"]; - if (error) { std::cerr << error << std::endl; abort(); } - return value.is(); + simdjson::dom::element value; + ASSERT_SUCCESS( parser.parse(pstr).get()["key"].get(value) ); + ASSERT_EQUAL( value.is(), true ); + return true; } static bool parse_and_check_unsigned(const std::string src) { std::cout << "src: " << src << ", expecting signed" << std::endl; const padded_string pstr{src}; simdjson::dom::parser parser; - auto [value, error] = parser.parse(pstr).get()["key"]; - if (error) { std::cerr << error << std::endl; abort(); } - return value.is(); + simdjson::dom::element value; + ASSERT_SUCCESS( parser.parse(pstr).get()["key"].get(value) ); + ASSERT_EQUAL( value.is(), true ); + return true; } int main() { @@ -75,21 +75,21 @@ int main() { constexpr auto int64_min = numeric_limits::lowest(); constexpr auto uint64_max = numeric_limits::max(); constexpr auto uint64_min = numeric_limits::lowest(); - parse_and_validate(make_json(int64_max), int64_max); - parse_and_validate(make_json(int64_min), int64_min); - parse_and_validate(make_json(uint64_max), uint64_max); - parse_and_validate(make_json(uint64_min), uint64_min); constexpr auto int64_max_plus1 = static_cast(int64_max) + 1; - parse_and_validate(make_json(int64_max_plus1), int64_max_plus1); - if(!parse_and_check_signed(make_json(int64_max))) { - std::cerr << "bug: large signed integers should be represented as signed integers" << std::endl; - return EXIT_FAILURE; + if (true + && parse_and_validate(make_json(int64_max), int64_max) + && parse_and_validate(make_json(uint64_max), uint64_max) + && parse_and_validate(make_json(uint64_min), uint64_min) + && parse_and_validate(make_json(int64_min), int64_min) + && parse_and_validate(make_json(uint64_max), uint64_max) + && parse_and_validate(make_json(uint64_min), uint64_min) + && parse_and_validate(make_json(int64_max_plus1), int64_max_plus1) + && parse_and_check_signed(make_json(int64_max)) + && parse_and_check_unsigned(make_json(uint64_max)) + ) { + std::cout << "All ok." << std::endl; + return EXIT_SUCCESS; } - if(!parse_and_check_unsigned(make_json(uint64_max))) { - std::cerr << "bug: a large unsigned integers is not represented as an unsigned integer" << std::endl; - return EXIT_FAILURE; - } - std::cout << "All ok." << std::endl; - return EXIT_SUCCESS; + return EXIT_FAILURE; } diff --git a/tests/pointercheck.cpp b/tests/pointercheck.cpp index 58e67ce3e..e0517edb5 100644 --- a/tests/pointercheck.cpp +++ b/tests/pointercheck.cpp @@ -1,6 +1,7 @@ #include #include "simdjson.h" +#include "test_macros.h" // we define our own asserts to get around NDEBUG #ifndef ASSERT @@ -35,49 +36,46 @@ const padded_string TEST_JSON = R"( bool json_pointer_success_test(const char *json_pointer, std::string_view expected_value) { std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl; dom::parser parser; - auto [value, error] = parser.parse(TEST_JSON).at(json_pointer).get(); - if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; } - ASSERT(value == expected_value); + std::string_view value; + ASSERT_SUCCESS( parser.parse(TEST_JSON).at(json_pointer).get(value) ); + ASSERT_EQUAL(value, expected_value); return true; } bool json_pointer_success_test(const char *json_pointer) { std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl; dom::parser parser; - auto error = parser.parse(TEST_JSON).at(json_pointer).error(); - if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; } + ASSERT_SUCCESS( parser.parse(TEST_JSON).at(json_pointer).error() ); return true; } -bool json_pointer_failure_test(const char *json_pointer, error_code expected_failure_test) { +bool json_pointer_failure_test(const char *json_pointer, error_code expected_error) { std::cout << "Running invalid JSON pointer test '" << json_pointer << "' ..." << std::endl; dom::parser parser; - auto error = parser.parse(TEST_JSON).at(json_pointer).error(); - ASSERT(error == expected_failure_test); + ASSERT_ERROR(parser.parse(TEST_JSON).at(json_pointer).error(), expected_error); return true; } int main() { - if ( - json_pointer_success_test("") && - json_pointer_success_test("~1~001abc") && - json_pointer_success_test("~1~001abc/1") && - json_pointer_success_test("~1~001abc/1/\\\" 0") && - json_pointer_success_test("~1~001abc/1/\\\" 0/0", "value0") && - json_pointer_success_test("~1~001abc/1/\\\" 0/1", "value1") && - json_pointer_failure_test("~1~001abc/1/\\\" 0/2", INDEX_OUT_OF_BOUNDS) && // index actually out of bounds - json_pointer_success_test("arr") && // get array - json_pointer_failure_test("arr/0", INDEX_OUT_OF_BOUNDS) && // array index 0 out of bounds on empty array - json_pointer_success_test("~1~001abc") && // get object - json_pointer_success_test("0", "0 ok") && // object index with integer-ish key - json_pointer_success_test("01", "01 ok") && // object index with key that would be an invalid integer - json_pointer_success_test("", "empty ok") && // object index with empty key - json_pointer_failure_test("~01abc", NO_SUCH_FIELD) && // Test that we don't try to compare the literal key - json_pointer_failure_test("~1~001abc/01", INVALID_JSON_POINTER) && // Leading 0 in integer index - json_pointer_failure_test("~1~001abc/", INVALID_JSON_POINTER) && // Empty index to array - json_pointer_failure_test("~1~001abc/-", INDEX_OUT_OF_BOUNDS) && // End index is always out of bounds - true + if (true + && json_pointer_success_test("") + && json_pointer_success_test("~1~001abc") + && json_pointer_success_test("~1~001abc/1") + && json_pointer_success_test("~1~001abc/1/\\\" 0") + && json_pointer_success_test("~1~001abc/1/\\\" 0/0", "value0") + && json_pointer_success_test("~1~001abc/1/\\\" 0/1", "value1") + && json_pointer_failure_test("~1~001abc/1/\\\" 0/2", INDEX_OUT_OF_BOUNDS) // index actually out of bounds + && json_pointer_success_test("arr") // get array + && json_pointer_failure_test("arr/0", INDEX_OUT_OF_BOUNDS) // array index 0 out of bounds on empty array + && json_pointer_success_test("~1~001abc") // get object + && json_pointer_success_test("0", "0 ok") // object index with integer-ish key + && json_pointer_success_test("01", "01 ok") // object index with key that would be an invalid integer + && json_pointer_success_test("", "empty ok") // object index with empty key + && json_pointer_failure_test("~01abc", NO_SUCH_FIELD) // Test that we don't try to compare the literal key + && json_pointer_failure_test("~1~001abc/01", INVALID_JSON_POINTER) // Leading 0 in integer index + && json_pointer_failure_test("~1~001abc/", INVALID_JSON_POINTER) // Empty index to array + && json_pointer_failure_test("~1~001abc/-", INDEX_OUT_OF_BOUNDS) // End index is always out of bounds ) { std::cout << "Success!" << std::endl; return 0; diff --git a/tests/readme_examples.cpp b/tests/readme_examples.cpp index c8712197f..1242f3ce5 100644 --- a/tests/readme_examples.cpp +++ b/tests/readme_examples.cpp @@ -88,7 +88,7 @@ void basics_dom_4() { auto abstract_json = R"( { "str" : { "123" : {"abc" : 3.14 } } } )"_padded; dom::parser parser; - double v = parser.parse(abstract_json)["str"]["123"]["abc"].get(); + double v = parser.parse(abstract_json)["str"]["123"]["abc"]; cout << "number: " << v << endl; } @@ -141,9 +141,10 @@ namespace treewalk_1 { #ifdef SIMDJSON_CPLUSPLUS17 void basics_cpp17_1() { - dom::parser parser; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; - auto [object, error] = parser.parse(json).get(); + dom::parser parser; + dom::object object; + auto error = parser.parse(json).get(object); if (error) { cerr << error << endl; return; } for (auto [key, value] : object) { cout << key << " = " << value << endl; @@ -153,11 +154,10 @@ void basics_cpp17_1() { void basics_cpp17_2() { // C++ 11 version for comparison - dom::parser parser; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; - simdjson::error_code error; + dom::parser parser; dom::object object; - error = parser.parse(json).get(object); + auto error = parser.parse(json).get(object); if (!error) { cerr << error << endl; return; } for (dom::key_value_pair field : object) { cout << field.key << " = " << field.value << endl; diff --git a/tests/test_macros.h b/tests/test_macros.h index 35228ca24..a44855534 100644 --- a/tests/test_macros.h +++ b/tests/test_macros.h @@ -18,17 +18,25 @@ const char *SMALLDEMO_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "smalldemo.json"; const char *TRUENULL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "truenull.json"; // For the ASSERT_EQUAL macro -template -bool equals_expected(T actual, T expected) { - return actual == expected; +template +bool equals_expected(T actual, S expected) { + return actual == T(expected); } template<> -bool equals_expected(const char *actual, const char *expected) { +bool equals_expected(const char *actual, const char *expected) { return !strcmp(actual, expected); } #define TEST_START() { cout << "Running " << __func__ << " ..." << endl; } -#define ASSERT_EQUAL(ACTUAL, EXPECTED) do { auto _actual = (ACTUAL); auto _expected = (EXPECTED); if (!equals_expected(_actual, _expected)) { std::cerr << "Expected " << #ACTUAL << " to be " << _expected << ", got " << _actual << " instead!" << std::endl; return false; } } while(0); +#define ASSERT_EQUAL(ACTUAL, EXPECTED) \ +do { \ + auto _actual = (ACTUAL); \ + auto _expected = (EXPECTED); \ + if (!equals_expected(_actual, _expected)) { \ + std::cerr << "Expected " << (#ACTUAL) << " to be " << _expected << ", got " << _actual << " instead!" << std::endl; \ + return false; \ + } \ +} while(0); #define ASSERT_ERROR(ACTUAL, EXPECTED) do { auto _actual = (ACTUAL); auto _expected = (EXPECTED); if (_actual != _expected) { std::cerr << "FAIL: Unexpected error \"" << _actual << "\" (expected \"" << _expected << "\")" << std::endl; return false; } } while (0); #define ASSERT(RESULT, MESSAGE) if (!(RESULT)) { std::cerr << MESSAGE << std::endl; return false; } #define RUN_TEST(RESULT) if (!RESULT) { return false; }