From 4becf38222e4dae57ef2aaf79c86633fce2f1b14 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Fri, 2 Dec 2022 08:46:22 +0800 Subject: [PATCH 01/34] add get --- iguana/error_code.h | 51 ++++++++++++++++++++++++++++++++++++++++++++- iguana/value.hpp | 23 ++++++++++++++++++++ test/test.cpp | 11 ++++++++-- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/iguana/error_code.h b/iguana/error_code.h index ed69e254..2565bf29 100644 --- a/iguana/error_code.h +++ b/iguana/error_code.h @@ -9,7 +9,7 @@ namespace iguana { class iguana_category : public std::error_category { public: virtual const char *name() const noexcept override { - return "iguna::category"; + return "iguana::category"; } virtual std::string message(int err_val) const override { for (auto &pair : err_map_) { @@ -46,4 +46,53 @@ inline std::error_code make_error_code(const std::string data = "") { auto err = iguana::category().add_message(data); return std::error_code(err, iguana::category()); } + +// dom parse error code +enum class dom_errc { + ok = 0, + wrong_type, +}; + +class iguana_dom_category : public std::error_category { +public: + virtual const char *name() const noexcept override { + return "iguana::dom_category"; + } + virtual std::string message(int err_val) const override { + switch (static_cast(err_val)) { + case dom_errc::ok: + return "ok"; + case dom_errc::wrong_type: { + auto it = detail_msg_map_.find(dom_errc::wrong_type); + if (it != detail_msg_map_.end()) { + return std::string("wrong type, ") + .append("real type is ") + .append(it->second); + } else { + return "wrong type"; + } + } + default: + return "(unrecognized error)"; + } + } + + // private: + std::map detail_msg_map_; +}; + +iguana::iguana_dom_category &dom_category() { + static iguana::iguana_dom_category instance; + return instance; +} + +inline std::error_code make_error_code(iguana::dom_errc err, + const std::string &error_msg) { + auto &instance = iguana::dom_category(); + if (!error_msg.empty()) { + instance.detail_msg_map_.emplace(err, error_msg); + } + + return std::error_code((int)err, instance); +} } // namespace iguana diff --git a/iguana/value.hpp b/iguana/value.hpp index 62fe9a25..723cb625 100644 --- a/iguana/value.hpp +++ b/iguana/value.hpp @@ -19,6 +19,8 @@ template using json_map = std::unordered_map; #endif +enum dom_parse_error { ok, wrong_type }; + template struct basic_json_value : std::variant< @@ -34,6 +36,11 @@ struct basic_json_value using base_type::base_type; + inline const static std::unordered_map type_map_ = { + {0, "undefined type"}, {1, "null type"}, {2, "bool type"}, + {3, "double type"}, {4, "int type"}, {5, "string type"}, + {6, "array type"}, {7, "object type"}}; + basic_json_value() : base_type(std::in_place_type) {} basic_json_value(CharT const *value) @@ -89,6 +96,22 @@ struct basic_json_value *ok = false; return {}; } + + template std::pair get() { + std::error_code ec{}; + try { + return std::make_pair(ec, std::get(*this)); + } catch (std::exception &e) { + auto it = type_map_.find(this->index()); + if (it == type_map_.end()) { + ec = iguana::make_error_code(iguana::dom_errc::wrong_type, + "undefined type"); + } else { + ec = iguana::make_error_code(iguana::dom_errc::wrong_type, it->second); + } + return std::make_pair(ec, T{}); + } + } }; template diff --git a/test/test.cpp b/test/test.cpp index c67e5aec..534765de 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -144,13 +144,20 @@ TEST_CASE("test dom parse") { std::string_view str = R"(null)"; iguana::jvalue val; iguana::parse(val, str.begin(), str.end()); - CHECK(std::get(val) == std::nullptr_t{}); + auto pair = val.get(); + if (pair.first) { + CHECK(pair.first.message() == "wrong type, real type is null type"); + } + CHECK(val.get().second == std::nullptr_t{}); } { std::string_view str = R"(false)"; iguana::jvalue val; iguana::parse(val, str.begin(), str.end()); - CHECK(std::get(val) == false); + + auto pair = val.get(); + CHECK(!pair.first); + CHECK(pair.second == false); } { std::string_view str = R"({"name": "tom", "ok":true, "t": {"val":2.5}})"; From 1592ff4b1b516c4bd778e1c2cf56228b8b0db461 Mon Sep 17 00:00:00 2001 From: sandyhsia Date: Sat, 3 Dec 2022 01:51:13 +0800 Subject: [PATCH 02/34] add to helpers. --- iguana/value.hpp | 91 ++++++++++++++++++++++++++++-------------------- test/test.cpp | 41 ++++++++++++++++++++-- 2 files changed, 92 insertions(+), 40 deletions(-) diff --git a/iguana/value.hpp b/iguana/value.hpp index 723cb625..81ea9595 100644 --- a/iguana/value.hpp +++ b/iguana/value.hpp @@ -61,43 +61,8 @@ struct basic_json_value bool is_array() const { return std::holds_alternative(*this); } bool is_object() const { return std::holds_alternative(*this); } - array_type to_array() const { - if (is_array()) - return std::get(*this); - return {}; - } - - object_type to_object() const { - if (is_object()) - return std::get(*this); - return {}; - } - - double to_double(bool *ok = nullptr) const { - if (ok) - *ok = true; - if (is_double()) - return std::get(*this); - if (is_int()) - return static_cast(std::get(*this)); - if (ok) - *ok = false; - return {}; - } - - double to_int(bool *ok = nullptr) const { - if (ok) - *ok = true; - if (is_double()) - return static_cast(std::get(*this)); - if (is_int()) - return std::get(*this); - if (ok) - *ok = false; - return {}; - } - - template std::pair get() { + template + std::pair get() const { std::error_code ec{}; try { return std::make_pair(ec, std::get(*this)); @@ -112,6 +77,58 @@ struct basic_json_value return std::make_pair(ec, T{}); } } + + template + std::error_code get_to(T &v) const { + auto [ec, val] = get(); + if (ec.value() == 0) + v = val; + return ec; + } + + template + T _get_to_may_throw() const { + auto [ec, v] = get(); + if (ec.value()) + throw(ec); + return v; + } + + template + T _get_to_no_throw(std::error_code &ec) const { + auto [code, v] = get(); + if (code.value()) + ec = code; + return v; + } + + object_type to_object() const { return _get_to_may_throw(); } + object_type to_object(std::error_code &ec) const { + return _get_to_no_throw(ec); + } + + array_type to_array() const { return _get_to_may_throw(); } + array_type to_array(std::error_code &ec) const { + return _get_to_no_throw(ec); + } + + double to_double() const { return _get_to_may_throw(); } + double to_double(std::error_code &ec) const { + return _get_to_no_throw(ec); + } + + int to_int() const { return _get_to_may_throw(); } + int to_int(std::error_code &ec) const { return _get_to_no_throw(ec); } + + bool to_bool() const { return _get_to_may_throw(); } + bool to_bool(std::error_code &ec) const { return _get_to_no_throw(ec); } + + std::basic_string to_string() const { + return _get_to_may_throw>(); + } + std::basic_string to_string(std::error_code &ec) const { + return _get_to_no_throw>(ec); + } }; template diff --git a/test/test.cpp b/test/test.cpp index 534765de..d0997923 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -139,6 +139,16 @@ struct test_double_t { }; REFLECTION(test_double_t, val); +template +void get_value_test_helper(const std::string &json_str, const T &expect) { + iguana::jvalue jv; + CHECK_NOTHROW(iguana::parse(jv, json_str.begin(), json_str.end())); + CHECK_NOTHROW(jv.get()); + T actual{}; + CHECK_NOTHROW(jv.get_to(actual)); + CHECK(actual == expect); +} + TEST_CASE("test dom parse") { { std::string_view str = R"(null)"; @@ -200,7 +210,10 @@ TEST_CASE("test dom parse") { const iguana::jarray &arr1 = val1.to_array(); CHECK(arr1.size() == 3); CHECK(arr1[0].to_double() == 0.5); - CHECK(val1.to_object().size() == 0); + + std::error_code ec; + CHECK_NOTHROW(val1.to_object(ec)); + CHECK_THROWS(val1.to_object()); } { std::string json_str = R"(709)"; @@ -209,6 +222,9 @@ TEST_CASE("test dom parse") { auto &num = std::get(val1); CHECK(num == 709); CHECK_THROWS(std::get(val1)); + + int expect = 709; + get_value_test_helper(json_str, 709); } { std::string json_str = R"(-0.111)"; @@ -224,12 +240,18 @@ TEST_CASE("test dom parse") { iguana::jvalue val1; iguana::parse(val1, json_str.begin(), json_str.end()); CHECK(val1.is_bool()); + + bool expect = true; + get_value_test_helper(json_str, expect); } { std::string json_str = R"("true")"; iguana::jvalue val1; iguana::parse(val1, json_str.begin(), json_str.end()); CHECK(val1.is_string()); + + std::string expect("true"); + get_value_test_helper(json_str, expect); } { std::string json_str = R"(null)"; @@ -238,8 +260,21 @@ TEST_CASE("test dom parse") { iguana::parse(val1, json_str.begin(), json_str.end()); CHECK(val1.is_null()); - CHECK(val1.to_array().size() == 0); - CHECK(val1.to_object().size() == 0); + // throw + CHECK_THROWS(val1.to_array()); + CHECK_THROWS(val1.to_object()); + CHECK_THROWS(val1.to_double()); + CHECK_THROWS(val1.to_int()); + CHECK_THROWS(val1.to_bool()); + CHECK_THROWS(val1.to_string()); + // no throw + std::error_code ec; + CHECK_NOTHROW(val1.to_array(ec)); + CHECK_NOTHROW(val1.to_object(ec)); + CHECK_NOTHROW(val1.to_double(ec)); + CHECK_NOTHROW(val1.to_int(ec)); + CHECK_NOTHROW(val1.to_bool(ec)); + CHECK_NOTHROW(val1.to_string(ec)); } { // what should be filled back? From a84871a2682ff016ef3895653dec8a40f4d4f829 Mon Sep 17 00:00:00 2001 From: sandyhsia Date: Sat, 3 Dec 2022 09:19:44 +0800 Subject: [PATCH 03/34] improve. --- iguana/value.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/value.hpp b/iguana/value.hpp index 81ea9595..f5997646 100644 --- a/iguana/value.hpp +++ b/iguana/value.hpp @@ -82,7 +82,7 @@ struct basic_json_value std::error_code get_to(T &v) const { auto [ec, val] = get(); if (ec.value() == 0) - v = val; + v = std::move(val); return ec; } From 2b0f4cfe289be82421ff825d660fc9c6d4f9a11a Mon Sep 17 00:00:00 2001 From: sandyhsia Date: Sat, 3 Dec 2022 09:20:06 +0800 Subject: [PATCH 04/34] add test from issue. --- test/test.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test.cpp b/test/test.cpp index d0997923..fdcbe351 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -139,6 +139,14 @@ struct test_double_t { }; REFLECTION(test_double_t, val); +struct test { + std::string username; + std::string password; + long long id; + bool error; +}; +REFLECTION(test, username, password, id, error); + template void get_value_test_helper(const std::string &json_str, const T &expect) { iguana::jvalue jv; @@ -149,6 +157,17 @@ void get_value_test_helper(const std::string &json_str, const T &expect) { CHECK(actual == expect); } +TEST_CASE("test from issues") { + test test1; + std::string str1 = + R"({"username1": "test", "password":test, "id": 10.1, "error": false})"; + CHECK_THROWS(iguana::from_json(test1, str1.c_str(), str1.length())); + std::cout << test1.username << std::endl; + std::cout << test1.password << std::endl; + std::cout << test1.id << std::endl; + std::cout << std::boolalpha << test1.error << std::endl; +} + TEST_CASE("test dom parse") { { std::string_view str = R"(null)"; From 20beee9efb07346cbae6fddcc54a8765f25dfcc1 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Sat, 3 Dec 2022 21:46:48 +0800 Subject: [PATCH 05/34] get() with throw and get(ec) with error code --- iguana/value.hpp | 73 +++++++++++++++++++----------------------------- test/test.cpp | 20 +++++++------ 2 files changed, 40 insertions(+), 53 deletions(-) diff --git a/iguana/value.hpp b/iguana/value.hpp index f5997646..357c54b7 100644 --- a/iguana/value.hpp +++ b/iguana/value.hpp @@ -61,73 +61,58 @@ struct basic_json_value bool is_array() const { return std::holds_alternative(*this); } bool is_object() const { return std::holds_alternative(*this); } - template - std::pair get() const { - std::error_code ec{}; + // if type is not match, will throw exception, if pass std::error_code, won't + // throw exception + template T get() const { try { - return std::make_pair(ec, std::get(*this)); + return std::get(*this); } catch (std::exception &e) { auto it = type_map_.find(this->index()); if (it == type_map_.end()) { - ec = iguana::make_error_code(iguana::dom_errc::wrong_type, - "undefined type"); + throw std::invalid_argument("undefined type"); } else { - ec = iguana::make_error_code(iguana::dom_errc::wrong_type, it->second); + throw std::invalid_argument(it->second); } - return std::make_pair(ec, T{}); } } - template - std::error_code get_to(T &v) const { - auto [ec, val] = get(); - if (ec.value() == 0) - v = std::move(val); - return ec; - } - - template - T _get_to_may_throw() const { - auto [ec, v] = get(); - if (ec.value()) - throw(ec); - return v; + template T get(std::error_code &ec) const { + try { + return get(); + } catch (std::exception &e) { + ec = iguana::make_error_code(iguana::dom_errc::wrong_type, e.what()); + return T{}; + } } - template - T _get_to_no_throw(std::error_code &ec) const { - auto [code, v] = get(); - if (code.value()) - ec = code; - return v; + template std::error_code get_to(T &v) const { + std::error_code ec; + v = get(ec); + return ec; } - object_type to_object() const { return _get_to_may_throw(); } + object_type to_object() const { return get(); } object_type to_object(std::error_code &ec) const { - return _get_to_no_throw(ec); + return get(ec); } - array_type to_array() const { return _get_to_may_throw(); } - array_type to_array(std::error_code &ec) const { - return _get_to_no_throw(ec); - } + array_type to_array() const { return get(); } + array_type to_array(std::error_code &ec) const { return get(ec); } - double to_double() const { return _get_to_may_throw(); } - double to_double(std::error_code &ec) const { - return _get_to_no_throw(ec); - } + double to_double() const { return get(); } + double to_double(std::error_code &ec) const { return get(ec); } - int to_int() const { return _get_to_may_throw(); } - int to_int(std::error_code &ec) const { return _get_to_no_throw(ec); } + int to_int() const { return get(); } + int to_int(std::error_code &ec) const { return get(ec); } - bool to_bool() const { return _get_to_may_throw(); } - bool to_bool(std::error_code &ec) const { return _get_to_no_throw(ec); } + bool to_bool() const { return get(); } + bool to_bool(std::error_code &ec) const { return get(ec); } std::basic_string to_string() const { - return _get_to_may_throw>(); + return get>(); } std::basic_string to_string(std::error_code &ec) const { - return _get_to_no_throw>(ec); + return get>(ec); } }; diff --git a/test/test.cpp b/test/test.cpp index fdcbe351..6d7eb22b 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -161,7 +161,8 @@ TEST_CASE("test from issues") { test test1; std::string str1 = R"({"username1": "test", "password":test, "id": 10.1, "error": false})"; - CHECK_THROWS(iguana::from_json(test1, str1.c_str(), str1.length())); + + CHECK_THROWS(iguana::from_json(test1, str1)); std::cout << test1.username << std::endl; std::cout << test1.password << std::endl; std::cout << test1.id << std::endl; @@ -173,20 +174,22 @@ TEST_CASE("test dom parse") { std::string_view str = R"(null)"; iguana::jvalue val; iguana::parse(val, str.begin(), str.end()); - auto pair = val.get(); - if (pair.first) { - CHECK(pair.first.message() == "wrong type, real type is null type"); + std::error_code ec; + [[maybe_unused]] int i = val.get(ec); + if (ec) { + CHECK(ec.message() == "wrong type, real type is null type"); } - CHECK(val.get().second == std::nullptr_t{}); + CHECK(val.get() == std::nullptr_t{}); } { std::string_view str = R"(false)"; iguana::jvalue val; iguana::parse(val, str.begin(), str.end()); - auto pair = val.get(); - CHECK(!pair.first); - CHECK(pair.second == false); + std::error_code ec; + auto b = val.get(ec); + CHECK(!ec); + CHECK(!b); } { std::string_view str = R"({"name": "tom", "ok":true, "t": {"val":2.5}})"; @@ -242,7 +245,6 @@ TEST_CASE("test dom parse") { CHECK(num == 709); CHECK_THROWS(std::get(val1)); - int expect = 709; get_value_test_helper(json_str, 709); } { From 2de417144cf071e2b703d18b1fc44444953cb538 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Sun, 4 Dec 2022 08:52:37 +0800 Subject: [PATCH 06/34] add at --- iguana/value.hpp | 22 ++++++++++++++++++++++ test/test.cpp | 7 +++++++ 2 files changed, 29 insertions(+) diff --git a/iguana/value.hpp b/iguana/value.hpp index 357c54b7..f10c9015 100644 --- a/iguana/value.hpp +++ b/iguana/value.hpp @@ -91,6 +91,28 @@ struct basic_json_value return ec; } + template T at(size_t idx) { + const auto &arr = get(); + if (idx >= arr.size()) { + throw std::out_of_range("idx is out of range"); + } + return arr[idx].template get(); + } + + template T at(size_t idx, std::error_code &ec) { + const auto &arr = get(ec); + if (ec) { + return T{}; + } + + if (idx >= arr.size()) { + ec = std::make_error_code(std::errc::result_out_of_range); + return T{}; + } + + return arr[idx].template get(ec); + } + object_type to_object() const { return get(); } object_type to_object(std::error_code &ec) const { return get(ec); diff --git a/test/test.cpp b/test/test.cpp index 6d7eb22b..9c1f00f3 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -224,6 +224,13 @@ TEST_CASE("test dom parse") { iguana::parse(val1, json_str.begin(), json_str.end()); auto &arr = std::get(val1); + CHECK(val1.at(1) == 2.2); + + std::error_code ec1; + val1.at(1, ec1); + CHECK(ec1); + std::cout << ec1.message() << "\n"; + CHECK(std::get(arr[0]) == 0.5); CHECK(std::get(arr[1]) == 2.2); CHECK(std::get(arr[2]) == 3.3); From ef13ed2c48c91b64aace688efc3c20b5e51a3b24 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 6 Dec 2022 08:50:28 +0800 Subject: [PATCH 07/34] add at string --- .github/workflows/mac.yml | 2 +- iguana/value.hpp | 23 +++++++++++++++++++++++ test/test.cpp | 15 ++++++++++----- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index a42f2e6c..a85f37db 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -26,4 +26,4 @@ jobs: - name: test working-directory: ${{ github.workspace }}/build - run: ctest -C ${{ matrix.mode }} -j `nproc` -V + run: ctest -C ${{ matrix.mode }} -j 1 `nproc` -V diff --git a/iguana/value.hpp b/iguana/value.hpp index f10c9015..3e06a24b 100644 --- a/iguana/value.hpp +++ b/iguana/value.hpp @@ -91,6 +91,29 @@ struct basic_json_value return ec; } + template T at(const std::string &key) { + const auto &map = get(); + auto it = map.find(key); + if (it == map.end()) { + throw std::invalid_argument("the key is unknown"); + } + return it->second.template get(); + } + + template T at(const std::string &key, std::error_code &ec) { + const auto &map = get(ec); + if (ec) { + return T{}; + } + + auto it = map.find(key); + if (it == map.end()) { + ec = std::make_error_code(std::errc::invalid_argument); + return T{}; + } + return it->second.template get(ec); + } + template T at(size_t idx) { const auto &arr = get(); if (idx >= arr.size()) { diff --git a/test/test.cpp b/test/test.cpp index 9c1f00f3..9d514198 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -195,12 +195,16 @@ TEST_CASE("test dom parse") { std::string_view str = R"({"name": "tom", "ok":true, "t": {"val":2.5}})"; iguana::jvalue val; iguana::parse(val, str.begin(), str.end()); - auto &map = std::get(val); - CHECK(std::get(map.at("name")) == "tom"); - CHECK(std::get(map.at("ok")) == true); - auto &sub_map = std::get(map.at("t")); - CHECK(std::get(sub_map.at("val")) == 2.5); + CHECK(val.at("name") == "tom"); + CHECK(val.at("ok") == true); + + std::error_code ec; + val.at("no such", ec); + CHECK(ec); + + auto sub_map = val.at("t"); + CHECK(sub_map.at("val").get() == 2.5); CHECK(val.is_object()); } @@ -208,6 +212,7 @@ TEST_CASE("test dom parse") { std::string json_str = R"({"a": [1, 2, 3]})"; iguana::jvalue val1; iguana::parse(val1, json_str.begin(), json_str.end()); + auto &map = std::get(val1); auto &arr = std::get(map.at("a")); From 14efdc9628170438d366c44748aecae4ff594d6b Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 11:47:07 +0800 Subject: [PATCH 08/34] test last case --- test/test.cpp | 1304 ++++++++++++++++++++++++------------------------- 1 file changed, 652 insertions(+), 652 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 9d514198..a79f9b9b 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -17,658 +17,658 @@ struct point_t { }; REFLECTION(point_t, x, y); -struct person { - std::string name; - bool ok; - bool operator==(person const &rhs) const { - return name == rhs.name and ok == rhs.ok; - } -}; -REFLECTION(person, name, ok); - -struct bool_t { - bool ok; -}; -REFLECTION(bool_t, ok); - -struct optional_t { - std::optional p; -}; -REFLECTION(optional_t, p); - -struct char_t { - char ch; -}; -REFLECTION(char_t, ch); - -// nested object -struct simple_nested_t { - int id; - person p; -}; -REFLECTION(simple_nested_t, id, p); - -// c array -struct arr_t { - int arr[2]; -}; -REFLECTION(arr_t, arr); - -// std array -struct std_array_t { - std::array arr; -}; -REFLECTION(std_array_t, arr); - -// vector -struct vector_t { - std::vector arr; -}; -REFLECTION(vector_t, arr); - -struct two_fields_t { - std::array a; - std::vector v; -}; -REFLECTION(two_fields_t, a, v); - -struct map_t { - std::map map1; - std::unordered_map map2; -}; -REFLECTION(map_t, map1, map2); - -struct list_t { - std::list lst; -}; -REFLECTION(list_t, lst); - -struct forward_list_t { - std::forward_list lst; -}; -REFLECTION(forward_list_t, lst); - -struct deque_t { - std::deque lst; -}; -REFLECTION(deque_t, lst); - -struct fixed_name_object_t { - std::string name0{}; - std::string name1{}; - std::string name2{}; - std::string name3{}; - std::string name4{}; -}; -REFLECTION(fixed_name_object_t, name0, name1, name2, name3, name4); - -struct nested_object_t { - std::vector> v3s{}; - std::string id{}; -}; -REFLECTION(nested_object_t, v3s, id); - -struct another_object_t { - std::string string{}; - std::string another_string{}; - bool boolean{}; - nested_object_t nested_object{}; -}; -REFLECTION(another_object_t, string, another_string, boolean, nested_object); - -struct json0_obj_t { - // fixed_object_t fixed_object{}; - fixed_name_object_t fixed_name_object{}; - another_object_t another_object{}; - std::vector string_array{}; - std::string string{}; - double number{}; - bool boolean{}; - bool another_bool{}; -}; -REFLECTION(json0_obj_t, fixed_name_object, another_object, string_array, string, - number, boolean, another_bool); - -struct tuple_t { - std::tuple tp; -}; -REFLECTION(tuple_t, tp); - -struct test_double_t { - double val; -}; -REFLECTION(test_double_t, val); - -struct test { - std::string username; - std::string password; - long long id; - bool error; -}; -REFLECTION(test, username, password, id, error); - -template -void get_value_test_helper(const std::string &json_str, const T &expect) { - iguana::jvalue jv; - CHECK_NOTHROW(iguana::parse(jv, json_str.begin(), json_str.end())); - CHECK_NOTHROW(jv.get()); - T actual{}; - CHECK_NOTHROW(jv.get_to(actual)); - CHECK(actual == expect); -} - -TEST_CASE("test from issues") { - test test1; - std::string str1 = - R"({"username1": "test", "password":test, "id": 10.1, "error": false})"; - - CHECK_THROWS(iguana::from_json(test1, str1)); - std::cout << test1.username << std::endl; - std::cout << test1.password << std::endl; - std::cout << test1.id << std::endl; - std::cout << std::boolalpha << test1.error << std::endl; -} - -TEST_CASE("test dom parse") { - { - std::string_view str = R"(null)"; - iguana::jvalue val; - iguana::parse(val, str.begin(), str.end()); - std::error_code ec; - [[maybe_unused]] int i = val.get(ec); - if (ec) { - CHECK(ec.message() == "wrong type, real type is null type"); - } - CHECK(val.get() == std::nullptr_t{}); - } - { - std::string_view str = R"(false)"; - iguana::jvalue val; - iguana::parse(val, str.begin(), str.end()); - - std::error_code ec; - auto b = val.get(ec); - CHECK(!ec); - CHECK(!b); - } - { - std::string_view str = R"({"name": "tom", "ok":true, "t": {"val":2.5}})"; - iguana::jvalue val; - iguana::parse(val, str.begin(), str.end()); - - CHECK(val.at("name") == "tom"); - CHECK(val.at("ok") == true); - - std::error_code ec; - val.at("no such", ec); - CHECK(ec); - - auto sub_map = val.at("t"); - CHECK(sub_map.at("val").get() == 2.5); - CHECK(val.is_object()); - } - - { - std::string json_str = R"({"a": [1, 2, 3]})"; - iguana::jvalue val1; - iguana::parse(val1, json_str.begin(), json_str.end()); - - auto &map = std::get(val1); - auto &arr = std::get(map.at("a")); - - CHECK(std::get(arr[0]) == 1); - CHECK(std::get(arr[1]) == 2); - CHECK(std::get(arr[2]) == 3); - CHECK(val1.is_object()); - CHECK(val1.to_object().size() == 1); - } - - { - std::string json_str = R"([0.5, 2.2, 3.3])"; - iguana::jvalue val1; - iguana::parse(val1, json_str.begin(), json_str.end()); - auto &arr = std::get(val1); - - CHECK(val1.at(1) == 2.2); - - std::error_code ec1; - val1.at(1, ec1); - CHECK(ec1); - std::cout << ec1.message() << "\n"; - - CHECK(std::get(arr[0]) == 0.5); - CHECK(std::get(arr[1]) == 2.2); - CHECK(std::get(arr[2]) == 3.3); - - CHECK(val1.is_array()); - const iguana::jarray &arr1 = val1.to_array(); - CHECK(arr1.size() == 3); - CHECK(arr1[0].to_double() == 0.5); - - std::error_code ec; - CHECK_NOTHROW(val1.to_object(ec)); - CHECK_THROWS(val1.to_object()); - } - { - std::string json_str = R"(709)"; - iguana::jvalue val1; - iguana::parse(val1, json_str.begin(), json_str.end()); - auto &num = std::get(val1); - CHECK(num == 709); - CHECK_THROWS(std::get(val1)); - - get_value_test_helper(json_str, 709); - } - { - std::string json_str = R"(-0.111)"; - iguana::jvalue val1; - iguana::parse(val1, json_str.begin(), json_str.end()); - - CHECK(val1.is_double()); - CHECK(val1.is_number()); - CHECK(!val1.is_array()); - } - { - std::string json_str = R"(true)"; - iguana::jvalue val1; - iguana::parse(val1, json_str.begin(), json_str.end()); - CHECK(val1.is_bool()); - - bool expect = true; - get_value_test_helper(json_str, expect); - } - { - std::string json_str = R"("true")"; - iguana::jvalue val1; - iguana::parse(val1, json_str.begin(), json_str.end()); - CHECK(val1.is_string()); - - std::string expect("true"); - get_value_test_helper(json_str, expect); - } - { - std::string json_str = R"(null)"; - iguana::jvalue val1; - CHECK(val1.is_undefined()); - - iguana::parse(val1, json_str.begin(), json_str.end()); - CHECK(val1.is_null()); - // throw - CHECK_THROWS(val1.to_array()); - CHECK_THROWS(val1.to_object()); - CHECK_THROWS(val1.to_double()); - CHECK_THROWS(val1.to_int()); - CHECK_THROWS(val1.to_bool()); - CHECK_THROWS(val1.to_string()); - // no throw - std::error_code ec; - CHECK_NOTHROW(val1.to_array(ec)); - CHECK_NOTHROW(val1.to_object(ec)); - CHECK_NOTHROW(val1.to_double(ec)); - CHECK_NOTHROW(val1.to_int(ec)); - CHECK_NOTHROW(val1.to_bool(ec)); - CHECK_NOTHROW(val1.to_string(ec)); - } - { - // what should be filled back? - std::string json_str = R"("tr)"; - iguana::jvalue val1; - std::error_code ec{}; - CHECK_NOTHROW(iguana::parse(val1, json_str.begin(), json_str.end(), ec)); - CHECK(!val1.is_string()); - CHECK(val1.is_null()); - } -} - -TEST_CASE("test simple object") { - { - // test_double_t d{.val = 1.4806532964699196e-22}; - // iguana::string_stream ss; - // iguana::to_json(d, ss); - // - // test_double_t p{}; - // iguana::from_json(p, std::begin(ss), std::end(ss)); - // std::cout << p.val << "\n"; - } - - std::string_view str = R"({"name": "tom", "ok":true})"; - - person p{}; - iguana::from_json(p, std::begin(str), std::end(str)); - CHECK(p.name == "tom"); - CHECK(p.ok == true); - - auto pretty_str = iguana::prettify(str); - std::cout << pretty_str << "\n"; - - SUBCASE("random order of fields") { - person p1{}; - std::string_view str1 = R"({"ok":false, "name": "tom"})"; - iguana::from_json(p1, std::begin(str1), std::end(str1)); - CHECK(p1.name == "tom"); - CHECK(p1.ok == false); - } -} - -TEST_CASE("test two_fields object") { - two_fields_t obj{{1, 2}, {"aa", "bb"}}; - iguana::string_stream ss; - iguana::to_json(obj, ss); - - two_fields_t p{}; - iguana::from_json(p, std::begin(ss), std::end(ss)); - CHECK(p.v == obj.v); -} - -TEST_CASE("test simple nested object") { - person o{.name = "tom", .ok = false}; - simple_nested_t t{1, o}; - iguana::string_stream ss; - iguana::to_json(t, ss); - - simple_nested_t p{}; - iguana::from_json(p, std::begin(ss), std::end(ss)); - - CHECK(t.id == p.id); - CHECK(t.p.name == p.p.name); - CHECK(t.p.ok == p.p.ok); -} - -TEST_CASE("test c array and std::array") { - arr_t arr{{1, 2}}; - iguana::string_stream ss; - iguana::to_json(arr, ss); - arr_t arr1{}; - - iguana::from_json(arr1, std::begin(ss), std::end(ss)); - CHECK(arr.arr[0] == arr1.arr[0]); - CHECK(arr.arr[1] == arr1.arr[1]); - - std_array_t arr2{}; - iguana::from_json(arr2, std::begin(ss), std::end(ss)); - CHECK(arr.arr[0] == arr2.arr[0]); - CHECK(arr.arr[1] == arr2.arr[1]); - - vector_t vec; - iguana::from_json(vec, std::begin(ss), std::end(ss)); - CHECK(vec.arr.size() == arr2.arr.size()); - CHECK(arr2.arr[0] == vec.arr[0]); - CHECK(arr2.arr[1] == vec.arr[1]); -} - -TEST_CASE("test bool, null, char, int, float") { - { - optional_t p{}; - std::string str = R"({"p": false})"; - iguana::from_json(p, std::begin(str), std::end(str)); - CHECK(p.p.has_value()); - CHECK(*p.p == false); - - std::string str1 = R"({"p": null})"; - optional_t p1{}; - iguana::from_json(p1, std::begin(str1), std::end(str1)); - CHECK(!p1.p.has_value()); - } - { - char_t p{}; - std::string str = R"({"ch": "t"})"; - iguana::from_json(p, std::begin(str), std::end(str)); - CHECK(p.ch == 't'); - } - - { - bool_t p{}; - std::string str = R"({"ok": true})"; - iguana::from_json(p, std::begin(str), std::end(str)); - CHECK(p.ok == true); - } - - { - point_t p{}; - std::string str = R"({"x" : 1, "y" : 2})"; - iguana::from_json(p, std::begin(str), std::end(str)); - CHECK(p.x == 1); - CHECK(p.y == double(2)); - } - - { - std::string str = R"([1.0, 2.0])"; - std::vector v; - iguana::from_json(v, str); - CHECK(v[0] == 1.0); - CHECK(v[1] == 2.0); - } -} - -TEST_CASE("test vector") { - vector_t arr{{1, 2}}; - iguana::string_stream ss; - iguana::to_json(arr, ss); - - vector_t p{}; - iguana::from_json(p, std::begin(ss), std::end(ss)); - CHECK(arr.arr == p.arr); -} - -TEST_CASE("test map") { - map_t map{}; - map.map1 = {{1, "hello"}, {2, "iguana"}}; - map.map2 = {{3, "this"}, {4, "hashmap"}}; - iguana::string_stream ss; - iguana::to_json(map, ss); - - map_t p{}; - iguana::from_json(p, std::begin(ss), std::end(ss)); - CHECK(map.map1 == p.map1); - CHECK(map.map2 == p.map2); -} - -TEST_CASE("test nested object") { - std::string str = R"({ - "v3s": [[0.12345, 0.23456, 0.001345], - [0.3894675, 97.39827, 297.92387], - [18.18, 87.289, 2988.298]], - "id": "298728949872" - })"; - - nested_object_t obj{}; - iguana::from_json(obj, std::begin(str), std::end(str)); - CHECK(obj.id == "298728949872"); -} - -TEST_CASE("test tuple") { - tuple_t t; - t.tp = std::make_tuple(2, 3.14, "hello iguana"); - iguana::string_stream ss; - iguana::to_json(t, ss); - - tuple_t p{}; - iguana::from_json(p, std::begin(ss), std::end(ss)); - - CHECK(std::get<0>(t.tp) == std::get<0>(p.tp)); - CHECK(std::get<1>(t.tp) == std::get<1>(p.tp)); - CHECK(std::get<2>(t.tp) == std::get<2>(p.tp)); -} - -TEST_CASE("test list") { - list_t list{{1, 2, 3}}; - iguana::string_stream ss; - iguana::to_json(list, ss); - - list_t p{}; - iguana::from_json(p, std::begin(ss), std::end(ss)); - CHECK(list.lst == p.lst); -} - -TEST_CASE("test deque_t") { - deque_t list{{1, 2, 3}}; - iguana::string_stream ss; - iguana::to_json(list, ss); - - deque_t p{}; - iguana::from_json(p, std::begin(ss), std::end(ss)); - CHECK(list.lst == p.lst); -} - -inline constexpr std::string_view json0 = R"( -{ - "fixed_name_object": { - "name0": "James", - "name1": "Abraham", - "name2": "Susan", - "name3": "Frank", - "name4": "Alicia" - }, - "another_object": { - "string": "here is some text", - "another_string": "Hello World", - "boolean": false, - "nested_object": { - "v3s": [[0.12345, 0.23456, 0.001345], - [0.3894675, 97.39827, 297.92387], - [18.18, 87.289, 2988.298]], - "id": "298728949872" - } - }, - "string_array": ["Cat", "Dog", "Elephant", "Tiger"], - "string": "Hello world", - "number": 3.14, - "boolean": true, - "another_bool": false -} -)"; - -TEST_CASE("test complicated object") { - json0_obj_t obj; - iguana::from_json(obj, std::begin(json0), std::end(json0)); - CHECK(obj.number == 3.14); - CHECK(obj.string == "Hello world"); -} - -TEST_CASE("test non-reflectable object") { - { - std::tuple t{1, 3.14, std::string("iguana")}; - - iguana::string_stream ss; - iguana::to_json(t, ss); - - std::tuple p{}; - iguana::from_json(p, std::begin(ss), std::end(ss)); - - CHECK(std::get<0>(t) == std::get<0>(p)); - CHECK(std::get<1>(t) == std::get<1>(p)); - CHECK(std::get<2>(t) == std::get<2>(p)); - } - - { - std::string str = "[1, 2, 3]"; - std::vector p{}; - iguana::from_json(p, std::begin(str), std::end(str)); - CHECK(p == std::vector{1, 2, 3}); - - std::array arr; - iguana::from_json(arr, std::begin(str), std::end(str)); - CHECK(arr == std::array{1, 2, 3}); - - int c_arr[3]; - iguana::from_json(c_arr, std::begin(str), std::end(str)); - CHECK(c_arr[0] == 1); - CHECK(c_arr[1] == 2); - CHECK(c_arr[2] == 3); - } - - { - std::string str = R"({"1":"tom"})"; - std::map map; - iguana::from_json(map, std::begin(str), std::end(str)); - CHECK(map.size() == 1); - CHECK(map.at(1) == "tom"); - } -} - -TEST_CASE("test file interface") { - std::string filename = "test.json"; - std::ofstream out(filename, std::ios::binary); - out.write(json0.data(), json0.size()); - out.close(); - - json0_obj_t obj; - iguana::from_json_file(obj, filename); - CHECK(obj.number == 3.14); - CHECK(obj.string == "Hello world"); - - std::filesystem::remove(filename); -} - -TEST_CASE("test view and byte interface") { - std::string_view str = R"({"name": "tom", "ok":true})"; - - person p; - iguana::from_json(p, str); - - std::string str1 = {str.data(), str.size()}; - person p1; - iguana::from_json(p1, str1); - - CHECK(p == p1); - - std::vector v; - v.resize(str.size()); - std::memcpy(v.data(), str.data(), str.size()); - person p2; - iguana::from_json(p2, v); - CHECK(p == p2); - - person p3; - iguana::from_json(p3, v.data(), v.size()); - CHECK(p2 == p3); -} - -TEST_CASE("parse num") { - std::string str = R"(["x"])"; - std::vector v; - CHECK_THROWS_WITH(iguana::from_json(v, str), "Failed to parse number"); - - std::vector v1; - CHECK_THROWS_WITH(iguana::from_json(v1, str), "Failed to parse number"); -} - -TEST_CASE("parse invalid array") { - { - std::string str = R"([1)"; - std::vector v; - CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); - - std::array arr; - CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); - } - { - std::string str = R"([ )"; - std::array v; - CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); - } - { - std::string str = R"([1})"; - std::vector v; - CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); - - std::array arr; - CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); - } - - { - std::string str = R"([])"; - std::array arr; - iguana::from_json(arr, str); - } -} - -TEST_CASE("parse some other char") { - std::string str = R"({"\name":"\tom", "ok":false})"; - person p; - iguana::from_json(p, str); - CHECK(p.name == "tom"); -} +// struct person { +// std::string name; +// bool ok; +// bool operator==(person const &rhs) const { +// return name == rhs.name and ok == rhs.ok; +// } +// }; +// REFLECTION(person, name, ok); + +// struct bool_t { +// bool ok; +// }; +// REFLECTION(bool_t, ok); + +// struct optional_t { +// std::optional p; +// }; +// REFLECTION(optional_t, p); + +// struct char_t { +// char ch; +// }; +// REFLECTION(char_t, ch); + +// // nested object +// struct simple_nested_t { +// int id; +// person p; +// }; +// REFLECTION(simple_nested_t, id, p); + +// // c array +// struct arr_t { +// int arr[2]; +// }; +// REFLECTION(arr_t, arr); + +// // std array +// struct std_array_t { +// std::array arr; +// }; +// REFLECTION(std_array_t, arr); + +// // vector +// struct vector_t { +// std::vector arr; +// }; +// REFLECTION(vector_t, arr); + +// struct two_fields_t { +// std::array a; +// std::vector v; +// }; +// REFLECTION(two_fields_t, a, v); + +// struct map_t { +// std::map map1; +// std::unordered_map map2; +// }; +// REFLECTION(map_t, map1, map2); + +// struct list_t { +// std::list lst; +// }; +// REFLECTION(list_t, lst); + +// struct forward_list_t { +// std::forward_list lst; +// }; +// REFLECTION(forward_list_t, lst); + +// struct deque_t { +// std::deque lst; +// }; +// REFLECTION(deque_t, lst); + +// struct fixed_name_object_t { +// std::string name0{}; +// std::string name1{}; +// std::string name2{}; +// std::string name3{}; +// std::string name4{}; +// }; +// REFLECTION(fixed_name_object_t, name0, name1, name2, name3, name4); + +// struct nested_object_t { +// std::vector> v3s{}; +// std::string id{}; +// }; +// REFLECTION(nested_object_t, v3s, id); + +// struct another_object_t { +// std::string string{}; +// std::string another_string{}; +// bool boolean{}; +// nested_object_t nested_object{}; +// }; +// REFLECTION(another_object_t, string, another_string, boolean, nested_object); + +// struct json0_obj_t { +// // fixed_object_t fixed_object{}; +// fixed_name_object_t fixed_name_object{}; +// another_object_t another_object{}; +// std::vector string_array{}; +// std::string string{}; +// double number{}; +// bool boolean{}; +// bool another_bool{}; +// }; +// REFLECTION(json0_obj_t, fixed_name_object, another_object, string_array, string, +// number, boolean, another_bool); + +// struct tuple_t { +// std::tuple tp; +// }; +// REFLECTION(tuple_t, tp); + +// struct test_double_t { +// double val; +// }; +// REFLECTION(test_double_t, val); + +// struct test { +// std::string username; +// std::string password; +// long long id; +// bool error; +// }; +// REFLECTION(test, username, password, id, error); + +// template +// void get_value_test_helper(const std::string &json_str, const T &expect) { +// iguana::jvalue jv; +// CHECK_NOTHROW(iguana::parse(jv, json_str.begin(), json_str.end())); +// CHECK_NOTHROW(jv.get()); +// T actual{}; +// CHECK_NOTHROW(jv.get_to(actual)); +// CHECK(actual == expect); +// } + +// TEST_CASE("test from issues") { +// test test1; +// std::string str1 = +// R"({"username1": "test", "password":test, "id": 10.1, "error": false})"; + +// CHECK_THROWS(iguana::from_json(test1, str1)); +// std::cout << test1.username << std::endl; +// std::cout << test1.password << std::endl; +// std::cout << test1.id << std::endl; +// std::cout << std::boolalpha << test1.error << std::endl; +// } + +// TEST_CASE("test dom parse") { +// { +// std::string_view str = R"(null)"; +// iguana::jvalue val; +// iguana::parse(val, str.begin(), str.end()); +// std::error_code ec; +// [[maybe_unused]] int i = val.get(ec); +// if (ec) { +// CHECK(ec.message() == "wrong type, real type is null type"); +// } +// CHECK(val.get() == std::nullptr_t{}); +// } +// { +// std::string_view str = R"(false)"; +// iguana::jvalue val; +// iguana::parse(val, str.begin(), str.end()); + +// std::error_code ec; +// auto b = val.get(ec); +// CHECK(!ec); +// CHECK(!b); +// } +// { +// std::string_view str = R"({"name": "tom", "ok":true, "t": {"val":2.5}})"; +// iguana::jvalue val; +// iguana::parse(val, str.begin(), str.end()); + +// CHECK(val.at("name") == "tom"); +// CHECK(val.at("ok") == true); + +// std::error_code ec; +// val.at("no such", ec); +// CHECK(ec); + +// auto sub_map = val.at("t"); +// CHECK(sub_map.at("val").get() == 2.5); +// CHECK(val.is_object()); +// } + +// { +// std::string json_str = R"({"a": [1, 2, 3]})"; +// iguana::jvalue val1; +// iguana::parse(val1, json_str.begin(), json_str.end()); + +// auto &map = std::get(val1); +// auto &arr = std::get(map.at("a")); + +// CHECK(std::get(arr[0]) == 1); +// CHECK(std::get(arr[1]) == 2); +// CHECK(std::get(arr[2]) == 3); +// CHECK(val1.is_object()); +// CHECK(val1.to_object().size() == 1); +// } + +// { +// std::string json_str = R"([0.5, 2.2, 3.3])"; +// iguana::jvalue val1; +// iguana::parse(val1, json_str.begin(), json_str.end()); +// auto &arr = std::get(val1); + +// CHECK(val1.at(1) == 2.2); + +// std::error_code ec1; +// val1.at(1, ec1); +// CHECK(ec1); +// std::cout << ec1.message() << "\n"; + +// CHECK(std::get(arr[0]) == 0.5); +// CHECK(std::get(arr[1]) == 2.2); +// CHECK(std::get(arr[2]) == 3.3); + +// CHECK(val1.is_array()); +// const iguana::jarray &arr1 = val1.to_array(); +// CHECK(arr1.size() == 3); +// CHECK(arr1[0].to_double() == 0.5); + +// std::error_code ec; +// CHECK_NOTHROW(val1.to_object(ec)); +// CHECK_THROWS(val1.to_object()); +// } +// { +// std::string json_str = R"(709)"; +// iguana::jvalue val1; +// iguana::parse(val1, json_str.begin(), json_str.end()); +// auto &num = std::get(val1); +// CHECK(num == 709); +// CHECK_THROWS(std::get(val1)); + +// get_value_test_helper(json_str, 709); +// } +// { +// std::string json_str = R"(-0.111)"; +// iguana::jvalue val1; +// iguana::parse(val1, json_str.begin(), json_str.end()); + +// CHECK(val1.is_double()); +// CHECK(val1.is_number()); +// CHECK(!val1.is_array()); +// } +// { +// std::string json_str = R"(true)"; +// iguana::jvalue val1; +// iguana::parse(val1, json_str.begin(), json_str.end()); +// CHECK(val1.is_bool()); + +// bool expect = true; +// get_value_test_helper(json_str, expect); +// } +// { +// std::string json_str = R"("true")"; +// iguana::jvalue val1; +// iguana::parse(val1, json_str.begin(), json_str.end()); +// CHECK(val1.is_string()); + +// std::string expect("true"); +// get_value_test_helper(json_str, expect); +// } +// { +// std::string json_str = R"(null)"; +// iguana::jvalue val1; +// CHECK(val1.is_undefined()); + +// iguana::parse(val1, json_str.begin(), json_str.end()); +// CHECK(val1.is_null()); +// // throw +// CHECK_THROWS(val1.to_array()); +// CHECK_THROWS(val1.to_object()); +// CHECK_THROWS(val1.to_double()); +// CHECK_THROWS(val1.to_int()); +// CHECK_THROWS(val1.to_bool()); +// CHECK_THROWS(val1.to_string()); +// // no throw +// std::error_code ec; +// CHECK_NOTHROW(val1.to_array(ec)); +// CHECK_NOTHROW(val1.to_object(ec)); +// CHECK_NOTHROW(val1.to_double(ec)); +// CHECK_NOTHROW(val1.to_int(ec)); +// CHECK_NOTHROW(val1.to_bool(ec)); +// CHECK_NOTHROW(val1.to_string(ec)); +// } +// { +// // what should be filled back? +// std::string json_str = R"("tr)"; +// iguana::jvalue val1; +// std::error_code ec{}; +// CHECK_NOTHROW(iguana::parse(val1, json_str.begin(), json_str.end(), ec)); +// CHECK(!val1.is_string()); +// CHECK(val1.is_null()); +// } +// } + +// TEST_CASE("test simple object") { +// { +// // test_double_t d{.val = 1.4806532964699196e-22}; +// // iguana::string_stream ss; +// // iguana::to_json(d, ss); +// // +// // test_double_t p{}; +// // iguana::from_json(p, std::begin(ss), std::end(ss)); +// // std::cout << p.val << "\n"; +// } + +// std::string_view str = R"({"name": "tom", "ok":true})"; + +// person p{}; +// iguana::from_json(p, std::begin(str), std::end(str)); +// CHECK(p.name == "tom"); +// CHECK(p.ok == true); + +// auto pretty_str = iguana::prettify(str); +// std::cout << pretty_str << "\n"; + +// SUBCASE("random order of fields") { +// person p1{}; +// std::string_view str1 = R"({"ok":false, "name": "tom"})"; +// iguana::from_json(p1, std::begin(str1), std::end(str1)); +// CHECK(p1.name == "tom"); +// CHECK(p1.ok == false); +// } +// } + +// TEST_CASE("test two_fields object") { +// two_fields_t obj{{1, 2}, {"aa", "bb"}}; +// iguana::string_stream ss; +// iguana::to_json(obj, ss); + +// two_fields_t p{}; +// iguana::from_json(p, std::begin(ss), std::end(ss)); +// CHECK(p.v == obj.v); +// } + +// TEST_CASE("test simple nested object") { +// person o{.name = "tom", .ok = false}; +// simple_nested_t t{1, o}; +// iguana::string_stream ss; +// iguana::to_json(t, ss); + +// simple_nested_t p{}; +// iguana::from_json(p, std::begin(ss), std::end(ss)); + +// CHECK(t.id == p.id); +// CHECK(t.p.name == p.p.name); +// CHECK(t.p.ok == p.p.ok); +// } + +// TEST_CASE("test c array and std::array") { +// arr_t arr{{1, 2}}; +// iguana::string_stream ss; +// iguana::to_json(arr, ss); +// arr_t arr1{}; + +// iguana::from_json(arr1, std::begin(ss), std::end(ss)); +// CHECK(arr.arr[0] == arr1.arr[0]); +// CHECK(arr.arr[1] == arr1.arr[1]); + +// std_array_t arr2{}; +// iguana::from_json(arr2, std::begin(ss), std::end(ss)); +// CHECK(arr.arr[0] == arr2.arr[0]); +// CHECK(arr.arr[1] == arr2.arr[1]); + +// vector_t vec; +// iguana::from_json(vec, std::begin(ss), std::end(ss)); +// CHECK(vec.arr.size() == arr2.arr.size()); +// CHECK(arr2.arr[0] == vec.arr[0]); +// CHECK(arr2.arr[1] == vec.arr[1]); +// } + +// TEST_CASE("test bool, null, char, int, float") { +// { +// optional_t p{}; +// std::string str = R"({"p": false})"; +// iguana::from_json(p, std::begin(str), std::end(str)); +// CHECK(p.p.has_value()); +// CHECK(*p.p == false); + +// std::string str1 = R"({"p": null})"; +// optional_t p1{}; +// iguana::from_json(p1, std::begin(str1), std::end(str1)); +// CHECK(!p1.p.has_value()); +// } +// { +// char_t p{}; +// std::string str = R"({"ch": "t"})"; +// iguana::from_json(p, std::begin(str), std::end(str)); +// CHECK(p.ch == 't'); +// } + +// { +// bool_t p{}; +// std::string str = R"({"ok": true})"; +// iguana::from_json(p, std::begin(str), std::end(str)); +// CHECK(p.ok == true); +// } + +// { +// point_t p{}; +// std::string str = R"({"x" : 1, "y" : 2})"; +// iguana::from_json(p, std::begin(str), std::end(str)); +// CHECK(p.x == 1); +// CHECK(p.y == double(2)); +// } + +// { +// std::string str = R"([1.0, 2.0])"; +// std::vector v; +// iguana::from_json(v, str); +// CHECK(v[0] == 1.0); +// CHECK(v[1] == 2.0); +// } +// } + +// TEST_CASE("test vector") { +// vector_t arr{{1, 2}}; +// iguana::string_stream ss; +// iguana::to_json(arr, ss); + +// vector_t p{}; +// iguana::from_json(p, std::begin(ss), std::end(ss)); +// CHECK(arr.arr == p.arr); +// } + +// TEST_CASE("test map") { +// map_t map{}; +// map.map1 = {{1, "hello"}, {2, "iguana"}}; +// map.map2 = {{3, "this"}, {4, "hashmap"}}; +// iguana::string_stream ss; +// iguana::to_json(map, ss); + +// map_t p{}; +// iguana::from_json(p, std::begin(ss), std::end(ss)); +// CHECK(map.map1 == p.map1); +// CHECK(map.map2 == p.map2); +// } + +// TEST_CASE("test nested object") { +// std::string str = R"({ +// "v3s": [[0.12345, 0.23456, 0.001345], +// [0.3894675, 97.39827, 297.92387], +// [18.18, 87.289, 2988.298]], +// "id": "298728949872" +// })"; + +// nested_object_t obj{}; +// iguana::from_json(obj, std::begin(str), std::end(str)); +// CHECK(obj.id == "298728949872"); +// } + +// TEST_CASE("test tuple") { +// tuple_t t; +// t.tp = std::make_tuple(2, 3.14, "hello iguana"); +// iguana::string_stream ss; +// iguana::to_json(t, ss); + +// tuple_t p{}; +// iguana::from_json(p, std::begin(ss), std::end(ss)); + +// CHECK(std::get<0>(t.tp) == std::get<0>(p.tp)); +// CHECK(std::get<1>(t.tp) == std::get<1>(p.tp)); +// CHECK(std::get<2>(t.tp) == std::get<2>(p.tp)); +// } + +// TEST_CASE("test list") { +// list_t list{{1, 2, 3}}; +// iguana::string_stream ss; +// iguana::to_json(list, ss); + +// list_t p{}; +// iguana::from_json(p, std::begin(ss), std::end(ss)); +// CHECK(list.lst == p.lst); +// } + +// TEST_CASE("test deque_t") { +// deque_t list{{1, 2, 3}}; +// iguana::string_stream ss; +// iguana::to_json(list, ss); + +// deque_t p{}; +// iguana::from_json(p, std::begin(ss), std::end(ss)); +// CHECK(list.lst == p.lst); +// } + +// inline constexpr std::string_view json0 = R"( +// { +// "fixed_name_object": { +// "name0": "James", +// "name1": "Abraham", +// "name2": "Susan", +// "name3": "Frank", +// "name4": "Alicia" +// }, +// "another_object": { +// "string": "here is some text", +// "another_string": "Hello World", +// "boolean": false, +// "nested_object": { +// "v3s": [[0.12345, 0.23456, 0.001345], +// [0.3894675, 97.39827, 297.92387], +// [18.18, 87.289, 2988.298]], +// "id": "298728949872" +// } +// }, +// "string_array": ["Cat", "Dog", "Elephant", "Tiger"], +// "string": "Hello world", +// "number": 3.14, +// "boolean": true, +// "another_bool": false +// } +// )"; + +// TEST_CASE("test complicated object") { +// json0_obj_t obj; +// iguana::from_json(obj, std::begin(json0), std::end(json0)); +// CHECK(obj.number == 3.14); +// CHECK(obj.string == "Hello world"); +// } + +// TEST_CASE("test non-reflectable object") { +// { +// std::tuple t{1, 3.14, std::string("iguana")}; + +// iguana::string_stream ss; +// iguana::to_json(t, ss); + +// std::tuple p{}; +// iguana::from_json(p, std::begin(ss), std::end(ss)); + +// CHECK(std::get<0>(t) == std::get<0>(p)); +// CHECK(std::get<1>(t) == std::get<1>(p)); +// CHECK(std::get<2>(t) == std::get<2>(p)); +// } + +// { +// std::string str = "[1, 2, 3]"; +// std::vector p{}; +// iguana::from_json(p, std::begin(str), std::end(str)); +// CHECK(p == std::vector{1, 2, 3}); + +// std::array arr; +// iguana::from_json(arr, std::begin(str), std::end(str)); +// CHECK(arr == std::array{1, 2, 3}); + +// int c_arr[3]; +// iguana::from_json(c_arr, std::begin(str), std::end(str)); +// CHECK(c_arr[0] == 1); +// CHECK(c_arr[1] == 2); +// CHECK(c_arr[2] == 3); +// } + +// { +// std::string str = R"({"1":"tom"})"; +// std::map map; +// iguana::from_json(map, std::begin(str), std::end(str)); +// CHECK(map.size() == 1); +// CHECK(map.at(1) == "tom"); +// } +// } + +// TEST_CASE("test file interface") { +// std::string filename = "test.json"; +// std::ofstream out(filename, std::ios::binary); +// out.write(json0.data(), json0.size()); +// out.close(); + +// json0_obj_t obj; +// iguana::from_json_file(obj, filename); +// CHECK(obj.number == 3.14); +// CHECK(obj.string == "Hello world"); + +// std::filesystem::remove(filename); +// } + +// TEST_CASE("test view and byte interface") { +// std::string_view str = R"({"name": "tom", "ok":true})"; + +// person p; +// iguana::from_json(p, str); + +// std::string str1 = {str.data(), str.size()}; +// person p1; +// iguana::from_json(p1, str1); + +// CHECK(p == p1); + +// std::vector v; +// v.resize(str.size()); +// std::memcpy(v.data(), str.data(), str.size()); +// person p2; +// iguana::from_json(p2, v); +// CHECK(p == p2); + +// person p3; +// iguana::from_json(p3, v.data(), v.size()); +// CHECK(p2 == p3); +// } + +// TEST_CASE("parse num") { +// std::string str = R"(["x"])"; +// std::vector v; +// CHECK_THROWS_WITH(iguana::from_json(v, str), "Failed to parse number"); + +// std::vector v1; +// CHECK_THROWS_WITH(iguana::from_json(v1, str), "Failed to parse number"); +// } + +// TEST_CASE("parse invalid array") { +// { +// std::string str = R"([1)"; +// std::vector v; +// CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); + +// std::array arr; +// CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); +// } +// { +// std::string str = R"([ )"; +// std::array v; +// CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); +// } +// { +// std::string str = R"([1})"; +// std::vector v; +// CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); + +// std::array arr; +// CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); +// } + +// { +// std::string str = R"([])"; +// std::array arr; +// iguana::from_json(arr, str); +// } +// } + +// TEST_CASE("parse some other char") { +// std::string str = R"({"\name":"\tom", "ok":false})"; +// person p; +// iguana::from_json(p, str); +// CHECK(p.name == "tom"); +// } TEST_CASE("check some types") { using value_type = std::variant; From 98d0a6153f2b160e8378dbfc25677c7f93e2fb99 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 11:50:22 +0800 Subject: [PATCH 09/34] 1-453 --- test/test.cpp | 824 +++++++++++++++++++++++++------------------------- 1 file changed, 412 insertions(+), 412 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index a79f9b9b..20be7e68 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -17,438 +17,438 @@ struct point_t { }; REFLECTION(point_t, x, y); -// struct person { -// std::string name; -// bool ok; -// bool operator==(person const &rhs) const { -// return name == rhs.name and ok == rhs.ok; -// } -// }; -// REFLECTION(person, name, ok); - -// struct bool_t { -// bool ok; -// }; -// REFLECTION(bool_t, ok); - -// struct optional_t { -// std::optional p; -// }; -// REFLECTION(optional_t, p); - -// struct char_t { -// char ch; -// }; -// REFLECTION(char_t, ch); - -// // nested object -// struct simple_nested_t { -// int id; -// person p; -// }; -// REFLECTION(simple_nested_t, id, p); - -// // c array -// struct arr_t { -// int arr[2]; -// }; -// REFLECTION(arr_t, arr); - -// // std array -// struct std_array_t { -// std::array arr; -// }; -// REFLECTION(std_array_t, arr); - -// // vector -// struct vector_t { -// std::vector arr; -// }; -// REFLECTION(vector_t, arr); - -// struct two_fields_t { -// std::array a; -// std::vector v; -// }; -// REFLECTION(two_fields_t, a, v); - -// struct map_t { -// std::map map1; -// std::unordered_map map2; -// }; -// REFLECTION(map_t, map1, map2); - -// struct list_t { -// std::list lst; -// }; -// REFLECTION(list_t, lst); - -// struct forward_list_t { -// std::forward_list lst; -// }; -// REFLECTION(forward_list_t, lst); - -// struct deque_t { -// std::deque lst; -// }; -// REFLECTION(deque_t, lst); - -// struct fixed_name_object_t { -// std::string name0{}; -// std::string name1{}; -// std::string name2{}; -// std::string name3{}; -// std::string name4{}; -// }; -// REFLECTION(fixed_name_object_t, name0, name1, name2, name3, name4); - -// struct nested_object_t { -// std::vector> v3s{}; -// std::string id{}; -// }; -// REFLECTION(nested_object_t, v3s, id); - -// struct another_object_t { -// std::string string{}; -// std::string another_string{}; -// bool boolean{}; -// nested_object_t nested_object{}; -// }; -// REFLECTION(another_object_t, string, another_string, boolean, nested_object); - -// struct json0_obj_t { -// // fixed_object_t fixed_object{}; -// fixed_name_object_t fixed_name_object{}; -// another_object_t another_object{}; -// std::vector string_array{}; -// std::string string{}; -// double number{}; -// bool boolean{}; -// bool another_bool{}; -// }; -// REFLECTION(json0_obj_t, fixed_name_object, another_object, string_array, string, -// number, boolean, another_bool); - -// struct tuple_t { -// std::tuple tp; -// }; -// REFLECTION(tuple_t, tp); - -// struct test_double_t { -// double val; -// }; -// REFLECTION(test_double_t, val); - -// struct test { -// std::string username; -// std::string password; -// long long id; -// bool error; -// }; -// REFLECTION(test, username, password, id, error); - -// template -// void get_value_test_helper(const std::string &json_str, const T &expect) { -// iguana::jvalue jv; -// CHECK_NOTHROW(iguana::parse(jv, json_str.begin(), json_str.end())); -// CHECK_NOTHROW(jv.get()); -// T actual{}; -// CHECK_NOTHROW(jv.get_to(actual)); -// CHECK(actual == expect); -// } +struct person { + std::string name; + bool ok; + bool operator==(person const &rhs) const { + return name == rhs.name and ok == rhs.ok; + } +}; +REFLECTION(person, name, ok); -// TEST_CASE("test from issues") { -// test test1; -// std::string str1 = -// R"({"username1": "test", "password":test, "id": 10.1, "error": false})"; +struct bool_t { + bool ok; +}; +REFLECTION(bool_t, ok); -// CHECK_THROWS(iguana::from_json(test1, str1)); -// std::cout << test1.username << std::endl; -// std::cout << test1.password << std::endl; -// std::cout << test1.id << std::endl; -// std::cout << std::boolalpha << test1.error << std::endl; -// } +struct optional_t { + std::optional p; +}; +REFLECTION(optional_t, p); -// TEST_CASE("test dom parse") { -// { -// std::string_view str = R"(null)"; -// iguana::jvalue val; -// iguana::parse(val, str.begin(), str.end()); -// std::error_code ec; -// [[maybe_unused]] int i = val.get(ec); -// if (ec) { -// CHECK(ec.message() == "wrong type, real type is null type"); -// } -// CHECK(val.get() == std::nullptr_t{}); -// } -// { -// std::string_view str = R"(false)"; -// iguana::jvalue val; -// iguana::parse(val, str.begin(), str.end()); - -// std::error_code ec; -// auto b = val.get(ec); -// CHECK(!ec); -// CHECK(!b); -// } -// { -// std::string_view str = R"({"name": "tom", "ok":true, "t": {"val":2.5}})"; -// iguana::jvalue val; -// iguana::parse(val, str.begin(), str.end()); +struct char_t { + char ch; +}; +REFLECTION(char_t, ch); -// CHECK(val.at("name") == "tom"); -// CHECK(val.at("ok") == true); +// nested object +struct simple_nested_t { + int id; + person p; +}; +REFLECTION(simple_nested_t, id, p); -// std::error_code ec; -// val.at("no such", ec); -// CHECK(ec); +// c array +struct arr_t { + int arr[2]; +}; +REFLECTION(arr_t, arr); -// auto sub_map = val.at("t"); -// CHECK(sub_map.at("val").get() == 2.5); -// CHECK(val.is_object()); -// } +// std array +struct std_array_t { + std::array arr; +}; +REFLECTION(std_array_t, arr); -// { -// std::string json_str = R"({"a": [1, 2, 3]})"; -// iguana::jvalue val1; -// iguana::parse(val1, json_str.begin(), json_str.end()); - -// auto &map = std::get(val1); -// auto &arr = std::get(map.at("a")); - -// CHECK(std::get(arr[0]) == 1); -// CHECK(std::get(arr[1]) == 2); -// CHECK(std::get(arr[2]) == 3); -// CHECK(val1.is_object()); -// CHECK(val1.to_object().size() == 1); -// } +// vector +struct vector_t { + std::vector arr; +}; +REFLECTION(vector_t, arr); -// { -// std::string json_str = R"([0.5, 2.2, 3.3])"; -// iguana::jvalue val1; -// iguana::parse(val1, json_str.begin(), json_str.end()); -// auto &arr = std::get(val1); - -// CHECK(val1.at(1) == 2.2); - -// std::error_code ec1; -// val1.at(1, ec1); -// CHECK(ec1); -// std::cout << ec1.message() << "\n"; - -// CHECK(std::get(arr[0]) == 0.5); -// CHECK(std::get(arr[1]) == 2.2); -// CHECK(std::get(arr[2]) == 3.3); - -// CHECK(val1.is_array()); -// const iguana::jarray &arr1 = val1.to_array(); -// CHECK(arr1.size() == 3); -// CHECK(arr1[0].to_double() == 0.5); - -// std::error_code ec; -// CHECK_NOTHROW(val1.to_object(ec)); -// CHECK_THROWS(val1.to_object()); -// } -// { -// std::string json_str = R"(709)"; -// iguana::jvalue val1; -// iguana::parse(val1, json_str.begin(), json_str.end()); -// auto &num = std::get(val1); -// CHECK(num == 709); -// CHECK_THROWS(std::get(val1)); - -// get_value_test_helper(json_str, 709); -// } -// { -// std::string json_str = R"(-0.111)"; -// iguana::jvalue val1; -// iguana::parse(val1, json_str.begin(), json_str.end()); +struct two_fields_t { + std::array a; + std::vector v; +}; +REFLECTION(two_fields_t, a, v); -// CHECK(val1.is_double()); -// CHECK(val1.is_number()); -// CHECK(!val1.is_array()); -// } -// { -// std::string json_str = R"(true)"; -// iguana::jvalue val1; -// iguana::parse(val1, json_str.begin(), json_str.end()); -// CHECK(val1.is_bool()); +struct map_t { + std::map map1; + std::unordered_map map2; +}; +REFLECTION(map_t, map1, map2); -// bool expect = true; -// get_value_test_helper(json_str, expect); -// } -// { -// std::string json_str = R"("true")"; -// iguana::jvalue val1; -// iguana::parse(val1, json_str.begin(), json_str.end()); -// CHECK(val1.is_string()); +struct list_t { + std::list lst; +}; +REFLECTION(list_t, lst); -// std::string expect("true"); -// get_value_test_helper(json_str, expect); -// } -// { -// std::string json_str = R"(null)"; -// iguana::jvalue val1; -// CHECK(val1.is_undefined()); - -// iguana::parse(val1, json_str.begin(), json_str.end()); -// CHECK(val1.is_null()); -// // throw -// CHECK_THROWS(val1.to_array()); -// CHECK_THROWS(val1.to_object()); -// CHECK_THROWS(val1.to_double()); -// CHECK_THROWS(val1.to_int()); -// CHECK_THROWS(val1.to_bool()); -// CHECK_THROWS(val1.to_string()); -// // no throw -// std::error_code ec; -// CHECK_NOTHROW(val1.to_array(ec)); -// CHECK_NOTHROW(val1.to_object(ec)); -// CHECK_NOTHROW(val1.to_double(ec)); -// CHECK_NOTHROW(val1.to_int(ec)); -// CHECK_NOTHROW(val1.to_bool(ec)); -// CHECK_NOTHROW(val1.to_string(ec)); -// } -// { -// // what should be filled back? -// std::string json_str = R"("tr)"; -// iguana::jvalue val1; -// std::error_code ec{}; -// CHECK_NOTHROW(iguana::parse(val1, json_str.begin(), json_str.end(), ec)); -// CHECK(!val1.is_string()); -// CHECK(val1.is_null()); -// } -// } +struct forward_list_t { + std::forward_list lst; +}; +REFLECTION(forward_list_t, lst); -// TEST_CASE("test simple object") { -// { -// // test_double_t d{.val = 1.4806532964699196e-22}; -// // iguana::string_stream ss; -// // iguana::to_json(d, ss); -// // -// // test_double_t p{}; -// // iguana::from_json(p, std::begin(ss), std::end(ss)); -// // std::cout << p.val << "\n"; -// } +struct deque_t { + std::deque lst; +}; +REFLECTION(deque_t, lst); + +struct fixed_name_object_t { + std::string name0{}; + std::string name1{}; + std::string name2{}; + std::string name3{}; + std::string name4{}; +}; +REFLECTION(fixed_name_object_t, name0, name1, name2, name3, name4); -// std::string_view str = R"({"name": "tom", "ok":true})"; +struct nested_object_t { + std::vector> v3s{}; + std::string id{}; +}; +REFLECTION(nested_object_t, v3s, id); -// person p{}; -// iguana::from_json(p, std::begin(str), std::end(str)); -// CHECK(p.name == "tom"); -// CHECK(p.ok == true); +struct another_object_t { + std::string string{}; + std::string another_string{}; + bool boolean{}; + nested_object_t nested_object{}; +}; +REFLECTION(another_object_t, string, another_string, boolean, nested_object); + +struct json0_obj_t { + // fixed_object_t fixed_object{}; + fixed_name_object_t fixed_name_object{}; + another_object_t another_object{}; + std::vector string_array{}; + std::string string{}; + double number{}; + bool boolean{}; + bool another_bool{}; +}; +REFLECTION(json0_obj_t, fixed_name_object, another_object, string_array, string, + number, boolean, another_bool); -// auto pretty_str = iguana::prettify(str); -// std::cout << pretty_str << "\n"; +struct tuple_t { + std::tuple tp; +}; +REFLECTION(tuple_t, tp); -// SUBCASE("random order of fields") { -// person p1{}; -// std::string_view str1 = R"({"ok":false, "name": "tom"})"; -// iguana::from_json(p1, std::begin(str1), std::end(str1)); -// CHECK(p1.name == "tom"); -// CHECK(p1.ok == false); -// } -// } +struct test_double_t { + double val; +}; +REFLECTION(test_double_t, val); -// TEST_CASE("test two_fields object") { -// two_fields_t obj{{1, 2}, {"aa", "bb"}}; -// iguana::string_stream ss; -// iguana::to_json(obj, ss); +struct test { + std::string username; + std::string password; + long long id; + bool error; +}; +REFLECTION(test, username, password, id, error); + +template +void get_value_test_helper(const std::string &json_str, const T &expect) { + iguana::jvalue jv; + CHECK_NOTHROW(iguana::parse(jv, json_str.begin(), json_str.end())); + CHECK_NOTHROW(jv.get()); + T actual{}; + CHECK_NOTHROW(jv.get_to(actual)); + CHECK(actual == expect); +} -// two_fields_t p{}; -// iguana::from_json(p, std::begin(ss), std::end(ss)); -// CHECK(p.v == obj.v); -// } +TEST_CASE("test from issues") { + test test1; + std::string str1 = + R"({"username1": "test", "password":test, "id": 10.1, "error": false})"; -// TEST_CASE("test simple nested object") { -// person o{.name = "tom", .ok = false}; -// simple_nested_t t{1, o}; -// iguana::string_stream ss; -// iguana::to_json(t, ss); + CHECK_THROWS(iguana::from_json(test1, str1)); + std::cout << test1.username << std::endl; + std::cout << test1.password << std::endl; + std::cout << test1.id << std::endl; + std::cout << std::boolalpha << test1.error << std::endl; +} -// simple_nested_t p{}; -// iguana::from_json(p, std::begin(ss), std::end(ss)); +TEST_CASE("test dom parse") { + { + std::string_view str = R"(null)"; + iguana::jvalue val; + iguana::parse(val, str.begin(), str.end()); + std::error_code ec; + [[maybe_unused]] int i = val.get(ec); + if (ec) { + CHECK(ec.message() == "wrong type, real type is null type"); + } + CHECK(val.get() == std::nullptr_t{}); + } + { + std::string_view str = R"(false)"; + iguana::jvalue val; + iguana::parse(val, str.begin(), str.end()); + + std::error_code ec; + auto b = val.get(ec); + CHECK(!ec); + CHECK(!b); + } + { + std::string_view str = R"({"name": "tom", "ok":true, "t": {"val":2.5}})"; + iguana::jvalue val; + iguana::parse(val, str.begin(), str.end()); + + CHECK(val.at("name") == "tom"); + CHECK(val.at("ok") == true); + + std::error_code ec; + val.at("no such", ec); + CHECK(ec); + + auto sub_map = val.at("t"); + CHECK(sub_map.at("val").get() == 2.5); + CHECK(val.is_object()); + } + + { + std::string json_str = R"({"a": [1, 2, 3]})"; + iguana::jvalue val1; + iguana::parse(val1, json_str.begin(), json_str.end()); + + auto &map = std::get(val1); + auto &arr = std::get(map.at("a")); + + CHECK(std::get(arr[0]) == 1); + CHECK(std::get(arr[1]) == 2); + CHECK(std::get(arr[2]) == 3); + CHECK(val1.is_object()); + CHECK(val1.to_object().size() == 1); + } + + { + std::string json_str = R"([0.5, 2.2, 3.3])"; + iguana::jvalue val1; + iguana::parse(val1, json_str.begin(), json_str.end()); + auto &arr = std::get(val1); + + CHECK(val1.at(1) == 2.2); + + std::error_code ec1; + val1.at(1, ec1); + CHECK(ec1); + std::cout << ec1.message() << "\n"; + + CHECK(std::get(arr[0]) == 0.5); + CHECK(std::get(arr[1]) == 2.2); + CHECK(std::get(arr[2]) == 3.3); + + CHECK(val1.is_array()); + const iguana::jarray &arr1 = val1.to_array(); + CHECK(arr1.size() == 3); + CHECK(arr1[0].to_double() == 0.5); + + std::error_code ec; + CHECK_NOTHROW(val1.to_object(ec)); + CHECK_THROWS(val1.to_object()); + } + { + std::string json_str = R"(709)"; + iguana::jvalue val1; + iguana::parse(val1, json_str.begin(), json_str.end()); + auto &num = std::get(val1); + CHECK(num == 709); + CHECK_THROWS(std::get(val1)); + + get_value_test_helper(json_str, 709); + } + { + std::string json_str = R"(-0.111)"; + iguana::jvalue val1; + iguana::parse(val1, json_str.begin(), json_str.end()); + + CHECK(val1.is_double()); + CHECK(val1.is_number()); + CHECK(!val1.is_array()); + } + { + std::string json_str = R"(true)"; + iguana::jvalue val1; + iguana::parse(val1, json_str.begin(), json_str.end()); + CHECK(val1.is_bool()); + + bool expect = true; + get_value_test_helper(json_str, expect); + } + { + std::string json_str = R"("true")"; + iguana::jvalue val1; + iguana::parse(val1, json_str.begin(), json_str.end()); + CHECK(val1.is_string()); + + std::string expect("true"); + get_value_test_helper(json_str, expect); + } + { + std::string json_str = R"(null)"; + iguana::jvalue val1; + CHECK(val1.is_undefined()); + + iguana::parse(val1, json_str.begin(), json_str.end()); + CHECK(val1.is_null()); + // throw + CHECK_THROWS(val1.to_array()); + CHECK_THROWS(val1.to_object()); + CHECK_THROWS(val1.to_double()); + CHECK_THROWS(val1.to_int()); + CHECK_THROWS(val1.to_bool()); + CHECK_THROWS(val1.to_string()); + // no throw + std::error_code ec; + CHECK_NOTHROW(val1.to_array(ec)); + CHECK_NOTHROW(val1.to_object(ec)); + CHECK_NOTHROW(val1.to_double(ec)); + CHECK_NOTHROW(val1.to_int(ec)); + CHECK_NOTHROW(val1.to_bool(ec)); + CHECK_NOTHROW(val1.to_string(ec)); + } + { + // what should be filled back? + std::string json_str = R"("tr)"; + iguana::jvalue val1; + std::error_code ec{}; + CHECK_NOTHROW(iguana::parse(val1, json_str.begin(), json_str.end(), ec)); + CHECK(!val1.is_string()); + CHECK(val1.is_null()); + } +} -// CHECK(t.id == p.id); -// CHECK(t.p.name == p.p.name); -// CHECK(t.p.ok == p.p.ok); -// } +TEST_CASE("test simple object") { + { + // test_double_t d{.val = 1.4806532964699196e-22}; + // iguana::string_stream ss; + // iguana::to_json(d, ss); + // + // test_double_t p{}; + // iguana::from_json(p, std::begin(ss), std::end(ss)); + // std::cout << p.val << "\n"; + } + + std::string_view str = R"({"name": "tom", "ok":true})"; + + person p{}; + iguana::from_json(p, std::begin(str), std::end(str)); + CHECK(p.name == "tom"); + CHECK(p.ok == true); + + auto pretty_str = iguana::prettify(str); + std::cout << pretty_str << "\n"; + + SUBCASE("random order of fields") { + person p1{}; + std::string_view str1 = R"({"ok":false, "name": "tom"})"; + iguana::from_json(p1, std::begin(str1), std::end(str1)); + CHECK(p1.name == "tom"); + CHECK(p1.ok == false); + } +} -// TEST_CASE("test c array and std::array") { -// arr_t arr{{1, 2}}; -// iguana::string_stream ss; -// iguana::to_json(arr, ss); -// arr_t arr1{}; - -// iguana::from_json(arr1, std::begin(ss), std::end(ss)); -// CHECK(arr.arr[0] == arr1.arr[0]); -// CHECK(arr.arr[1] == arr1.arr[1]); - -// std_array_t arr2{}; -// iguana::from_json(arr2, std::begin(ss), std::end(ss)); -// CHECK(arr.arr[0] == arr2.arr[0]); -// CHECK(arr.arr[1] == arr2.arr[1]); - -// vector_t vec; -// iguana::from_json(vec, std::begin(ss), std::end(ss)); -// CHECK(vec.arr.size() == arr2.arr.size()); -// CHECK(arr2.arr[0] == vec.arr[0]); -// CHECK(arr2.arr[1] == vec.arr[1]); -// } +TEST_CASE("test two_fields object") { + two_fields_t obj{{1, 2}, {"aa", "bb"}}; + iguana::string_stream ss; + iguana::to_json(obj, ss); -// TEST_CASE("test bool, null, char, int, float") { -// { -// optional_t p{}; -// std::string str = R"({"p": false})"; -// iguana::from_json(p, std::begin(str), std::end(str)); -// CHECK(p.p.has_value()); -// CHECK(*p.p == false); + two_fields_t p{}; + iguana::from_json(p, std::begin(ss), std::end(ss)); + CHECK(p.v == obj.v); +} -// std::string str1 = R"({"p": null})"; -// optional_t p1{}; -// iguana::from_json(p1, std::begin(str1), std::end(str1)); -// CHECK(!p1.p.has_value()); -// } -// { -// char_t p{}; -// std::string str = R"({"ch": "t"})"; -// iguana::from_json(p, std::begin(str), std::end(str)); -// CHECK(p.ch == 't'); -// } +TEST_CASE("test simple nested object") { + person o{.name = "tom", .ok = false}; + simple_nested_t t{1, o}; + iguana::string_stream ss; + iguana::to_json(t, ss); -// { -// bool_t p{}; -// std::string str = R"({"ok": true})"; -// iguana::from_json(p, std::begin(str), std::end(str)); -// CHECK(p.ok == true); -// } + simple_nested_t p{}; + iguana::from_json(p, std::begin(ss), std::end(ss)); -// { -// point_t p{}; -// std::string str = R"({"x" : 1, "y" : 2})"; -// iguana::from_json(p, std::begin(str), std::end(str)); -// CHECK(p.x == 1); -// CHECK(p.y == double(2)); -// } + CHECK(t.id == p.id); + CHECK(t.p.name == p.p.name); + CHECK(t.p.ok == p.p.ok); +} -// { -// std::string str = R"([1.0, 2.0])"; -// std::vector v; -// iguana::from_json(v, str); -// CHECK(v[0] == 1.0); -// CHECK(v[1] == 2.0); -// } -// } +TEST_CASE("test c array and std::array") { + arr_t arr{{1, 2}}; + iguana::string_stream ss; + iguana::to_json(arr, ss); + arr_t arr1{}; + + iguana::from_json(arr1, std::begin(ss), std::end(ss)); + CHECK(arr.arr[0] == arr1.arr[0]); + CHECK(arr.arr[1] == arr1.arr[1]); + + std_array_t arr2{}; + iguana::from_json(arr2, std::begin(ss), std::end(ss)); + CHECK(arr.arr[0] == arr2.arr[0]); + CHECK(arr.arr[1] == arr2.arr[1]); + + vector_t vec; + iguana::from_json(vec, std::begin(ss), std::end(ss)); + CHECK(vec.arr.size() == arr2.arr.size()); + CHECK(arr2.arr[0] == vec.arr[0]); + CHECK(arr2.arr[1] == vec.arr[1]); +} -// TEST_CASE("test vector") { -// vector_t arr{{1, 2}}; -// iguana::string_stream ss; -// iguana::to_json(arr, ss); +TEST_CASE("test bool, null, char, int, float") { + { + optional_t p{}; + std::string str = R"({"p": false})"; + iguana::from_json(p, std::begin(str), std::end(str)); + CHECK(p.p.has_value()); + CHECK(*p.p == false); + + std::string str1 = R"({"p": null})"; + optional_t p1{}; + iguana::from_json(p1, std::begin(str1), std::end(str1)); + CHECK(!p1.p.has_value()); + } + { + char_t p{}; + std::string str = R"({"ch": "t"})"; + iguana::from_json(p, std::begin(str), std::end(str)); + CHECK(p.ch == 't'); + } + + { + bool_t p{}; + std::string str = R"({"ok": true})"; + iguana::from_json(p, std::begin(str), std::end(str)); + CHECK(p.ok == true); + } + + { + point_t p{}; + std::string str = R"({"x" : 1, "y" : 2})"; + iguana::from_json(p, std::begin(str), std::end(str)); + CHECK(p.x == 1); + CHECK(p.y == double(2)); + } + + { + std::string str = R"([1.0, 2.0])"; + std::vector v; + iguana::from_json(v, str); + CHECK(v[0] == 1.0); + CHECK(v[1] == 2.0); + } +} -// vector_t p{}; -// iguana::from_json(p, std::begin(ss), std::end(ss)); -// CHECK(arr.arr == p.arr); -// } +TEST_CASE("test vector") { + vector_t arr{{1, 2}}; + iguana::string_stream ss; + iguana::to_json(arr, ss); + + vector_t p{}; + iguana::from_json(p, std::begin(ss), std::end(ss)); + CHECK(arr.arr == p.arr); +} // TEST_CASE("test map") { // map_t map{}; @@ -670,15 +670,15 @@ REFLECTION(point_t, x, y); // CHECK(p.name == "tom"); // } -TEST_CASE("check some types") { - using value_type = std::variant; - constexpr auto map = iguana::get_iguana_struct_map(); - static_assert(map.size() == 2); - static_assert(map.at("x") == - value_type{std::in_place_index_t<0>{}, &point_t::x}); - static_assert(map.at("y") == - value_type{std::in_place_index_t<1>{}, &point_t::y}); -} +// TEST_CASE("check some types") { +// using value_type = std::variant; +// constexpr auto map = iguana::get_iguana_struct_map(); +// static_assert(map.size() == 2); +// static_assert(map.at("x") == +// value_type{std::in_place_index_t<0>{}, &point_t::x}); +// static_assert(map.at("y") == +// value_type{std::in_place_index_t<1>{}, &point_t::y}); +// } // doctest comments // 'function' : must be 'attribute' - see issue #182 From 0d44808e2144c74ebf4afc6deabab88f319db1af Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 12:09:51 +0800 Subject: [PATCH 10/34] 453-546 --- test/test.cpp | 168 +++++++++++++++++++++++++------------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 20be7e68..5494d5cb 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -450,100 +450,100 @@ TEST_CASE("test vector") { CHECK(arr.arr == p.arr); } -// TEST_CASE("test map") { -// map_t map{}; -// map.map1 = {{1, "hello"}, {2, "iguana"}}; -// map.map2 = {{3, "this"}, {4, "hashmap"}}; -// iguana::string_stream ss; -// iguana::to_json(map, ss); - -// map_t p{}; -// iguana::from_json(p, std::begin(ss), std::end(ss)); -// CHECK(map.map1 == p.map1); -// CHECK(map.map2 == p.map2); -// } +TEST_CASE("test map") { + map_t map{}; + map.map1 = {{1, "hello"}, {2, "iguana"}}; + map.map2 = {{3, "this"}, {4, "hashmap"}}; + iguana::string_stream ss; + iguana::to_json(map, ss); -// TEST_CASE("test nested object") { -// std::string str = R"({ -// "v3s": [[0.12345, 0.23456, 0.001345], -// [0.3894675, 97.39827, 297.92387], -// [18.18, 87.289, 2988.298]], -// "id": "298728949872" -// })"; - -// nested_object_t obj{}; -// iguana::from_json(obj, std::begin(str), std::end(str)); -// CHECK(obj.id == "298728949872"); -// } + map_t p{}; + iguana::from_json(p, std::begin(ss), std::end(ss)); + CHECK(map.map1 == p.map1); + CHECK(map.map2 == p.map2); +} -// TEST_CASE("test tuple") { -// tuple_t t; -// t.tp = std::make_tuple(2, 3.14, "hello iguana"); -// iguana::string_stream ss; -// iguana::to_json(t, ss); +TEST_CASE("test nested object") { + std::string str = R"({ + "v3s": [[0.12345, 0.23456, 0.001345], + [0.3894675, 97.39827, 297.92387], + [18.18, 87.289, 2988.298]], + "id": "298728949872" + })"; + + nested_object_t obj{}; + iguana::from_json(obj, std::begin(str), std::end(str)); + CHECK(obj.id == "298728949872"); +} -// tuple_t p{}; -// iguana::from_json(p, std::begin(ss), std::end(ss)); +TEST_CASE("test tuple") { + tuple_t t; + t.tp = std::make_tuple(2, 3.14, "hello iguana"); + iguana::string_stream ss; + iguana::to_json(t, ss); -// CHECK(std::get<0>(t.tp) == std::get<0>(p.tp)); -// CHECK(std::get<1>(t.tp) == std::get<1>(p.tp)); -// CHECK(std::get<2>(t.tp) == std::get<2>(p.tp)); -// } + tuple_t p{}; + iguana::from_json(p, std::begin(ss), std::end(ss)); -// TEST_CASE("test list") { -// list_t list{{1, 2, 3}}; -// iguana::string_stream ss; -// iguana::to_json(list, ss); + CHECK(std::get<0>(t.tp) == std::get<0>(p.tp)); + CHECK(std::get<1>(t.tp) == std::get<1>(p.tp)); + CHECK(std::get<2>(t.tp) == std::get<2>(p.tp)); +} -// list_t p{}; -// iguana::from_json(p, std::begin(ss), std::end(ss)); -// CHECK(list.lst == p.lst); -// } +TEST_CASE("test list") { + list_t list{{1, 2, 3}}; + iguana::string_stream ss; + iguana::to_json(list, ss); -// TEST_CASE("test deque_t") { -// deque_t list{{1, 2, 3}}; -// iguana::string_stream ss; -// iguana::to_json(list, ss); + list_t p{}; + iguana::from_json(p, std::begin(ss), std::end(ss)); + CHECK(list.lst == p.lst); +} -// deque_t p{}; -// iguana::from_json(p, std::begin(ss), std::end(ss)); -// CHECK(list.lst == p.lst); -// } +TEST_CASE("test deque_t") { + deque_t list{{1, 2, 3}}; + iguana::string_stream ss; + iguana::to_json(list, ss); -// inline constexpr std::string_view json0 = R"( -// { -// "fixed_name_object": { -// "name0": "James", -// "name1": "Abraham", -// "name2": "Susan", -// "name3": "Frank", -// "name4": "Alicia" -// }, -// "another_object": { -// "string": "here is some text", -// "another_string": "Hello World", -// "boolean": false, -// "nested_object": { -// "v3s": [[0.12345, 0.23456, 0.001345], -// [0.3894675, 97.39827, 297.92387], -// [18.18, 87.289, 2988.298]], -// "id": "298728949872" -// } -// }, -// "string_array": ["Cat", "Dog", "Elephant", "Tiger"], -// "string": "Hello world", -// "number": 3.14, -// "boolean": true, -// "another_bool": false -// } -// )"; + deque_t p{}; + iguana::from_json(p, std::begin(ss), std::end(ss)); + CHECK(list.lst == p.lst); +} -// TEST_CASE("test complicated object") { -// json0_obj_t obj; -// iguana::from_json(obj, std::begin(json0), std::end(json0)); -// CHECK(obj.number == 3.14); -// CHECK(obj.string == "Hello world"); -// } +inline constexpr std::string_view json0 = R"( +{ + "fixed_name_object": { + "name0": "James", + "name1": "Abraham", + "name2": "Susan", + "name3": "Frank", + "name4": "Alicia" + }, + "another_object": { + "string": "here is some text", + "another_string": "Hello World", + "boolean": false, + "nested_object": { + "v3s": [[0.12345, 0.23456, 0.001345], + [0.3894675, 97.39827, 297.92387], + [18.18, 87.289, 2988.298]], + "id": "298728949872" + } + }, + "string_array": ["Cat", "Dog", "Elephant", "Tiger"], + "string": "Hello world", + "number": 3.14, + "boolean": true, + "another_bool": false +} +)"; + +TEST_CASE("test complicated object") { + json0_obj_t obj; + iguana::from_json(obj, std::begin(json0), std::end(json0)); + CHECK(obj.number == 3.14); + CHECK(obj.string == "Hello world"); +} // TEST_CASE("test non-reflectable object") { // { From 784b55c5498ddf0483be4c8b6c940ade71973fd6 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 12:15:01 +0800 Subject: [PATCH 11/34] 548->602 --- test/test.cpp | 92 +++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 5494d5cb..5e648c71 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -545,60 +545,60 @@ TEST_CASE("test complicated object") { CHECK(obj.string == "Hello world"); } -// TEST_CASE("test non-reflectable object") { -// { -// std::tuple t{1, 3.14, std::string("iguana")}; +TEST_CASE("test non-reflectable object") { + { + std::tuple t{1, 3.14, std::string("iguana")}; -// iguana::string_stream ss; -// iguana::to_json(t, ss); + iguana::string_stream ss; + iguana::to_json(t, ss); -// std::tuple p{}; -// iguana::from_json(p, std::begin(ss), std::end(ss)); + std::tuple p{}; + iguana::from_json(p, std::begin(ss), std::end(ss)); -// CHECK(std::get<0>(t) == std::get<0>(p)); -// CHECK(std::get<1>(t) == std::get<1>(p)); -// CHECK(std::get<2>(t) == std::get<2>(p)); -// } + CHECK(std::get<0>(t) == std::get<0>(p)); + CHECK(std::get<1>(t) == std::get<1>(p)); + CHECK(std::get<2>(t) == std::get<2>(p)); + } -// { -// std::string str = "[1, 2, 3]"; -// std::vector p{}; -// iguana::from_json(p, std::begin(str), std::end(str)); -// CHECK(p == std::vector{1, 2, 3}); - -// std::array arr; -// iguana::from_json(arr, std::begin(str), std::end(str)); -// CHECK(arr == std::array{1, 2, 3}); - -// int c_arr[3]; -// iguana::from_json(c_arr, std::begin(str), std::end(str)); -// CHECK(c_arr[0] == 1); -// CHECK(c_arr[1] == 2); -// CHECK(c_arr[2] == 3); -// } + { + std::string str = "[1, 2, 3]"; + std::vector p{}; + iguana::from_json(p, std::begin(str), std::end(str)); + CHECK(p == std::vector{1, 2, 3}); -// { -// std::string str = R"({"1":"tom"})"; -// std::map map; -// iguana::from_json(map, std::begin(str), std::end(str)); -// CHECK(map.size() == 1); -// CHECK(map.at(1) == "tom"); -// } -// } + std::array arr; + iguana::from_json(arr, std::begin(str), std::end(str)); + CHECK(arr == std::array{1, 2, 3}); -// TEST_CASE("test file interface") { -// std::string filename = "test.json"; -// std::ofstream out(filename, std::ios::binary); -// out.write(json0.data(), json0.size()); -// out.close(); + int c_arr[3]; + iguana::from_json(c_arr, std::begin(str), std::end(str)); + CHECK(c_arr[0] == 1); + CHECK(c_arr[1] == 2); + CHECK(c_arr[2] == 3); + } + + { + std::string str = R"({"1":"tom"})"; + std::map map; + iguana::from_json(map, std::begin(str), std::end(str)); + CHECK(map.size() == 1); + CHECK(map.at(1) == "tom"); + } +} -// json0_obj_t obj; -// iguana::from_json_file(obj, filename); -// CHECK(obj.number == 3.14); -// CHECK(obj.string == "Hello world"); +TEST_CASE("test file interface") { + std::string filename = "test.json"; + std::ofstream out(filename, std::ios::binary); + out.write(json0.data(), json0.size()); + out.close(); -// std::filesystem::remove(filename); -// } + json0_obj_t obj; + iguana::from_json_file(obj, filename); + CHECK(obj.number == 3.14); + CHECK(obj.string == "Hello world"); + + std::filesystem::remove(filename); +} // TEST_CASE("test view and byte interface") { // std::string_view str = R"({"name": "tom", "ok":true})"; From 3fa0c5ee1548ca90ea455b63b3c9ad10b4c77258 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 12:21:20 +0800 Subject: [PATCH 12/34] 603->664 --- test/test.cpp | 108 +++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 5e648c71..06e15831 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -600,68 +600,68 @@ TEST_CASE("test file interface") { std::filesystem::remove(filename); } -// TEST_CASE("test view and byte interface") { -// std::string_view str = R"({"name": "tom", "ok":true})"; +TEST_CASE("test view and byte interface") { + std::string_view str = R"({"name": "tom", "ok":true})"; -// person p; -// iguana::from_json(p, str); + person p; + iguana::from_json(p, str); -// std::string str1 = {str.data(), str.size()}; -// person p1; -// iguana::from_json(p1, str1); + std::string str1 = {str.data(), str.size()}; + person p1; + iguana::from_json(p1, str1); -// CHECK(p == p1); + CHECK(p == p1); -// std::vector v; -// v.resize(str.size()); -// std::memcpy(v.data(), str.data(), str.size()); -// person p2; -// iguana::from_json(p2, v); -// CHECK(p == p2); + std::vector v; + v.resize(str.size()); + std::memcpy(v.data(), str.data(), str.size()); + person p2; + iguana::from_json(p2, v); + CHECK(p == p2); -// person p3; -// iguana::from_json(p3, v.data(), v.size()); -// CHECK(p2 == p3); -// } + person p3; + iguana::from_json(p3, v.data(), v.size()); + CHECK(p2 == p3); +} -// TEST_CASE("parse num") { -// std::string str = R"(["x"])"; -// std::vector v; -// CHECK_THROWS_WITH(iguana::from_json(v, str), "Failed to parse number"); +TEST_CASE("parse num") { + std::string str = R"(["x"])"; + std::vector v; + CHECK_THROWS_WITH(iguana::from_json(v, str), "Failed to parse number"); -// std::vector v1; -// CHECK_THROWS_WITH(iguana::from_json(v1, str), "Failed to parse number"); -// } + std::vector v1; + CHECK_THROWS_WITH(iguana::from_json(v1, str), "Failed to parse number"); +} -// TEST_CASE("parse invalid array") { -// { -// std::string str = R"([1)"; -// std::vector v; -// CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); - -// std::array arr; -// CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); -// } -// { -// std::string str = R"([ )"; -// std::array v; -// CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); -// } -// { -// std::string str = R"([1})"; -// std::vector v; -// CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); - -// std::array arr; -// CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); -// } - -// { -// std::string str = R"([])"; -// std::array arr; -// iguana::from_json(arr, str); -// } -// } +TEST_CASE("parse invalid array") { + { + std::string str = R"([1)"; + std::vector v; + CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); + + std::array arr; + CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); + } + { + std::string str = R"([ )"; + std::array v; + CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); + } + { + std::string str = R"([1})"; + std::vector v; + CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); + + std::array arr; + CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); + } + + { + std::string str = R"([])"; + std::array arr; + iguana::from_json(arr, str); + } +} // TEST_CASE("parse some other char") { // std::string str = R"({"\name":"\tom", "ok":false})"; From 6d37762dba47810f2b4ce4700ce4269a53db014c Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 12:28:53 +0800 Subject: [PATCH 13/34] 603->635 --- test/test.cpp | 58 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 06e15831..76e04f79 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -633,35 +633,35 @@ TEST_CASE("parse num") { CHECK_THROWS_WITH(iguana::from_json(v1, str), "Failed to parse number"); } -TEST_CASE("parse invalid array") { - { - std::string str = R"([1)"; - std::vector v; - CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); - - std::array arr; - CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); - } - { - std::string str = R"([ )"; - std::array v; - CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); - } - { - std::string str = R"([1})"; - std::vector v; - CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); - - std::array arr; - CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); - } - - { - std::string str = R"([])"; - std::array arr; - iguana::from_json(arr, str); - } -} +// TEST_CASE("parse invalid array") { +// { +// std::string str = R"([1)"; +// std::vector v; +// CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); + +// std::array arr; +// CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); +// } +// { +// std::string str = R"([ )"; +// std::array v; +// CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); +// } +// { +// std::string str = R"([1})"; +// std::vector v; +// CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); + +// std::array arr; +// CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); +// } + +// { +// std::string str = R"([])"; +// std::array arr; +// iguana::from_json(arr, str); +// } +// } // TEST_CASE("parse some other char") { // std::string str = R"({"\name":"\tom", "ok":false})"; From 9932bd727fbd2040e48b3fb07aa07b5c75cbef48 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 12:35:25 +0800 Subject: [PATCH 14/34] parse invalid array 638->649 --- test/test.cpp | 92 +++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 76e04f79..ff426f52 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -633,52 +633,52 @@ TEST_CASE("parse num") { CHECK_THROWS_WITH(iguana::from_json(v1, str), "Failed to parse number"); } -// TEST_CASE("parse invalid array") { -// { -// std::string str = R"([1)"; -// std::vector v; -// CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); - -// std::array arr; -// CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); -// } -// { -// std::string str = R"([ )"; -// std::array v; -// CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); -// } -// { -// std::string str = R"([1})"; -// std::vector v; -// CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); - -// std::array arr; -// CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); -// } - -// { -// std::string str = R"([])"; -// std::array arr; -// iguana::from_json(arr, str); -// } -// } - -// TEST_CASE("parse some other char") { -// std::string str = R"({"\name":"\tom", "ok":false})"; -// person p; -// iguana::from_json(p, str); -// CHECK(p.name == "tom"); -// } - -// TEST_CASE("check some types") { -// using value_type = std::variant; -// constexpr auto map = iguana::get_iguana_struct_map(); -// static_assert(map.size() == 2); -// static_assert(map.at("x") == -// value_type{std::in_place_index_t<0>{}, &point_t::x}); -// static_assert(map.at("y") == -// value_type{std::in_place_index_t<1>{}, &point_t::y}); -// } +TEST_CASE("parse invalid array") { + { + std::string str = R"([1)"; + std::vector v; + CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); + + std::array arr; + CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); + } + { + std::string str = R"([ )"; + std::array v; + CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); + } + // { + // std::string str = R"([1})"; + // std::vector v; + // CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); + + // std::array arr; + // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); + // } + + // { + // std::string str = R"([])"; + // std::array arr; + // iguana::from_json(arr, str); + // } +} + +TEST_CASE("parse some other char") { + std::string str = R"({"\name":"\tom", "ok":false})"; + person p; + iguana::from_json(p, str); + CHECK(p.name == "tom"); +} + +TEST_CASE("check some types") { + using value_type = std::variant; + constexpr auto map = iguana::get_iguana_struct_map(); + static_assert(map.size() == 2); + static_assert(map.at("x") == + value_type{std::in_place_index_t<0>{}, &point_t::x}); + static_assert(map.at("y") == + value_type{std::in_place_index_t<1>{}, &point_t::y}); +} // doctest comments // 'function' : must be 'attribute' - see issue #182 From 6c43e7a297a0fb5f74f1fea409460c112053c7d5 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 13:35:38 +0800 Subject: [PATCH 15/34] 637->649 annotation --- test/test.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index ff426f52..30f37cbb 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -634,33 +634,33 @@ TEST_CASE("parse num") { } TEST_CASE("parse invalid array") { - { - std::string str = R"([1)"; - std::vector v; - CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); - - std::array arr; - CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); - } - { - std::string str = R"([ )"; - std::array v; - CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); - } // { - // std::string str = R"([1})"; - // std::vector v; - // CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); + // std::string str = R"([1)"; + // std::vector v; + // CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); // std::array arr; - // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); + // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); // } - // { - // std::string str = R"([])"; - // std::array arr; - // iguana::from_json(arr, str); + // std::string str = R"([ )"; + // std::array v; + // CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); // } + { + std::string str = R"([1})"; + std::vector v; + CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); + + std::array arr; + CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); + } + + { + std::string str = R"([])"; + std::array arr; + iguana::from_json(arr, str); + } } TEST_CASE("parse some other char") { From 78795df58fd43d1c1fbac04a02265be5ba2b6243 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 13:43:38 +0800 Subject: [PATCH 16/34] 637->663 anno --- test/test.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 30f37cbb..f41e79e6 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -647,20 +647,20 @@ TEST_CASE("parse invalid array") { // std::array v; // CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); // } - { - std::string str = R"([1})"; - std::vector v; - CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); + // { + // std::string str = R"([1})"; + // std::vector v; + // CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); - std::array arr; - CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); - } + // std::array arr; + // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); + // } - { - std::string str = R"([])"; - std::array arr; - iguana::from_json(arr, str); - } + // { + // std::string str = R"([])"; + // std::array arr; + // iguana::from_json(arr, str); + // } } TEST_CASE("parse some other char") { From a38acf5a3ff3937f45cf0d4c5d2855d04bc85e50 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 13:51:27 +0800 Subject: [PATCH 17/34] 650->663 anno --- test/test.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index f41e79e6..ff426f52 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -634,19 +634,19 @@ TEST_CASE("parse num") { } TEST_CASE("parse invalid array") { - // { - // std::string str = R"([1)"; - // std::vector v; - // CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); + { + std::string str = R"([1)"; + std::vector v; + CHECK_THROWS_WITH(iguana::from_json(v, str), "Expected ]"); - // std::array arr; - // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); - // } - // { - // std::string str = R"([ )"; - // std::array v; - // CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); - // } + std::array arr; + CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); + } + { + std::string str = R"([ )"; + std::array v; + CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); + } // { // std::string str = R"([1})"; // std::vector v; From decfb8a7630522aee810e3abcfceb31aec41cff7 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 14:32:08 +0800 Subject: [PATCH 18/34] 645->649 anno --- test/test.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index ff426f52..c7c05fba 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -642,11 +642,11 @@ TEST_CASE("parse invalid array") { std::array arr; CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); } - { - std::string str = R"([ )"; - std::array v; - CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); - } + // { + // std::string str = R"([ )"; + // std::array v; + // CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); + // } // { // std::string str = R"([1})"; // std::vector v; From 20e69952f53b6c755f3a0805b0b915726b24c312 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 14:45:09 +0800 Subject: [PATCH 19/34] spilt unexpected end --- test/test.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test.cpp b/test/test.cpp index c7c05fba..46dd377e 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -663,6 +663,15 @@ TEST_CASE("parse invalid array") { // } } +TEST_CASE("parse invalid array Unexpected end") +{ + { + std::string str = R"([ )"; + std::array v; + CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); + } +} + TEST_CASE("parse some other char") { std::string str = R"({"\name":"\tom", "ok":false})"; person p; From 54b2e010bc20fe28775aca91d103b865d7ecb1d4 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 14:54:54 +0800 Subject: [PATCH 20/34] spilt parse invalid array running error --- test/test.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/test.cpp b/test/test.cpp index 46dd377e..3b9f31a8 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -672,6 +672,18 @@ TEST_CASE("parse invalid array Unexpected end") } } +TEST_CASE("pase invalid array running error") +{ + { + std::string str = R"([1})"; + std::vector v; + CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); + + std::array arr; + CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); + } +} + TEST_CASE("parse some other char") { std::string str = R"({"\name":"\tom", "ok":false})"; person p; From 13a7179ab7fe48e15f957e65d52dcc2848345c49 Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 15:06:31 +0800 Subject: [PATCH 21/34] anno 682->683 --- test/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 3b9f31a8..a5f6d3cd 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -679,8 +679,8 @@ TEST_CASE("pase invalid array running error") std::vector v; CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); - std::array arr; - CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); + // std::array arr; + // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); } } From a87e900d0320895ee41ec379eab3ff8fc49a463d Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 15:38:14 +0800 Subject: [PATCH 22/34] anchor --- test/test.cpp | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index a5f6d3cd..0e77941b 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -642,38 +642,11 @@ TEST_CASE("parse invalid array") { std::array arr; CHECK_THROWS_WITH(iguana::from_json(arr, str), "Unexpected end"); } - // { - // std::string str = R"([ )"; - // std::array v; - // CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); - // } - // { - // std::string str = R"([1})"; - // std::vector v; - // CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); - - // std::array arr; - // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); - // } - - // { - // std::string str = R"([])"; - // std::array arr; - // iguana::from_json(arr, str); - // } -} - -TEST_CASE("parse invalid array Unexpected end") -{ { std::string str = R"([ )"; std::array v; CHECK_THROWS_WITH(iguana::from_json(v, str), "Unexpected end"); } -} - -TEST_CASE("pase invalid array running error") -{ { std::string str = R"([1})"; std::vector v; @@ -682,6 +655,12 @@ TEST_CASE("pase invalid array running error") // std::array arr; // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); } + + { + std::string str = R"([])"; + std::array arr; + iguana::from_json(arr, str); + } } TEST_CASE("parse some other char") { From f820697866cd2e54f27fa136835edc21010e7c4e Mon Sep 17 00:00:00 2001 From: kcwl <767899122@qq.com> Date: Tue, 6 Dec 2022 15:49:26 +0800 Subject: [PATCH 23/34] fix bus error --- test/test.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 0e77941b..2bc2c701 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -651,9 +651,11 @@ TEST_CASE("parse invalid array") { std::string str = R"([1})"; std::vector v; CHECK_THROWS_AS(iguana::from_json(v, str), std::runtime_error); - - // std::array arr; - // CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); + } + { + std::string str = R"([1}])"; + std::array arr; + CHECK_THROWS_WITH(iguana::from_json(arr, str), "Expected ]"); } { From 575a2232038509b054977352c56e007a05e54426 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 7 Dec 2022 14:28:04 +0800 Subject: [PATCH 24/34] catch more --- iguana/value.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/value.hpp b/iguana/value.hpp index 3e06a24b..47d599e5 100644 --- a/iguana/value.hpp +++ b/iguana/value.hpp @@ -73,6 +73,8 @@ struct basic_json_value } else { throw std::invalid_argument(it->second); } + } catch (...) { + throw std::invalid_argument("unknown exception"); } } From 497a3c294bf1ea83d2cbf9e334b8c4075fc92728 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 7 Dec 2022 15:09:53 +0800 Subject: [PATCH 25/34] add some log --- test/test.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/test.cpp b/test/test.cpp index 2bc2c701..5de283f1 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -207,7 +207,7 @@ TEST_CASE("test dom parse") { CHECK(sub_map.at("val").get() == 2.5); CHECK(val.is_object()); } - + std::cout << "test dom parse part 1 ok\n"; { std::string json_str = R"({"a": [1, 2, 3]})"; iguana::jvalue val1; @@ -223,6 +223,8 @@ TEST_CASE("test dom parse") { CHECK(val1.to_object().size() == 1); } + std::cout << "test dom parse part 2 ok\n"; + { std::string json_str = R"([0.5, 2.2, 3.3])"; iguana::jvalue val1; @@ -259,6 +261,8 @@ TEST_CASE("test dom parse") { get_value_test_helper(json_str, 709); } + + std::cout << "test get ok\n"; { std::string json_str = R"(-0.111)"; iguana::jvalue val1; @@ -318,6 +322,8 @@ TEST_CASE("test dom parse") { CHECK(!val1.is_string()); CHECK(val1.is_null()); } + + std::cout << "test dom parse ok\n"; } TEST_CASE("test simple object") { From 26f1f94dfbcd8ee4ab046e7a78beb49d2c5ada68 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 7 Dec 2022 15:26:52 +0800 Subject: [PATCH 26/34] init --- test/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.cpp b/test/test.cpp index 5de283f1..acbfb4c7 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -158,7 +158,7 @@ void get_value_test_helper(const std::string &json_str, const T &expect) { } TEST_CASE("test from issues") { - test test1; + test test1{}; std::string str1 = R"({"username1": "test", "password":test, "id": 10.1, "error": false})"; From 572f4da8d73196cd241b0fe96e17342d86f67e46 Mon Sep 17 00:00:00 2001 From: Courier Ma Date: Tue, 6 Dec 2022 23:17:50 +0800 Subject: [PATCH 27/34] add some testcase for coverage --- test/test.cpp | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index acbfb4c7..2b35f1ba 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -139,6 +139,9 @@ struct test_double_t { }; REFLECTION(test_double_t, val); +struct test_empty_t {}; +REFLECTION_EMPTY(test_empty_t); + struct test { std::string username; std::string password; @@ -551,6 +554,14 @@ TEST_CASE("test complicated object") { CHECK(obj.string == "Hello world"); } +TEST_CASE("test empty object") { + test_empty_t empty_obj; + + iguana::string_stream ss; + iguana::to_json(empty_obj, ss); + CHECK(ss == "{}"); +} + TEST_CASE("test non-reflectable object") { { std::tuple t{1, 3.14, std::string("iguana")}; @@ -593,17 +604,34 @@ TEST_CASE("test non-reflectable object") { } TEST_CASE("test file interface") { - std::string filename = "test.json"; - std::ofstream out(filename, std::ios::binary); - out.write(json0.data(), json0.size()); - out.close(); + namespace fs = std::filesystem; + { + std::string filename = "test.json"; + std::ofstream out(filename, std::ios::binary); + out.write(json0.data(), json0.size()); + out.close(); - json0_obj_t obj; - iguana::from_json_file(obj, filename); - CHECK(obj.number == 3.14); - CHECK(obj.string == "Hello world"); + json0_obj_t obj; + iguana::from_json_file(obj, filename); + CHECK(obj.number == 3.14); + CHECK(obj.string == "Hello world"); - std::filesystem::remove(filename); + fs::remove(filename); + } + { + fs::path p = "empty_file.bin"; + std::ofstream{p}; + std::cout << p << " size = " << fs::file_size(p) << '\n'; + test_empty_t empty_obj; + CHECK_THROWS_WITH(iguana::from_json_file(empty_obj, p.string()), + "empty file"); + + fs::remove(p); + } + { + test_empty_t empty_obj; + CHECK_THROWS(iguana::from_json_file(empty_obj, "/null")); + } } TEST_CASE("test view and byte interface") { @@ -692,4 +720,4 @@ TEST_CASE("check some types") { // 'function' : must be 'attribute' - see issue #182 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) int main(int argc, char **argv) { return doctest::Context(argc, argv).run(); } -DOCTEST_MSVC_SUPPRESS_WARNING_POP \ No newline at end of file +DOCTEST_MSVC_SUPPRESS_WARNING_POP From 6415819ef3fc51068184e64ed8a52f5ffabb19b4 Mon Sep 17 00:00:00 2001 From: Courier Ma Date: Tue, 6 Dec 2022 23:17:50 +0800 Subject: [PATCH 28/34] update some testcase --- test/test.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 2b35f1ba..8bc73a6c 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -203,9 +203,11 @@ TEST_CASE("test dom parse") { CHECK(val.at("ok") == true); std::error_code ec; - val.at("no such", ec); + CHECK(val.at("no such", ec) == false); CHECK(ec); + CHECK_THROWS_WITH(val.at("no ec"), "the key is unknown"); + auto sub_map = val.at("t"); CHECK(sub_map.at("val").get() == 2.5); CHECK(val.is_object()); @@ -229,7 +231,7 @@ TEST_CASE("test dom parse") { std::cout << "test dom parse part 2 ok\n"; { - std::string json_str = R"([0.5, 2.2, 3.3])"; + std::string json_str = R"([0.5, 2.2, 3.3, 4])"; iguana::jvalue val1; iguana::parse(val1, json_str.begin(), json_str.end()); auto &arr = std::get(val1); @@ -240,6 +242,13 @@ TEST_CASE("test dom parse") { val1.at(1, ec1); CHECK(ec1); std::cout << ec1.message() << "\n"; + + { + CHECK_THROWS_WITH(val1.at(9), "idx is out of range"); + std::error_code ec; + CHECK_NOTHROW(val1.at(-1, ec)); + CHECK(ec); + } CHECK(std::get(arr[0]) == 0.5); CHECK(std::get(arr[1]) == 2.2); @@ -247,8 +256,9 @@ TEST_CASE("test dom parse") { CHECK(val1.is_array()); const iguana::jarray &arr1 = val1.to_array(); - CHECK(arr1.size() == 3); + CHECK(arr1.size() == 4); CHECK(arr1[0].to_double() == 0.5); + CHECK(arr1[3].is_int()); std::error_code ec; CHECK_NOTHROW(val1.to_object(ec)); From f5097584f2a5f6769e6f684ac1dafbe92b0adc6d Mon Sep 17 00:00:00 2001 From: Courier Ma Date: Wed, 7 Dec 2022 22:33:43 +0800 Subject: [PATCH 29/34] format --- test/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.cpp b/test/test.cpp index 8bc73a6c..97a58fd2 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -242,7 +242,7 @@ TEST_CASE("test dom parse") { val1.at(1, ec1); CHECK(ec1); std::cout << ec1.message() << "\n"; - + { CHECK_THROWS_WITH(val1.at(9), "idx is out of range"); std::error_code ec; From f22a3fb046d00c5e878fcf72993411e2228ad763 Mon Sep 17 00:00:00 2001 From: Courier Ma Date: Fri, 9 Dec 2022 10:58:36 +0800 Subject: [PATCH 30/34] [fix] parse array contain empty object throw Expect:, --- iguana/json_reader.hpp | 12 ++++++++---- test/test.cpp | 12 +++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/iguana/json_reader.hpp b/iguana/json_reader.hpp index 820ee3df..0287ead3 100644 --- a/iguana/json_reader.hpp +++ b/iguana/json_reader.hpp @@ -627,8 +627,10 @@ template inline void parse_array(jarray &result, It &&it, It &&end) { skip_ws(it, end); match<'['>(it, end); - if (*it == ']') + if (*it == ']') [[unlikely]] { + ++it; return; + } while (true) { if (it == end) { break; @@ -637,20 +639,22 @@ inline void parse_array(jarray &result, It &&it, It &&end) { parse(result.back(), it, end); - if (*it == ']') { + if (*it == ']') [[unlikely]] { ++it; return; } match<','>(it, end); } + throw std::runtime_error("Expected ]"); } template inline void parse_object(jobject &result, It &&it, It &&end) { skip_ws(it, end); match<'{'>(it, end); - if (*it == '}') { + if (*it == '}') [[unlikely]] { + ++it; return; } @@ -671,7 +675,7 @@ inline void parse_object(jobject &result, It &&it, It &&end) { parse(emplaced.first->second, it, end); - if (*it == '}') { + if (*it == '}') [[unlikely]] { ++it; return; } diff --git a/test/test.cpp b/test/test.cpp index 97a58fd2..5cb67211 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -227,11 +227,16 @@ TEST_CASE("test dom parse") { CHECK(val1.is_object()); CHECK(val1.to_object().size() == 1); } + { + std::string json_str = R"({ "b": [{}, {"c":1}] })"; + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, json_str.begin(), json_str.end())); + } std::cout << "test dom parse part 2 ok\n"; { - std::string json_str = R"([0.5, 2.2, 3.3, 4])"; + std::string json_str = R"([0.5, 2.2, 3.3, 4, "6.7"])"; iguana::jvalue val1; iguana::parse(val1, json_str.begin(), json_str.end()); auto &arr = std::get(val1); @@ -253,10 +258,12 @@ TEST_CASE("test dom parse") { CHECK(std::get(arr[0]) == 0.5); CHECK(std::get(arr[1]) == 2.2); CHECK(std::get(arr[2]) == 3.3); + // could arr elems be different type? + CHECK(std::get(arr[4]) == "6.7"); CHECK(val1.is_array()); const iguana::jarray &arr1 = val1.to_array(); - CHECK(arr1.size() == 4); + CHECK(arr1.size() == 5); CHECK(arr1[0].to_double() == 0.5); CHECK(arr1[3].is_int()); @@ -631,7 +638,6 @@ TEST_CASE("test file interface") { { fs::path p = "empty_file.bin"; std::ofstream{p}; - std::cout << p << " size = " << fs::file_size(p) << '\n'; test_empty_t empty_obj; CHECK_THROWS_WITH(iguana::from_json_file(empty_obj, p.string()), "empty file"); From 6c3f77aa9547c83088d1f238536c93573fec5e01 Mon Sep 17 00:00:00 2001 From: Courier Ma Date: Fri, 9 Dec 2022 10:59:34 +0800 Subject: [PATCH 31/34] parse support View as para --- iguana/json_reader.hpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/iguana/json_reader.hpp b/iguana/json_reader.hpp index 0287ead3..a9a69746 100644 --- a/iguana/json_reader.hpp +++ b/iguana/json_reader.hpp @@ -464,7 +464,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { match<'"'>(it, end); } -inline void skip_object_value(auto &&it, auto &&end) { +IGUANA_INLINE void skip_object_value(auto &&it, auto &&end) { skip_ws(it, end); while (it != end) { switch (*it) { @@ -624,7 +624,7 @@ IGUANA_INLINE void from_json(T &value, const Byte *data, size_t size, template void parse(jvalue &result, It &&it, It &&end); template -inline void parse_array(jarray &result, It &&it, It &&end) { +IGUANA_INLINE void parse_array(jarray &result, It &&it, It &&end) { skip_ws(it, end); match<'['>(it, end); if (*it == ']') [[unlikely]] { @@ -650,7 +650,7 @@ inline void parse_array(jarray &result, It &&it, It &&end) { } template -inline void parse_object(jobject &result, It &&it, It &&end) { +IGUANA_INLINE void parse_object(jobject &result, It &&it, It &&end) { skip_ws(it, end); match<'{'>(it, end); if (*it == '}') [[unlikely]] { @@ -684,7 +684,8 @@ inline void parse_object(jobject &result, It &&it, It &&end) { } } -template inline void parse(jvalue &result, It &&it, It &&end) { +template +IGUANA_INLINE void parse(jvalue &result, It &&it, It &&end) { skip_ws(it, end); switch (*it) { case 'n': @@ -736,7 +737,8 @@ template inline void parse(jvalue &result, It &&it, It &&end) { } template -inline void parse(jvalue &result, It &&it, It &&end, std::error_code &ec) { +IGUANA_INLINE void parse(jvalue &result, It &&it, It &&end, + std::error_code &ec) { try { parse(result, it, end); ec = {}; @@ -746,6 +748,22 @@ inline void parse(jvalue &result, It &&it, It &&end, std::error_code &ec) { } } +template +IGUANA_INLINE void parse(T &result, const View &view) { + parse(result, std::begin(view), std::end(view)); +} + +template +IGUANA_INLINE void parse(T &result, const View &view, + std::error_code &ec) noexcept { + try { + parse(result, view); + ec = {}; + } catch (std::runtime_error &e) { + ec = iguana::make_error_code(e.what()); + } +} + template IGUANA_INLINE void from_json(T &value, It &&it, It &&end) { static_assert(!sizeof(T), "The type is not support, please check if you have " From 8d42f4cb37f4663b1960a43113ac9a814cc62bf5 Mon Sep 17 00:00:00 2001 From: Courier Ma Date: Fri, 9 Dec 2022 12:53:47 +0800 Subject: [PATCH 32/34] add testcase for dom parse file --- iguana/value.hpp | 2 + test/test_json_files.cpp | 119 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/iguana/value.hpp b/iguana/value.hpp index 47d599e5..d11f028f 100644 --- a/iguana/value.hpp +++ b/iguana/value.hpp @@ -6,6 +6,8 @@ #include #include +#include "error_code.h" + namespace iguana { #define GCC_COMPILER (defined(__GNUC__) && !defined(__clang__)) diff --git a/test/test_json_files.cpp b/test/test_json_files.cpp index c21a3b98..1cf61a10 100644 --- a/test/test_json_files.cpp +++ b/test/test_json_files.cpp @@ -3,6 +3,7 @@ #include #include "iguana/reflection.hpp" +#include "iguana/value.hpp" #define DOCTEST_CONFIG_IMPLEMENT #include #include @@ -40,6 +41,18 @@ TEST_CASE("test canada.json") { FeatureCollection p; iguana::from_json(p, test_str); std::cout << p.type << "\n"; + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, test_str.begin(), test_str.end())); + + auto &&features = val.at("features"); + CHECK(features.size() == 1); + CHECK(features[0].is_object()); + auto &&feature = features[0].get(); + auto &&geometry = feature["geometry"].to_object(); + CHECK(geometry["coordinates"].is_array()); + auto &&coors = geometry["coordinates"].to_array(); + CHECK(coors.size() == 1); } FeatureCollection t; @@ -54,7 +67,17 @@ TEST_CASE("test apache_builds.json") { for (auto &v : t.views) { std::cout << v.name << ", " << v.url << "\n"; } + { + auto &&content = iguana::json_file_content("../data/apache_builds.json"); + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, content)); + CHECK(val.at("numExecutors") == 0); + auto &&arr = val.at(("jobs")); + CHECK(arr.size() == 875); + } } + TEST_CASE("test numbers.json") { { std::string test_str = R"( @@ -91,12 +114,49 @@ TEST_CASE("test numbers.json") { } if (std::filesystem::exists(jsonName)) std::filesystem::remove(jsonName); + + { + auto &&content = iguana::json_file_content("../data/numbers.json"); + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, content)); + CHECK(val.to_array().size() == numbers.size()); + } } TEST_CASE("test citm_catalog.json") { citm_object_t t; iguana::from_json_file(t, "../data/citm_catalog.json"); CHECK(t.venueNames.value().PLEYEL_PLEYEL == "Salle Pleyel"); + + { + std::string test_str = R"({ + "events": { + "138586341": { + "description": null, + "id": 138586341, + "logo": null, + "name": "30th Anniversary Tour", + "subTopicIds": [ + 337184269, + 337184283 + ], + "subjectCode": null, + "subtitle": null, + "topicIds": [ + 324846099, + 107888604 + ] + } + } + })"; + + auto &&content = iguana::json_file_content("../data/citm_catalog.json"); + + iguana::jvalue val; + iguana::parse(val, content); + CHECK(val.at("performances").size() == 243); + } } TEST_CASE("test gsoc-2018.json") { @@ -105,12 +165,31 @@ TEST_CASE("test gsoc-2018.json") { auto last = std::rbegin(t); CHECK(last->second.author.type == "Person"); CHECK(last->second.author.name == "Oleg Serikov"); + + { + auto &&content = iguana::json_file_content("../data/gsoc-2018.json"); + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, content)); + auto &&map = val.to_object(); + auto &&last = map.rbegin(); + CHECK(last->second.at("@type") == "SoftwareSourceCode"); + } } TEST_CASE("test mesh.pretty.json") { mesh_t t; iguana::from_json_file(t, "../data/mesh.pretty.json"); CHECK(t.tex0.back() == 0); + + { + auto &&content = iguana::json_file_content("../data/mesh.pretty.json"); + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, content)); + auto arr = val.at("positions"); + CHECK(arr.back().is_number()); + } } TEST_CASE("test random.json") { @@ -118,6 +197,17 @@ TEST_CASE("test random.json") { iguana::from_json_file(t, "../data/random.json"); CHECK(t.result.back().id == 1000); CHECK(t.result.back().age == 32); + + { + auto &&content = iguana::json_file_content("../data/random.json"); + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, content)); + auto &&arr = val.at("result"); + CHECK(arr.back().is_object()); + auto &&res = arr.back().to_object(); + CHECK(res.at("admin").is_bool()); + } } TEST_CASE("test github_events.json") { @@ -177,6 +267,17 @@ TEST_CASE("test github_events.json") { } std::vector events; iguana::from_json_file(events, "../data/github_events.json"); + + { + auto &&content = iguana::json_file_content("../data/github_events.json"); + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, content)); + auto &&arr = val.to_array(); + auto &&last = arr.rbegin(); + auto &&actor = last->at("actor"); + CHECK(!actor["id"].is_double()); + } } TEST_CASE("test marine_ik.json") { @@ -188,12 +289,30 @@ TEST_CASE("test marine_ik.json") { CHECK(t.object.children[0].matrix[0] == 1); CHECK(t.geometries[0].uuid == "C5CA037C-30C8-3A8C-9678-8A4BF32D5D85"); + + { + auto &&content = iguana::json_file_content("../data/marine_ik.json"); + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, content)); + auto &&meta = val.at("metadata"); + CHECK(meta["version"].to_double() == 4.4); + } } TEST_CASE("test instruments.json") { instruments_t t; iguana::from_json_file(t, "../data/instruments.json"); CHECK(t.name == "epanos"); + + { + auto &&content = iguana::json_file_content("../data/instruments.json"); + + iguana::jvalue val; + CHECK_NOTHROW(iguana::parse(val, content)); + auto &&patterns = val.at("patterns"); + CHECK(patterns[0].to_object().at("data").is_null()); + } } // doctest comments From 240146bcaaf002b6d55001378ca24f30334b91bc Mon Sep 17 00:00:00 2001 From: qicosmos Date: Sat, 10 Dec 2022 09:28:47 +0800 Subject: [PATCH 33/34] inline --- iguana/json_reader.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/json_reader.hpp b/iguana/json_reader.hpp index a9a69746..b1350711 100644 --- a/iguana/json_reader.hpp +++ b/iguana/json_reader.hpp @@ -621,7 +621,8 @@ IGUANA_INLINE void from_json(T &value, const Byte *data, size_t size, } } -template void parse(jvalue &result, It &&it, It &&end); +template +IGUANA_INLINE void parse(jvalue &result, It &&it, It &&end); template IGUANA_INLINE void parse_array(jarray &result, It &&it, It &&end) { From d581832409791cc43bd02e521f4221bd43359bb7 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Sat, 10 Dec 2022 09:36:03 +0800 Subject: [PATCH 34/34] inline --- iguana/json_reader.hpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/iguana/json_reader.hpp b/iguana/json_reader.hpp index b1350711..24f7b3c9 100644 --- a/iguana/json_reader.hpp +++ b/iguana/json_reader.hpp @@ -621,11 +621,10 @@ IGUANA_INLINE void from_json(T &value, const Byte *data, size_t size, } } -template -IGUANA_INLINE void parse(jvalue &result, It &&it, It &&end); +template void parse(jvalue &result, It &&it, It &&end); template -IGUANA_INLINE void parse_array(jarray &result, It &&it, It &&end) { +inline void parse_array(jarray &result, It &&it, It &&end) { skip_ws(it, end); match<'['>(it, end); if (*it == ']') [[unlikely]] { @@ -651,7 +650,7 @@ IGUANA_INLINE void parse_array(jarray &result, It &&it, It &&end) { } template -IGUANA_INLINE void parse_object(jobject &result, It &&it, It &&end) { +inline void parse_object(jobject &result, It &&it, It &&end) { skip_ws(it, end); match<'{'>(it, end); if (*it == '}') [[unlikely]] { @@ -685,8 +684,7 @@ IGUANA_INLINE void parse_object(jobject &result, It &&it, It &&end) { } } -template -IGUANA_INLINE void parse(jvalue &result, It &&it, It &&end) { +template inline void parse(jvalue &result, It &&it, It &&end) { skip_ws(it, end); switch (*it) { case 'n': @@ -738,8 +736,7 @@ IGUANA_INLINE void parse(jvalue &result, It &&it, It &&end) { } template -IGUANA_INLINE void parse(jvalue &result, It &&it, It &&end, - std::error_code &ec) { +inline void parse(jvalue &result, It &&it, It &&end, std::error_code &ec) { try { parse(result, it, end); ec = {}; @@ -750,13 +747,12 @@ IGUANA_INLINE void parse(jvalue &result, It &&it, It &&end, } template -IGUANA_INLINE void parse(T &result, const View &view) { +inline void parse(T &result, const View &view) { parse(result, std::begin(view), std::end(view)); } template -IGUANA_INLINE void parse(T &result, const View &view, - std::error_code &ec) noexcept { +inline void parse(T &result, const View &view, std::error_code &ec) noexcept { try { parse(result, view); ec = {};