JOHNZON-97 implemented JsonPatch
Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/74cb9088 Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/74cb9088 Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/74cb9088 Branch: refs/heads/JSONP-1.1 Commit: 74cb90884b51861361929cb6f5bcb32ca154a96c Parents: 24fe453 Author: Reinhard Sandtner <[email protected]> Authored: Thu Nov 24 00:11:42 2016 +0100 Committer: Reinhard Sandtner <[email protected]> Committed: Fri Nov 25 14:35:56 2016 +0100 ---------------------------------------------------------------------- .../org/apache/johnzon/core/JsonPatchImpl.java | 23 + .../org/apache/johnzon/core/JsonPatchTest.java | 920 ++++++++++++++++++- 2 files changed, 931 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/johnzon/blob/74cb9088/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java index 352af88..0aaedf9 100644 --- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java @@ -22,6 +22,7 @@ package org.apache.johnzon.core; import java.util.Arrays; import java.util.List; +import javax.json.JsonException; import javax.json.JsonPatch; import javax.json.JsonPointer; import javax.json.JsonStructure; @@ -42,12 +43,34 @@ class JsonPatchImpl implements JsonPatch { //X TODO JsonPointer should use generics like JsonPatch JsonStructure patched = target; + for (PatchValue patch : patches) { switch (patch.operation) { case ADD: patched = patch.path.add(patched, patch.value); break; + case REMOVE: + patched = patch.path.remove(patched); + break; + case REPLACE: + // first remove the existing element and then add the new value + patched = patch.path.add(patch.path.remove(patched), patch.value); + break; + case MOVE: + JsonValue valueToMove = patch.from.getValue(patched); + patched = patch.path.add(patch.from.remove(patched), valueToMove); + break; + case COPY: + JsonValue toCopy = patch.from.getValue(patched); + patched = patch.path.add(patched, toCopy); + break; + case TEST: + JsonValue toTest = patch.path.getValue(patched); + if (!toTest.equals(patch.value)) { + throw new JsonException("JsonPatchOperation.TEST fails! Values are not equal"); + } + break; default: throw new IllegalStateException("unsupported operation: " + patch.operation); } http://git-wip-us.apache.org/repos/asf/johnzon/blob/74cb9088/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchTest.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchTest.java b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchTest.java index a303893..b4665ed 100644 --- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchTest.java +++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchTest.java @@ -18,16 +18,22 @@ */ package org.apache.johnzon.core; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.io.StringReader; -import java.io.StringWriter; +import org.junit.Test; import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonException; import javax.json.JsonObject; +import javax.json.JsonStructure; +import javax.json.JsonValue; +import java.io.StringReader; +import java.io.StringWriter; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; public class JsonPatchTest { @@ -37,21 +43,911 @@ public class JsonPatchTest { JsonObject object = Json.createReader(new StringReader("{ \"foo\": \"bar\" }")) .readObject(); + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/baz"), + null, // no from + new JsonStringImpl("qux"))); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertEquals("bar", patched.getString("foo")); + assertEquals("qux", patched.getString("baz")); + + assertEquals("{\"foo\":\"bar\",\"baz\":\"qux\"}", toJsonString(patched)); + } + + @Test + public void testAddArrayElementWithIndex() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createArrayBuilder() + .add("bar") + .add("baz")) + .build(); JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, - Json.createJsonPointer("/baz"), - null, // no from - new JsonStringImpl("qux"))); + Json.createJsonPointer("/foo/1"), + null, // no from + new JsonStringImpl("qux"))); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + + JsonArray array = patched.getJsonArray("foo"); + assertNotNull(array); + assertEquals("bar", array.getString(0)); + assertEquals("qux", array.getString(1)); + assertEquals("baz", array.getString(2)); + + assertEquals("{\"foo\":[\"bar\",\"qux\",\"baz\"]}", toJsonString(patched)); + } + + @Test + public void testAddArrayElementAppend() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createArrayBuilder() + .add("bar") + .add("baz")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/foo/-"), + null, // no from + new JsonStringImpl("qux"))); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + + JsonArray array = patched.getJsonArray("foo"); + assertNotNull(array); + assertEquals("bar", array.getString(0)); + assertEquals("baz", array.getString(1)); + assertEquals("qux", array.getString(2)); + + assertEquals("{\"foo\":[\"bar\",\"baz\",\"qux\"]}", toJsonString(patched)); + } + + @Test + public void testAddArrayElementPlainArray() { + JsonArray array = Json.createArrayBuilder() + .add("bar") + .add("baz") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/-"), + null, // no from + new JsonStringImpl("qux"))); + + JsonArray patched = patch.apply(array); + assertNotNull(patched); + assertNotSame(array, patched); + assertEquals("bar", patched.getString(0)); + assertEquals("baz", patched.getString(1)); + assertEquals("qux", patched.getString(2)); + + assertEquals("[\"bar\",\"baz\",\"qux\"]", toJsonString(patched)); + } + + @Test(expected = JsonException.class) + public void testAddNonexistentTarget() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/baz/bat"), + null, // no from + new JsonStringImpl("qux"))); + + patch.apply(object); + } + + @Test(expected = JsonException.class) + public void testAddArrayIndexOutOfBounds() { + + JsonArray array = Json.createArrayBuilder() + .add("bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/5"), + null, + new JsonStringImpl("baz"))); + + patch.apply(array); + } + + + @Test + public void testRemoveObjectMember() { + + JsonObject object = Json.createObjectBuilder() + .add("baz", "qux") + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REMOVE, + Json.createJsonPointer("/baz"), + null, + null)); JsonObject patched = patch.apply(object); assertNotNull(patched); assertEquals("bar", patched.getString("foo")); + assertFalse("patched JsonObject must no contain \"baz\"", patched.containsKey("baz")); + + assertEquals("{\"foo\":\"bar\"}", toJsonString(patched)); + } + + @Test + public void testRemoveArrayElement() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createArrayBuilder() + .add("bar") + .add("qux") + .add("baz")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REMOVE, + Json.createJsonPointer("/foo/1"), + null, + null)); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + + JsonArray array = patched.getJsonArray("foo"); + assertNotNull(array); + assertEquals(2, array.size()); + assertEquals("bar", array.getString(0)); + assertEquals("baz", array.getString(1)); + + assertEquals("{\"foo\":[\"bar\",\"baz\"]}", toJsonString(patched)); + } + + @Test + public void testRemoveArrayElementPlainArray() { + + JsonArray array = Json.createArrayBuilder() + .add("bar") + .add("qux") + .add("baz") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REMOVE, + Json.createJsonPointer("/1"), + null, + null)); + + JsonArray patched = patch.apply(array); + assertNotNull(patched); + assertEquals(2, patched.size()); + assertEquals("bar", patched.getString(0)); + assertEquals("baz", patched.getString(1)); + + assertEquals("[\"bar\",\"baz\"]", toJsonString(patched)); + } + + @Test(expected = JsonException.class) + public void testRemoveObjectElementNonexistentTarget() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .add("baz", "qux") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REMOVE, + Json.createJsonPointer("/nomatch"), + null, + null)); + + patch.apply(object); + } + + @Test(expected = JsonException.class) + public void testRemoveArrayElementIndexOutOfBounds() { + + JsonArray array = Json.createArrayBuilder() + .add("bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REMOVE, + Json.createJsonPointer("/5"), + null, + null)); + + patch.apply(array); + } + + + @Test + public void testReplacingObjectMember() { + + JsonObject object = Json.createObjectBuilder() + .add("baz", "qux") + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REPLACE, + Json.createJsonPointer("/baz"), + null, + new JsonStringImpl("boo"))); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertNotSame(object, patched); + assertEquals("boo", patched.getString("baz")); + assertEquals("bar", patched.getString("foo")); + + assertEquals("{\"foo\":\"bar\",\"baz\":\"boo\"}", toJsonString(patched)); + } + + @Test + public void testReplacingArrayElement() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createArrayBuilder() + .add("bar") + .add("qux")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REPLACE, + Json.createJsonPointer("/foo/1"), + null, + new JsonStringImpl("boo"))); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertNotSame(object, patched); + + JsonArray array = patched.getJsonArray("foo"); + assertNotNull(array); + assertNotSame(object.getJsonArray("foo"), array); + assertEquals(2, array.size()); + assertEquals("bar", array.getString(0)); + assertEquals("boo", array.getString(1)); + + assertEquals("{\"foo\":[\"bar\",\"boo\"]}", toJsonString(patched)); + } + + @Test + public void testReplacingArrayElementPlainArray() { + + JsonArray array = Json.createArrayBuilder() + .add("bar") + .add("qux") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REPLACE, + Json.createJsonPointer("/0"), + null, + new JsonStringImpl("boo"))); + + JsonArray patched = patch.apply(array); + assertNotNull(patched); + assertNotSame(array, patched); + assertEquals(2, patched.size()); + assertEquals("boo", patched.getString(0)); + assertEquals("qux", patched.getString(1)); + + assertEquals("[\"boo\",\"qux\"]", toJsonString(patched)); + } + + @Test(expected = JsonException.class) + public void testReplacingObjectMemberNonexistingTarget() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REPLACE, + Json.createJsonPointer("/nomatch"), + null, + new JsonStringImpl("notneeded"))); + + patch.apply(object); + } + + @Test(expected = JsonException.class) + public void testReplacingArrayElementIndexOutOfBounds() { + + JsonArray array = Json.createArrayBuilder() + .add("foo") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.REPLACE, + Json.createJsonPointer("/1"), + null, + new JsonStringImpl("notneeded"))); + + patch.apply(array); + } + + + @Test + public void testMovingObjectMember() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createObjectBuilder() + .add("bar", "baz") + .add("waldo", "fred")) + .add("qux", Json.createObjectBuilder() + .add("corge", "grault")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.MOVE, + Json.createJsonPointer("/qux/thud"), + Json.createJsonPointer("/foo/waldo"), + null)); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertNotSame(object, patched); + + JsonObject foo = patched.getJsonObject("foo"); + assertNotNull(foo); + assertEquals("baz", foo.getString("bar")); + assertFalse("JsonObject with key 'foo' must not contain 'waldo'", foo.containsKey("waldo")); + + JsonObject qux = patched.getJsonObject("qux"); + assertNotNull(qux); + assertEquals("grault", qux.getString("corge")); + assertEquals("fred", qux.getString("thud")); + + assertEquals("{\"foo\":{\"bar\":\"baz\"},\"qux\":{\"corge\":\"grault\",\"thud\":\"fred\"}}", toJsonString(patched)); + } + + @Test + public void testMovingArrayElement() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createArrayBuilder() + .add("all") + .add("grass") + .add("cows") + .add("eat")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.MOVE, + Json.createJsonPointer("/foo/3"), + Json.createJsonPointer("/foo/1"), + null)); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertNotSame(object, patched); + + JsonArray array = patched.getJsonArray("foo"); + assertNotNull(array); + assertEquals("all", array.getString(0)); + assertEquals("cows", array.getString(1)); + assertEquals("eat", array.getString(2)); + assertEquals("grass", array.getString(3)); + + assertEquals("{\"foo\":[\"all\",\"cows\",\"eat\",\"grass\"]}", toJsonString(patched)); + } + + @Test + public void testMovingArrayElementPlainArray() { + + JsonArray array = Json.createArrayBuilder() + .add("two") + .add("three") + .add("four") + .add("one") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.MOVE, + Json.createJsonPointer("/0"), + Json.createJsonPointer("/3"), + null)); + + JsonArray patched = patch.apply(array); + assertNotNull(patched); + assertNotSame(array, patched); + assertEquals("one", patched.getString(0)); + assertEquals("two", patched.getString(1)); + assertEquals("three", patched.getString(2)); + assertEquals("four", patched.getString(3)); + } + + @Test + public void testMovingArrayElementToObjectMember() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createArrayBuilder() + .add("one") + .add("two") + .add("dog")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.MOVE, + Json.createJsonPointer("/bar"), + Json.createJsonPointer("/foo/2"), + null)); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertEquals(2, patched.size()); + + JsonArray array = patched.getJsonArray("foo"); + assertEquals(2, array.size()); + assertEquals("one", array.getString(0)); + assertEquals("two", array.getString(1)); + + assertEquals("dog", patched.getString("bar")); + + assertEquals("{\"foo\":[\"one\",\"two\"],\"bar\":\"dog\"}", toJsonString(patched)); + } + + @Test(expected = JsonException.class) + public void testMovingObjectMemberNonexistingFrom() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.MOVE, + Json.createJsonPointer("/baz"), + Json.createJsonPointer("/nomatch"), + null)); + + patch.apply(object); + + } + + @Test(expected = JsonException.class) + public void testMovingObjectMemberNonexistingTarget() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.MOVE, + Json.createJsonPointer("/nomatch/child"), + Json.createJsonPointer("/foo"), + null)); + + patch.apply(object); + } + + @Test(expected = JsonException.class) + public void testMovingObjectMemberMoveToSubFrom() { + + JsonObject object = Json.createObjectBuilder() + .add("object", Json.createObjectBuilder() + .add("key", "value")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.MOVE, + Json.createJsonPointer("/object/key"), + Json.createJsonPointer("/object"), + null)); + + patch.apply(object); + } + + + @Test + public void testCopyObjectMember() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/baz"), + Json.createJsonPointer("/foo"), + null)); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertEquals(2, patched.size()); + assertEquals("bar", patched.getString("foo")); + assertEquals("bar", patched.getString("baz")); + + assertEquals("{\"foo\":\"bar\",\"baz\":\"bar\"}", toJsonString(patched)); + } + + @Test + public void testCopyArrayMember() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createArrayBuilder() + .add("bar") + .add("baz")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/foo/-"), + Json.createJsonPointer("/foo/0"), + null)); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + + JsonArray array = patched.getJsonArray("foo"); + assertEquals(3, array.size()); + assertEquals("bar", array.getString(0)); + assertEquals("baz", array.getString(1)); + assertEquals("bar", array.getString(2)); + + assertEquals("{\"foo\":[\"bar\",\"baz\",\"bar\"]}", toJsonString(patched)); + } + + @Test + public void testCopyArrayMemberPlainArray() { + + JsonArray array = Json.createArrayBuilder() + .add("foo") + .add("bar") + .build(); + + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/0"), + Json.createJsonPointer("/1"), + null)); + + JsonArray patched = patch.apply(array); + assertNotNull(patched); + assertNotSame(array, patched); + assertEquals(3, patched.size()); + assertEquals("bar", patched.getString(0)); + assertEquals("foo", patched.getString(1)); + assertEquals("bar", patched.getString(2)); + + assertEquals("[\"bar\",\"foo\",\"bar\"]", toJsonString(patched)); + } + + @Test + public void testCopyObjectMemberToObjectMember() { + + JsonObject object = Json.createObjectBuilder() + .add("name", "Hugo") + .add("partner", Json.createObjectBuilder() + .add("name", "Leia") + .add("partner", JsonValue.EMPTY_JSON_OBJECT)) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/partner/partner/name"), + Json.createJsonPointer("/name"), + null)); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertNotSame(object, patched); + assertEquals("Hugo", patched.getString("name")); + + JsonObject partner = patched.getJsonObject("partner"); + assertEquals("Leia", partner.getString("name")); + + JsonObject parent = partner.getJsonObject("partner"); + assertEquals(patched.getString("name"), parent.getString("name")); + + assertEquals("{\"name\":\"Hugo\",\"partner\":{\"name\":\"Leia\",\"partner\":{\"name\":\"Hugo\"}}}", toJsonString(patched)); + } + + @Test(expected = JsonException.class) + public void testCopyObjectMemberFromNonexistentTarget() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/notneeded"), + Json.createJsonPointer("/nomatch"), + null)); + + patch.apply(object); + } + + @Test(expected = JsonException.class) + public void testCopyObjectMemberToNonexistingTarget() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/path/nomatch"), + Json.createJsonPointer("/foo"), + null)); + + patch.apply(object); + } + + @Test(expected = JsonException.class) + public void testCopyArrayMemberFromIndexOutOfBounds() { + + JsonArray array = Json.createArrayBuilder() + .add("foo") + .add("bar") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/-"), + Json.createJsonPointer("/2"), + null)); + + patch.apply(array); + } + + @Test(expected = JsonException.class) + public void testCopyArrayMemberToIndexOutOfBounds() { + + JsonArray array = Json.createArrayBuilder() + .add("foo") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/1"), + Json.createJsonPointer("/-"), + null)); + + patch.apply(array); + } + + + @Test + public void testTestingObjectMemberValueSuccess() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "qux") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/foo"), + null, + new JsonStringImpl("qux"))); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertSame(object, patched); + } + + @Test(expected = JsonException.class) + public void testTestingObjectMemberValueFailed() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "qux") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/foo"), + null, + Json.createArrayBuilder().build())); + + patch.apply(object); + } + + @Test + public void testTestingArrayAsObjectMemberSuccess() { + + JsonObject object = Json.createObjectBuilder() + .add("name", "Thor") + .add("parents", Json.createArrayBuilder() + .add("Odin") + .add("Forjgyn")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/parents"), + null, + Json.createArrayBuilder() // yessss, we really want to create a new JsonArray ;) + .add("Odin") + .add("Forjgyn") + .build())); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertSame(object, patched); + } + + @Test(expected = JsonException.class) + public void testTestingArrayAsObjectMemberFailed() { + + JsonObject object = Json.createObjectBuilder() + .add("magic", "array") + .add("numbers", Json.createArrayBuilder() + .add(1) + .add(2)) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/numbers"), + null, + Json.createArrayBuilder() // different ordering + .add(2) + .add(1) + .build())); + + patch.apply(object); + } + + @Test + public void testTestingArrayElementSuccess() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", Json.createArrayBuilder() + .add("bar") + .add("baz")) + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/foo/1"), + null, + new JsonStringImpl("baz"))); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertSame(object, patched); + } + + @Test + public void testTestingArrayElementPlainArraySuccess() { + + JsonArray array = Json.createArrayBuilder() + .add("foo") + .add("bar") + .add("qux") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/2"), + null, + new JsonStringImpl("qux"))); + + JsonArray patched = patch.apply(array); + assertNotNull(patched); + assertSame(array, patched); + } + + @Test(expected = JsonException.class) + public void testTestingArrayElementPlainArrayFailed() { + + JsonArray array = Json.createArrayBuilder() + .add(1) + .add("2") + .add("qux") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/0"), + null, + new JsonStringImpl("bar"))); + + patch.apply(array); + } + + @Test(expected = JsonException.class) + public void testTestingObjectMemeberNonexistentTarget() { + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/nomatch"), + null, + JsonValue.EMPTY_JSON_OBJECT)); + + patch.apply(JsonValue.EMPTY_JSON_OBJECT); + } + + @Test(expected = JsonException.class) + public void testTestingArrayElementIndexOutOfBounds() { + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.TEST, + Json.createJsonPointer("/3"), + null, + JsonValue.EMPTY_JSON_OBJECT)); + + patch.apply(JsonValue.EMPTY_JSON_ARRAY); + } + + + @Test + public void testAddObjectMemberAlreadyExists() { + + JsonObject object = Json.createObjectBuilder() + .add("foo", "bar") + .add("baz", "qux") + .build(); + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/foo"), + null, + new JsonStringImpl("abcd"))); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertNotSame(object, patched); + assertEquals("abcd", patched.getString("foo")); assertEquals("qux", patched.getString("baz")); - StringWriter writer = new StringWriter(); - Json.createWriter(writer).write(patched); + assertEquals("{\"foo\":\"abcd\",\"baz\":\"qux\"}", toJsonString(patched)); + } - assertEquals("{\"foo\":\"bar\",\"baz\":\"qux\"}", writer.toString()); + @Test + public void testAddArrayElementToEmptyArray() { + + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/-"), + null, + new JsonStringImpl("foo"))); + + JsonArray patched = patch.apply(JsonValue.EMPTY_JSON_ARRAY); + assertNotNull(patched); + assertEquals(1, patched.size()); + assertEquals("foo", patched.getString(0)); + } + + @Test + public void testPatchWithMoreOperations() { + + JsonObject object = Json.createObjectBuilder() + .add("family", Json.createObjectBuilder() + .add("children", JsonValue.EMPTY_JSON_ARRAY)) + .build(); + + // i know this can be done with PatchBuilder but + // currently it's not implemented and its fun ;) + JsonPatchImpl patch = new JsonPatchImpl(new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/family/father"), + null, + Json.createObjectBuilder() + .add("name", "Gaio Modry Effect") + .build()), + new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/family/mother"), + null, + Json.createObjectBuilder() + .add("name", "Cassius vom Hause Clarabella") + .build()), + new JsonPatchImpl.PatchValue(JsonPatchOperation.MOVE, + Json.createJsonPointer("/family/children/0"), + Json.createJsonPointer("/family/mother"), + null), + new JsonPatchImpl.PatchValue(JsonPatchOperation.ADD, + Json.createJsonPointer("/family/mother"), + null, + Json.createObjectBuilder() + .add("name", "Aimee vom Hause Clarabella") + .build()), + new JsonPatchImpl.PatchValue(JsonPatchOperation.COPY, + Json.createJsonPointer("/pedigree"), + Json.createJsonPointer("/family"), + null), + new JsonPatchImpl.PatchValue(JsonPatchOperation.REMOVE, + Json.createJsonPointer("/family"), + null, + null)); + + JsonObject patched = patch.apply(object); + assertNotNull(patched); + assertNotSame(object, patched); + + JsonObject pedigree = patched.getJsonObject("pedigree"); + assertEquals("Gaio Modry Effect", pedigree.getJsonObject("father").getString("name")); + assertEquals("Aimee vom Hause Clarabella", pedigree.getJsonObject("mother").getString("name")); + assertEquals("Cassius vom Hause Clarabella", pedigree.getJsonArray("children").getJsonObject(0).getString("name")); + + assertEquals("{\"pedigree\":{" + + "\"children\":[" + + "{\"name\":\"Cassius vom Hause Clarabella\"}]," + + "\"mother\":{\"name\":\"Aimee vom Hause Clarabella\"}," + + "\"father\":{\"name\":\"Gaio Modry Effect\"}}}", toJsonString(patched)); + } + + + + private static String toJsonString(JsonStructure value) { + StringWriter writer = new StringWriter(); + Json.createWriter(writer).write(value); + return writer.toString(); } }
