704 lines
19 KiB
C++
704 lines
19 KiB
C++
|
#include "StarJson.hpp"
|
||
|
#include "StarFile.hpp"
|
||
|
#include "StarJsonPatch.hpp"
|
||
|
#include "StarJsonPath.hpp"
|
||
|
|
||
|
#include "gtest/gtest.h"
|
||
|
|
||
|
using namespace Star;
|
||
|
|
||
|
TEST(JsonTest, ImplicitSharing) {
|
||
|
Json map1 = JsonObject{{"foo", 1}, {"bar", 10}};
|
||
|
|
||
|
Json map2 = JsonObject{{"foo", 5}, {"bar", 50}};
|
||
|
|
||
|
std::swap(map1, map2);
|
||
|
Json map3 = map1;
|
||
|
map1 = map2;
|
||
|
map2 = map3;
|
||
|
|
||
|
EXPECT_EQ(map1.get("foo"), 1);
|
||
|
EXPECT_EQ(map2.get("bar"), 50);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, Defaults) {
|
||
|
Json obj = JsonObject{{"null", Json()}};
|
||
|
Json arr = JsonArray{"array", JsonArray{Json(), Json()}};
|
||
|
|
||
|
EXPECT_EQ(obj.getInt("null", 5), 5);
|
||
|
EXPECT_EQ(arr.getInt(2, 5), 5);
|
||
|
EXPECT_EQ(arr.getInt(3, 5), 5);
|
||
|
EXPECT_THROW(arr.getInt(2), JsonException);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, Merging) {
|
||
|
JsonObject a{{"I", "feel"}, {"friendly", "now"}};
|
||
|
JsonObject b{{"hello", "there"}, {"leg", "friend"}};
|
||
|
JsonObject c{{"hello", "you"}, {"leg", "fiend"}};
|
||
|
JsonObject d{{"goodbye", "you"}, {"friendly", "leg"}};
|
||
|
|
||
|
Json merged = jsonMerge(a, b, c, d);
|
||
|
|
||
|
EXPECT_EQ(merged.get("I"), "feel");
|
||
|
EXPECT_EQ(merged.get("hello"), "you");
|
||
|
EXPECT_EQ(merged.get("friendly"), "leg");
|
||
|
EXPECT_EQ(merged.get("leg"), "fiend");
|
||
|
|
||
|
Json e = JsonObject();
|
||
|
e = e.set("1", 2);
|
||
|
e = e.setAll({{"a", "b"}, {"c", "d"}});
|
||
|
Json f = JsonObject{{"1", 2}, {"a", "b"}, {"c", "d"}};
|
||
|
|
||
|
EXPECT_EQ(e, f);
|
||
|
|
||
|
Json g = JsonObject{{"a", "a"}, {"sub", JsonObject()}};
|
||
|
g = g.setPath("sub.field", 1);
|
||
|
g = g.setPath("sub.field2", 2);
|
||
|
g = g.erasePath("sub.field2");
|
||
|
Json h = JsonObject{{"a", "a"}, {"sub", JsonObject{{"field", 1}}}};
|
||
|
EXPECT_EQ(g, h);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, Unicode) {
|
||
|
Json v = Json::parse("{ \"first\" : \"日本語\", \"second\" : \"foobar\\u0019\" }");
|
||
|
EXPECT_EQ(v.getString("first"), String("日本語"));
|
||
|
EXPECT_EQ(v.get("second").repr(), String("\"foobar\\u0019\""));
|
||
|
|
||
|
String json = v.printJson();
|
||
|
Json v2 = Json::parseJson(json);
|
||
|
EXPECT_EQ(v2.getString("first"), String("日本語"));
|
||
|
|
||
|
EXPECT_EQ(v, v2);
|
||
|
|
||
|
EXPECT_EQ(Json("😀"), Json::parse("\"\\ud83d\\ude00\""));
|
||
|
EXPECT_EQ(Json::parse("\"\\ud83d\\ude00\"").toString().size(), 1u);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, UnicodeFile) {
|
||
|
Json v = Json::parse("{ \"first\" : \"日本語\", \"second\" : \"foobar\\u0019\" }");
|
||
|
EXPECT_EQ(v.getString("first"), String("日本語"));
|
||
|
EXPECT_EQ(v.get("second").repr(), String("\"foobar\\u0019\""));
|
||
|
|
||
|
String file = File::temporaryFileName();
|
||
|
auto finallyGuard = finally([&file]() { File::remove(file); });
|
||
|
|
||
|
File::writeFile(v.printJson(), file);
|
||
|
Json v2 = Json::parseJson(File::readFileString(file));
|
||
|
EXPECT_EQ(v2.getString("first"), "日本語");
|
||
|
|
||
|
EXPECT_EQ(v, v2);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, JsonParsingEdge) {
|
||
|
auto isValidFragment = [](String const& json) -> bool {
|
||
|
try {
|
||
|
Json::parse(json);
|
||
|
return true;
|
||
|
} catch (JsonParsingException const&) {
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
auto isValidJson = [](String const& json) -> bool {
|
||
|
try {
|
||
|
Json::parseJson(json);
|
||
|
return true;
|
||
|
} catch (JsonParsingException const&) {
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
EXPECT_TRUE(isValidFragment(" \t 0.0 "));
|
||
|
EXPECT_TRUE(isValidFragment("-0.0\t "));
|
||
|
EXPECT_FALSE(isValidFragment("-.0"));
|
||
|
EXPECT_FALSE(isValidFragment("00.0"));
|
||
|
|
||
|
EXPECT_FALSE(isValidJson(" 0.0"));
|
||
|
EXPECT_FALSE(isValidJson("true"));
|
||
|
EXPECT_TRUE(isValidJson("\t[]"));
|
||
|
EXPECT_TRUE(isValidJson(" {} "));
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, Types) {
|
||
|
Json v;
|
||
|
EXPECT_EQ(v.type(), Json::Type::Null);
|
||
|
v = 0;
|
||
|
EXPECT_EQ(v.type(), Json::Type::Int);
|
||
|
v = 0.0;
|
||
|
EXPECT_EQ(v.type(), Json::Type::Float);
|
||
|
v = true;
|
||
|
EXPECT_EQ(v.type(), Json::Type::Bool);
|
||
|
v = "";
|
||
|
EXPECT_EQ(v.type(), Json::Type::String);
|
||
|
v = JsonArray();
|
||
|
EXPECT_EQ(v.type(), Json::Type::Array);
|
||
|
v = JsonObject();
|
||
|
EXPECT_EQ(v.type(), Json::Type::Object);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, Query) {
|
||
|
Json v = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "bar",
|
||
|
"baz" : {
|
||
|
"baf" : [1, 2],
|
||
|
"bal" : 2
|
||
|
},
|
||
|
|
||
|
"baf" : null
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
EXPECT_EQ(v.query("foo"), Json("bar"));
|
||
|
EXPECT_EQ(v.query("baz.baf[1]"), Json(2));
|
||
|
EXPECT_EQ(v.query("baz.bal"), Json(2));
|
||
|
EXPECT_EQ(v.query("blargh", Json("default")), Json("default"));
|
||
|
EXPECT_EQ(v.query("blargh", Json("default")), Json("default"));
|
||
|
EXPECT_EQ(v.query("baz.baf[3]", Json("default")), Json("default"));
|
||
|
EXPECT_EQ(v.query("baz.bal[0]", Json("default")), Json("default"));
|
||
|
EXPECT_EQ(v.query("baz[1]", Json("default")), Json("default"));
|
||
|
EXPECT_EQ(v.query("baz.bal.a", Json("default")), Json("default"));
|
||
|
EXPECT_EQ(v.query("baz[0]", Json("default")), Json("default"));
|
||
|
EXPECT_EQ(v.query("baz.baf.a", Json("default")), Json("default"));
|
||
|
EXPECT_THROW(v.query("blargh"), JsonPath::TraversalException);
|
||
|
EXPECT_THROW(v.query("baz.funk"), JsonPath::TraversalException);
|
||
|
EXPECT_THROW(v.query("baz.baf[3]"), JsonPath::TraversalException);
|
||
|
EXPECT_THROW(v.query("baz.baf[whee]", Json()), JsonPath::ParsingException);
|
||
|
EXPECT_THROW(v.query("baz.baf[[]", Json()), JsonPath::ParsingException);
|
||
|
EXPECT_THROW(v.query("baz..baf", Json()), JsonPath::ParsingException);
|
||
|
EXPECT_THROW(v.query("baf.nothing"), JsonException);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, PatchingAdd) {
|
||
|
Json before = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "bar",
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bal" : 2
|
||
|
},
|
||
|
"rab" : [0, 1, 2, "foo", false]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json after = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "xyzzy",
|
||
|
"bar" : "foo",
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bal" : 2,
|
||
|
"0" : "derp",
|
||
|
"rebar" : {
|
||
|
"after" : "party"
|
||
|
}
|
||
|
},
|
||
|
"rab" : [0, 0, 1, 2, "foo", false, true, { "baz" : "bar"} ]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json patch = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "add", "path" : "/foo", "value" : "xyzzy"},
|
||
|
{"op" : "add", "path" : "/bar", "value" : "foo"},
|
||
|
{"op" : "add", "path" : "/baz/rebar", "value" : {}},
|
||
|
{"op" : "add", "path" : "/baz/rebar/after", "value" : "party"},
|
||
|
{"op" : "add", "path" : "/baz/0", "value" : "derp"},
|
||
|
{"op" : "add", "path" : "/rab/0", "value" : 0},
|
||
|
{"op" : "add", "path" : "/rab/6", "value" : true},
|
||
|
{"op" : "add", "path" : "/rab/-", "value" : {"baz" : "bar"} }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Past end of list
|
||
|
Json badPatch1 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "add", "path" : "/rab/6", "value" : {"baz" : "bar"} }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Parent does not exist, map
|
||
|
Json badPatch2 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "add", "path" : "/bar/baz", "value" : {"baz" : "bar"} }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Parent does not exist, list
|
||
|
Json badPatch3 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "add", "path" : "/bar/0", "value" : {"baz" : "bar"} }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
EXPECT_EQ(jsonPatch(before, patch.toArray()), after);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch1.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch2.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch3.toArray()), JsonPatchException);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, PatchingRemove) {
|
||
|
Json before = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "xyzzy",
|
||
|
"bar" : "foo",
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bal" : 2,
|
||
|
"rebar" : true
|
||
|
},
|
||
|
"rab" : [0, 0, 1, 2, "foo", false, {"baz" : "bar"} ]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json after = Json::parse(R"JSON(
|
||
|
{
|
||
|
"bar" : "foo",
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bal" : 2
|
||
|
},
|
||
|
"rab" : [0, 1, 2, "foo", false]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json patch = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "remove", "path" : "/foo"},
|
||
|
{"op" : "remove", "path" : "/baz/rebar"},
|
||
|
{"op" : "remove", "path" : "/rab/0"},
|
||
|
{"op" : "remove", "path" : "/rab/5"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Removing end of list
|
||
|
Json badPatch1 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "remove", "path" : "/rab/-"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Removing past end of list
|
||
|
Json badPatch2 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "add", "path" : "/rab/7"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Path wrong type
|
||
|
Json badPatch3 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "remove", "path" : "/bar/baz"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
EXPECT_EQ(jsonPatch(before, patch.toArray()), after);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch1.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch2.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch3.toArray()), JsonPatchException);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, PatchingReplace) {
|
||
|
Json before = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "bar",
|
||
|
"bar" : {
|
||
|
"baf" : 1,
|
||
|
"bal" : 2
|
||
|
},
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bal" : 2
|
||
|
},
|
||
|
"rab" : [0, 1, 2, "foo", false],
|
||
|
"rabby" : [0, 1, 2, "foo", false]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json after = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "xyzzy",
|
||
|
"bar" : [3, 2, 1, "contact"],
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bal" : "touched"
|
||
|
},
|
||
|
"rab" : [{"omg" : "no"}, 1, 2, "foo", false],
|
||
|
"rabby" : false
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json patch = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "replace", "path" : "/foo", "value" : "xyzzy"},
|
||
|
{"op" : "replace", "path" : "/bar", "value" : [3, 2, 1, "contact"]},
|
||
|
{"op" : "replace", "path" : "/baz/bal", "value" : "touched"},
|
||
|
{"op" : "replace", "path" : "/rab/0", "value" : {"omg" : "yes"}},
|
||
|
{"op" : "replace", "path" : "/rab/0/omg", "value" : "no"},
|
||
|
{"op" : "replace", "path" : "/rab/2", "value" : 2},
|
||
|
{"op" : "replace", "path" : "/rabby", "value" : false}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// End of list
|
||
|
Json badPatch1 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "replace", "path" : "/rab/-", "value" : {"baz" : "bar"} }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Past end of list
|
||
|
Json badPatch2 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "replace", "path" : "/rab/5", "value" : {"baz" : "bar"} }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Key does not exist
|
||
|
Json badPatch3 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "replace", "path" : "/bar/baz", "value" : {"baz" : "bar"} }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
EXPECT_EQ(jsonPatch(before, patch.toArray()), after);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch1.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch2.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch3.toArray()), JsonPatchException);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, PatchingMove) {
|
||
|
Json before = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "bar",
|
||
|
"bar" : [1, 2, 3, "contact"],
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bar" : 2
|
||
|
},
|
||
|
"rab" : [0, 1, 2, "foo", false],
|
||
|
"rabby" : [0, 1, 2, "foo", true]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json after = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foot" : "bar",
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bar" : [3, 2, 1, "contact"]
|
||
|
},
|
||
|
"bar" : 2,
|
||
|
"rab" : [0, 1, 2, true, "foo"]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json patch = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "move", "from" : "/foo", "path" : "/foot"},
|
||
|
{"op" : "move", "from" : "/bar", "path" : "/baz/bal"},
|
||
|
{"op" : "move", "from" : "/baz/bar", "path" : "/bar"},
|
||
|
{"op" : "move", "from" : "/baz/bal", "path" : "/baz/bar"},
|
||
|
{"op" : "move", "from" : "/baz/bar/0", "path" : "/baz/bar/1"},
|
||
|
{"op" : "move", "from" : "/baz/bar/2", "path" : "/baz/bar/0"},
|
||
|
{"op" : "move", "from" : "/rabby", "path" : "/rab"},
|
||
|
{"op" : "move", "from" : "/rab/3", "path" : "/rab/-"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// From end of list
|
||
|
Json badPatch1 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "move", "from" : "/rab/-", "path" : "/doesnotmatter"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// From past end of list
|
||
|
Json badPatch2 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "move", "from" : "/rab/5", "path" : "/doesnotmatter"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// To past end of list
|
||
|
Json badPatch3 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "move", "from" : "/rab/0", "path" : "/rab/5"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Source path does not exist
|
||
|
Json badPatch4 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "move", "from" : "/omgomg", "path" : "/doesntmatter"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Dest path wrong type
|
||
|
Json badPatch5 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "move", "from" : "/baz/bar", "path" : "/rabby/bar"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
EXPECT_EQ(jsonPatch(before, patch.toArray()), after);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch1.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch2.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch3.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch4.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch5.toArray()), JsonPatchException);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, PatchingCopy) {
|
||
|
Json before = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "bar",
|
||
|
"foot" : "bar",
|
||
|
"bar" : [1, 2, 3, "contact"],
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bar" : 2
|
||
|
},
|
||
|
"rab" : [0, 1, 2, "foo", false],
|
||
|
"rabby" : [0, 1, 2, "foo", true]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json after = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "bar",
|
||
|
"foot" : "bar",
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bar" : [2, 1, 1, 2, 3, "contact"],
|
||
|
"bal" : [1, 2, 3, "contact"]
|
||
|
},
|
||
|
"bar" : 2,
|
||
|
"rab" : [0, 1, 2, "foo", true, "foo"],
|
||
|
"rabby" : [0, 1, 2, "foo", true]
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json patch = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "copy", "from" : "/foo", "path" : "/foot"},
|
||
|
{"op" : "copy", "from" : "/bar", "path" : "/baz/bal"},
|
||
|
{"op" : "copy", "from" : "/baz/bar", "path" : "/bar"},
|
||
|
{"op" : "copy", "from" : "/baz/bal", "path" : "/baz/bar"},
|
||
|
{"op" : "copy", "from" : "/baz/bar/0", "path" : "/baz/bar/1"},
|
||
|
{"op" : "copy", "from" : "/baz/bar/2", "path" : "/baz/bar/0"},
|
||
|
{"op" : "copy", "from" : "/rabby", "path" : "/rab"},
|
||
|
{"op" : "copy", "from" : "/rab/3", "path" : "/rab/-"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// From end of list
|
||
|
Json badPatch1 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "copy", "from" : "/rab/-", "path" : "/doesnotmatter"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// From past end of list
|
||
|
Json badPatch2 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "copy", "from" : "/rab/5", "path" : "/doesnotmatter"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// To past end of list
|
||
|
Json badPatch3 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "copy", "from" : "/rab/0", "path" : "/rab/6"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Source path does not exist
|
||
|
Json badPatch4 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "copy", "from" : "/omgomg", "path" : "/doesntmatter"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
// Dest path wrong type
|
||
|
Json badPatch5 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "copy", "from" : "/baz/bar", "path" : "/rabby/bar"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
EXPECT_EQ(jsonPatch(before, patch.toArray()), after);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch1.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch2.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch3.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch4.toArray()), JsonPatchException);
|
||
|
ASSERT_THROW(jsonPatch(before, badPatch5.toArray()), JsonPatchException);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, PatchingTest) {
|
||
|
Json base = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "bar",
|
||
|
"foot" : "bart",
|
||
|
"bar" : [1, 2, 3, "contact"],
|
||
|
"baz" : {
|
||
|
"baf" : 1,
|
||
|
"bar" : 2,
|
||
|
"0" : 3
|
||
|
}
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json goodTest = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/foo", "value" : "bar"},
|
||
|
{"op" : "test", "path" : "/foo", "value" : "bark", "inverse" : true},
|
||
|
{"op" : "test", "path" : "/foot", "value" : "bart"},
|
||
|
{"op" : "test", "path" : "/bar", "value" : [1, 2, 3, "contact"]},
|
||
|
{"op" : "test", "path" : "/bar/0", "value" : 1},
|
||
|
{"op" : "test", "path" : "/bar/1", "value" : 2},
|
||
|
{"op" : "test", "path" : "/bar/2", "value" : 3},
|
||
|
{"op" : "test", "path" : "/bar/3", "value" : "contact"},
|
||
|
{"op" : "test", "path" : "/baz", "value" : {"0" : 3, "baf" : 1, "bar" : 2}},
|
||
|
{"op" : "test", "path" : "/baz/baf", "value" : 1},
|
||
|
{"op" : "test", "path" : "/baz/bar", "value" : 2},
|
||
|
{"op" : "test", "path" : "/baz/0", "value" : 3},
|
||
|
{"op" : "test", "path" : "/nothere", "inverse" : true},
|
||
|
{"op" : "test", "path" : "/foo" }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
Json failTest1 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/bar", "value" : [1, 3, 2, "contact"]}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
Json failTest2 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/bar/-", "value" : "contact"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
Json failTest3 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/xyzzy", "value" : null}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
Json failTest4 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/xyzzy/zop", "value" : null}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
Json failTest5 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/nothere" }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
Json failTest6 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/bar", "inverse" : true }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
Json failTest7 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/foo", "value" : "bar", "inverse" : true }
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
jsonPatch(base, goodTest.toArray());
|
||
|
|
||
|
ASSERT_THROW(jsonPatch(base, failTest1.toArray()), JsonPatchTestFail);
|
||
|
ASSERT_THROW(jsonPatch(base, failTest2.toArray()), JsonPatchTestFail);
|
||
|
ASSERT_THROW(jsonPatch(base, failTest3.toArray()), JsonPatchTestFail);
|
||
|
ASSERT_THROW(jsonPatch(base, failTest4.toArray()), JsonPatchTestFail);
|
||
|
ASSERT_THROW(jsonPatch(base, failTest5.toArray()), JsonPatchTestFail);
|
||
|
ASSERT_THROW(jsonPatch(base, failTest6.toArray()), JsonPatchTestFail);
|
||
|
ASSERT_THROW(jsonPatch(base, failTest7.toArray()), JsonPatchTestFail);
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, PatchingEscaping) {
|
||
|
Json base1 = Json::parse(R"JSON(
|
||
|
{
|
||
|
"~" : true,
|
||
|
"/" : false,
|
||
|
"~~0" : "foo",
|
||
|
"~~1" : "bar",
|
||
|
"~~0~1/~0~" : "ugh"
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
Json test1 = Json::parse(R"JSON(
|
||
|
[
|
||
|
{"op" : "test", "path" : "/~0", "value" : true},
|
||
|
{"op" : "test", "path" : "/~1", "value" : false},
|
||
|
{"op" : "test", "path" : "/~0~00", "value" : "foo"},
|
||
|
{"op" : "test", "path" : "/~0~01", "value" : "bar"},
|
||
|
{"op" : "test", "path" : "/~0~00~01~1~00~0", "value" : "ugh"}
|
||
|
]
|
||
|
)JSON");
|
||
|
|
||
|
jsonPatch(base1, test1.toArray());
|
||
|
}
|
||
|
|
||
|
TEST(JsonTest, MergeQuery) {
|
||
|
Json json1 = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "foo1",
|
||
|
"bar" : "bar1",
|
||
|
"baz" : {
|
||
|
"1" : "1"
|
||
|
},
|
||
|
"fob" : {},
|
||
|
"fizz" : 4
|
||
|
}
|
||
|
)JSON");
|
||
|
Json json2 = Json::parse(R"JSON(
|
||
|
{
|
||
|
"foo" : "foo2",
|
||
|
"bar" : "bar2",
|
||
|
"baz" : null,
|
||
|
"baf" : {
|
||
|
"2" : "2"
|
||
|
},
|
||
|
"fob" : 2
|
||
|
}
|
||
|
)JSON");
|
||
|
Json json3 = Json::parse(R"JSON(
|
||
|
{
|
||
|
"baz" : {
|
||
|
"3" : "3"
|
||
|
},
|
||
|
"baf" : {
|
||
|
"3" : "3"
|
||
|
},
|
||
|
"fizz" : {
|
||
|
}
|
||
|
}
|
||
|
)JSON");
|
||
|
|
||
|
auto testIdentical = [&](String const& key) {
|
||
|
EXPECT_EQ(jsonMergeQuery(key, json1, json2, json3), jsonMerge(json1, json2, json3).query(key, {}));
|
||
|
};
|
||
|
|
||
|
testIdentical("foo");
|
||
|
testIdentical("bar");
|
||
|
testIdentical("baz");
|
||
|
testIdentical("baf");
|
||
|
testIdentical("baz.1");
|
||
|
testIdentical("baz.2");
|
||
|
testIdentical("baz.3");
|
||
|
testIdentical("baf.0");
|
||
|
testIdentical("baf.2");
|
||
|
testIdentical("baf.3");
|
||
|
testIdentical("baz.blip");
|
||
|
testIdentical("boo.blip");
|
||
|
testIdentical("fob");
|
||
|
testIdentical("fiz");
|
||
|
testIdentical("nothing");
|
||
|
}
|