|
|
@@ -25,6 +25,11 @@ using std::operator""s;
|
|
|
using std::operator""sv;
|
|
|
using namespace magic_enum::bitwise_operators;
|
|
|
|
|
|
+using testing::Field;
|
|
|
+using testing::IsNull;
|
|
|
+using testing::NotNull;
|
|
|
+using testing::Pointee;
|
|
|
+
|
|
|
enum class Color { RED, BLUE, GREEN };
|
|
|
enum class Mask { LEFT = 1, RIGHT = 2 };
|
|
|
|
|
|
@@ -72,12 +77,94 @@ TEST(JsonizerTest, ParsesCollection) {
|
|
|
EXPECT_ROUNDTRIP(izer, std::set({1, 2, 3, 1}), "[1, 2, 3]"_json);
|
|
|
}
|
|
|
|
|
|
+TEST(JsonizerTest, ThrowsOnParsingCollectionFromNonArray) {
|
|
|
+ serializer::Jsonizer izer;
|
|
|
+ std::vector<int> out;
|
|
|
+ EXPECT_THROW(izer.from_json(out, "1"_json), std::invalid_argument);
|
|
|
+}
|
|
|
+
|
|
|
TEST(JsonizerTest, ParsesAssociative) {
|
|
|
serializer::Jsonizer izer;
|
|
|
EXPECT_ROUNDTRIP(izer, (std::map<int, int>{{1, 2}, {3, 1}}),
|
|
|
"{\"1\":2, \"3\":1}"_json);
|
|
|
+}
|
|
|
+
|
|
|
+TEST(JsonizerTest, AssociativeCanParseFromPairListOrObject) {
|
|
|
+ using Type = std::map<std::string, int>;
|
|
|
+ serializer::Jsonizer izer;
|
|
|
+
|
|
|
+ EXPECT_THAT(izer.from_json<Type>("[[\"A\", 2], [\"B\", 1]]"_json),
|
|
|
+ (Type{{"A", 2}, {"B", 1}}));
|
|
|
+
|
|
|
+ EXPECT_THAT(izer.from_json<Type>("{ \"A\": 2, \"B\": 1 }"_json),
|
|
|
+ (Type{{"A", 2}, {"B", 1}}));
|
|
|
+}
|
|
|
+
|
|
|
+TEST(JsonizerTest, AssociativeWithNonTrivialKeyIsPairList) {
|
|
|
+ using Type = std::map<std::pair<int, int>, int>;
|
|
|
+ serializer::Jsonizer izer;
|
|
|
+ EXPECT_ROUNDTRIP(izer, (Type{{{1, 2}, 1}, {{2, 1}, 2}}),
|
|
|
+ "[[[1, 2], 1], [[2, 1], 2]]"_json);
|
|
|
+}
|
|
|
+
|
|
|
+TEST(JsonizerTest, ThrowsOnParsingAssociativeFromNonCollection) {
|
|
|
+ serializer::Jsonizer izer;
|
|
|
+ std::map<int, int> out;
|
|
|
+ EXPECT_THROW(izer.from_json(out, "1"_json), std::invalid_argument);
|
|
|
+}
|
|
|
+
|
|
|
+struct Cacheable {
|
|
|
+ std::string name;
|
|
|
+};
|
|
|
|
|
|
- std::map<int, int> ex;
|
|
|
- izer.from_json(ex, "[[1, 2], [3, 1]]"_json);
|
|
|
- EXPECT_THAT(ex, (std::map<int, int>{{1, 2}, {3, 1}}));
|
|
|
+template <>
|
|
|
+void serializer::Jsonizer::from_json(Cacheable & value,
|
|
|
+ Json::Value const & json) const {
|
|
|
+ from_json(value.name, json["name"]);
|
|
|
+}
|
|
|
+
|
|
|
+TEST(JsonizerTest, CanAttemptToLoadFromCache) {
|
|
|
+ serializer::Jsonizer izer;
|
|
|
+ std::shared_ptr<Cacheable const> ptr;
|
|
|
+
|
|
|
+ EXPECT_THROW(izer.from_json(ptr, "\"ONE\""_json), std::domain_error);
|
|
|
+ EXPECT_THAT(ptr, IsNull());
|
|
|
+
|
|
|
+ EXPECT_NO_THROW(izer.from_json(ptr, "{\"name\":\"ONE\"}"_json));
|
|
|
+ EXPECT_THAT(ptr, NotNull());
|
|
|
+ EXPECT_THAT(ptr, Pointee(Field(&Cacheable::name, "ONE")));
|
|
|
+}
|
|
|
+
|
|
|
+struct Serializable {
|
|
|
+ using serial_type = std::map<int, int>;
|
|
|
+
|
|
|
+ Serializable(std::vector<int> value = {}) : value(value) {}
|
|
|
+
|
|
|
+ Serializable(serial_type vals) {
|
|
|
+ for (auto [k, v] : vals) {
|
|
|
+ while (v--) {
|
|
|
+ value.push_back(k);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ operator serial_type() const {
|
|
|
+ serial_type rval;
|
|
|
+ for (auto v : value) {
|
|
|
+ ++rval[v];
|
|
|
+ }
|
|
|
+ return rval;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<int> value;
|
|
|
+};
|
|
|
+
|
|
|
+bool operator==(Serializable const & lhs, Serializable const & rhs) {
|
|
|
+ return lhs.value == rhs.value;
|
|
|
+}
|
|
|
+
|
|
|
+TEST(JsonizerTest, CanConstructFromAltType) {
|
|
|
+ serializer::Jsonizer izer;
|
|
|
+ EXPECT_ROUNDTRIP(izer, Serializable({1, 1, 1, 1, 2, 2, 2, 3, 3, 4}),
|
|
|
+ "{\"1\":4, \"2\":3, \"3\":2, \"4\":1}"_json);
|
|
|
}
|