diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..ffc0b7d
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: maven
+ directory: /
+ schedule:
+ interval: weekly
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..d696af2
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,19 @@
+name: Java CI
+
+on:
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ - name: Set up JDK 24
+ uses: actions/setup-java@v4
+ with:
+ java-version: '24'
+ distribution: 'zulu'
+ - name: Build with Maven
+ run: mvn -B verify
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a38abf8..8a21321 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,11 +8,11 @@ The following guidelines apply to all contributors.
### Making Changes
-* Fork the `monstor-cdc/bsonpatch` repository
+* Fork the `bsonpatch/bsonpatch` repository
* Make your changes and push them to a topic branch in your fork
* See our commit message guidelines further down in this document
-* Submit a pull request to the `monstor-cdc/bsonpatch` repository
-* Update `monstor-cdc/bsonpatch` GITHUB issue with the generated pull request link
+* Submit a pull request to the `bsonpatch/bsonpatch` repository
+* Update `bsonpatch/bsonpatch` GITHUB issue with the generated pull request link
### General Guidelines
@@ -34,7 +34,7 @@ The following guidelines apply to all contributors.
* The first line should be limited to 50 characters and should not end in a
period.
* Subsequent lines should be wrapped at 72 characters.
-* Put `Closes: https://github.com/eBay/bsonpatch/issues/XXX` line at the very
+* Put `Closes: https://github.com/bsonpatch/bsonpatch/issues/XXX` line at the very
end (where `XXX` is the actual issue number) if the proposed change is relevant to a tracked issue.
Note: In Git commits the first line of the commit message has special
diff --git a/NOTICE b/NOTICE
index 82ea274..1846345 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,9 +1,10 @@
bsonpatch library
-Copyright 2017,2018,2022 eBay, Inc.
+Copyright 2025
-This product includes software developed at
-eBay, Inc. (https://www.ebay.com/).
+This software was ported (forked, renamed, repackaged, modified) from
+the bsonpatch project, developed at ebay.com
+https://github.com/eBay/bsonpatch
-This software was ported (copied, renamed, repackaged, modified) from
+Which, in turn, was ported (forked, renamed, repackaged, modified) from
the zjsonpatch project, developed at flipkart.com
-https://github.com/flipkart-incubator/zjsonpatch.
+https://github.com/flipkart-incubator/zjsonpatch
diff --git a/README.md b/README.md
index 9d6ed95..59ff5fb 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,39 @@
-# This is an implementation of [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) written in Java.
+# This is an implementation of [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) written in Java with extended BSON pointer.
This [JSON Patch](http://jsonpatch.com) implementation works directly with [BSON documents](http://bsonspec.org/) using the [MongoDB Java driver implementation of BSON](https://www.mongodb.com/json-and-bson).
-The code here was ported (copied, renamed, repackaged, modified) from the [zjsonpatch project](https://github.com/flipkart-incubator/zjsonpatch).
+The code here was forked (copied, renamed, repackaged, modified) from [eBay bsonpatch project](https://github.com/eBay/bsonpatch) which, in turn, was ported (forked, renamed, repackaged, modified) from the [zjsonpatch project](https://github.com/flipkart-incubator/zjsonpatch).
## Description & Use-Cases
- Java Library to find / apply JSON Patches according to [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902).
- JSON Patch defines a JSON document structure for representing changes to a JSON document.
- It can be used to avoid sending a whole document when only a part has changed, thus reducing network bandwidth requirements if data (in JSON format) is required to send across multiple systems over network or in case of multi DC transfer.
-- When used in combination with the HTTP PATCH method as per [RFC 5789 HTTP PATCH](https://datatracker.ietf.org/doc/html/rfc5789), it will do partial updates for HTTP APIs in a standard way.
+- When used in combination with the HTTP PATCH method as per [RFC 5789 HTTP PATCH](https://datatracker.ietf.org/doc/html/rfc5789), it will do partial updates for HTTP APIs in a standard way.
+- Extended JSON pointer functionality (i.e. reference array elements via a key): `/array/id=123/data`
+ - The user has to ensure that a unique field is used as a reference key. Should there be more than one array
+ element matching the given key-value pair, the first element will be selected.
+ - Key based referencing may be slow for large arrays. Hence, standard index based array pointers should be used for large arrays.
- This library compares two [BsonValue](https://mongodb.github.io/mongo-java-driver/3.12/javadoc/org/bson/BsonValue.html) inputs and produces a [BsonArray](https://mongodb.github.io/mongo-java-driver/3.12/javadoc/org/bson/BsonArray.html) of the changes.
### Compatible with : Java 8 and above all versions
## Complexity
-- To find JsonPatch : Ω(N+M) ,N and M represents number of keys in first and second JSON respectively / O(summation of la*lb) where la , lb represents JSON Array of length la / lb of against same key in first and second JSON ,since LCS is used to find difference between 2 JSON arrays there of order of quadratic.
+- To find JsonPatch : Ω(N+M), N and M represents number of keys in first and second JSON respectively / O(summation of la*lb) where la , lb represents JSON Array of length la / lb of against same key in first and second JSON ,since LCS is used to find difference between 2 JSON arrays there of order of quadratic.
- To Optimize Diffs ( compact move and remove into Move ) : Ω(D) / O(D*D) where D represents number of diffs obtained before compaction into Move operation.
- To Apply Diff : O(D) where D represents number of diffs
### How to use:
-### Current Version : 0.4.12
+### Current Version : 0.5.0
Add following to `` section of your pom.xml -
```xml
- com.ebay.bsonpatch
+ io.github.bsonpatch
bsonpatch
- 0.4.12
+ 0.5.0
```
@@ -78,6 +82,33 @@ Following patch will be returned:
```
here `"op"` represents the operation (`"move"`), `"from"` represent path from where value should be moved, `"path"` represents where value should be moved. The value that is moved is taken as the content at the `"from"` path.
+### Extended JSON Pointer Example
+JSON
+```json
+{
+ "a": [
+ {
+ "id": 1,
+ "data": "abc"
+ },
+ {
+ "id": 2,
+ "data": "def"
+ }
+ ]
+}
+```
+
+JSON path
+```jsonpath
+/a/id=2/data
+```
+
+Following JSON would be returned
+```json
+"def"
+```
+
### Apply Json Patch In-Place
```xml
BsonPatch.applyInPlace(BsonArray patch, BsonValue source);
@@ -85,19 +116,24 @@ BsonPatch.applyInPlace(BsonArray patch, BsonValue source);
Given a `patch`, it will apply it to the `source` BSON mutating the instance, opposed to `BsonPatch.apply` which returns
a new instance with the patch applied, leaving the `source` unchanged.
+This is an extension to the RFC, and has some additional limitations. Specifically, the source document cannot be fully change in place. This means the following operations are not supported:
+* `remove` with an empty or root path;
+* `replace` with an empty or root path;
+* `move`, `add` or `copy` targeting an empty or root path.
+
### Tests:
1. 100+ selective hardcoded different input JSONs , with their driver test classes present under /test directory.
2. Apart from selective input, a deterministic random JSON generator is present under ( TestDataGenerator.java ), and its driver test class method is JsonDiffTest.testGeneratedJsonDiff().
-#### *** Tests can only show presence of bugs and not their absence ***
+#### *** Tests can only show the presence of bugs and not their absence ***
## Get Involved
* **Contributing**: Pull requests are welcome!
* Read [`CONTRIBUTING.md`](CONTRIBUTING.md)
- * Submit [github issues](https://github.com/eBay/bsonpatch/issues) for any feature enhancements, bugs or documentation problems
+ * Submit [github issues](https://github.com/bsonpatch/bsonpatch/issues) for any feature enhancements, bugs or documentation problems
-* **Support**: Questions/comments can posted as [github issues](https://github.com/eBay/bsonpatch/issues)
+* **Support**: Questions/comments can posted as [github issues](https://github.com/bsonpatch/bsonpatch/issues)
## Maintainers
diff --git a/pom.xml b/pom.xml
index e21982e..a9001cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,29 +4,25 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- com.ebay.bsonpatch
+ io.github.bsonpatch
bsonpatch
- 0.4.12
+ 0.5.0-SNAPSHOT
jar
${project.groupId}:${project.artifactId}
Java Library to find / apply JSON Patches according to RFC 6902 against BsonValues
- https://github.com/ebay/bsonpatch/
-
-
- scm:git:git://github.com/eBay/bsonpatch.git
- scm:git:ssh://github.com/eBay/bsonpatch.git
- https://github.com/ebay/bsonpatch
- HEAD
-
+ https://github.com/bsonpatch/bsonpatch/
+
+
+ scm:git:git://github.com/bsonpatch/bsonpatch.git
+ scm:git:ssh://github.com:bsonpatch/bsonpatch.git
+ https://github.com/bsonpatch/bsonpatch/tree/master
+
dandoug
Dan Douglas
- ddouglas@skibums.org
- eBay
- https://www.ebay.com
@@ -40,6 +36,9 @@
UTF-8
+ 1.8
+ 1.8
+ 5.13.4
@@ -47,7 +46,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.10.1
+ 3.14.0
1.8
1.8
@@ -61,7 +60,7 @@
org.apache.maven.plugins
maven-source-plugin
- 3.2.1
+ 3.3.1
attach-sources
@@ -137,25 +136,31 @@
org.mongodb
mongo-java-driver
- 3.12.10
+ 3.12.14
org.apache.commons
commons-collections4
- 4.3
+ 4.5.0
-
+
- test
commons-io
commons-io
- 2.7
-
-
- test
- junit
- junit
- 4.13.1
+ 2.20.0
+ test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ ${junitVersion}
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ ${junitVersion}
+ test
+
diff --git a/src/main/java/com/ebay/bsonpatch/BsonDiff.java b/src/main/java/io/github/bsonpatch/BsonDiff.java
similarity index 98%
rename from src/main/java/com/ebay/bsonpatch/BsonDiff.java
rename to src/main/java/io/github/bsonpatch/BsonDiff.java
index 6c50735..b20e0da 100644
--- a/src/main/java/com/ebay/bsonpatch/BsonDiff.java
+++ b/src/main/java/io/github/bsonpatch/BsonDiff.java
@@ -17,14 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
-
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+package io.github.bsonpatch;
import org.apache.commons.collections4.ListUtils;
import org.bson.BsonArray;
@@ -32,6 +25,8 @@
import org.bson.BsonString;
import org.bson.BsonValue;
+import java.util.*;
+
public final class BsonDiff {
@@ -266,7 +261,7 @@ private static JsonPointer updatePathWithCounters(List counters, JsonPo
int value = counters.get(i);
if (value != 0) {
int currValue = tokens.get(i).getIndex();
- tokens.set(i, new JsonPointer.RefToken(Integer.toString(currValue + value)));
+ tokens.set(i, JsonPointer.RefToken.parse(Integer.toString(currValue + value)));
}
}
return new JsonPointer(tokens);
diff --git a/src/main/java/com/ebay/bsonpatch/BsonPatch.java b/src/main/java/io/github/bsonpatch/BsonPatch.java
similarity index 87%
rename from src/main/java/com/ebay/bsonpatch/BsonPatch.java
rename to src/main/java/io/github/bsonpatch/BsonPatch.java
index de86fa3..6d7329b 100644
--- a/src/main/java/com/ebay/bsonpatch/BsonPatch.java
+++ b/src/main/java/io/github/bsonpatch/BsonPatch.java
@@ -17,25 +17,35 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
-import static com.ebay.bsonpatch.InPlaceApplyProcessor.cloneBsonValue;
+import org.bson.BsonArray;
+import org.bson.BsonNull;
+import org.bson.BsonValue;
import java.util.EnumSet;
import java.util.Iterator;
-import org.bson.BsonArray;
-import org.bson.BsonNull;
-import org.bson.BsonValue;
+import static io.github.bsonpatch.InPlaceApplyProcessor.cloneBsonValue;
public final class BsonPatch {
private BsonPatch() {}
+ private static BsonValue getPatchStringAttr(BsonValue bsonNode, String attr) {
+ BsonValue child = getPatchAttr(bsonNode, attr);
+
+ if (!child.isString())
+ throw new InvalidBsonPatchException("Invalid JSON Patch payload (non-text '" + attr + "' field)");
+
+ return child;
+ }
+
private static BsonValue getPatchAttr(BsonValue bsonNode, String attr) {
BsonValue child = bsonNode.asDocument().get(attr);
if (child == null)
throw new InvalidBsonPatchException("Invalid BSON Patch payload (missing '" + attr + "' field)");
+
return child;
}
@@ -54,8 +64,8 @@ private static void process(BsonArray patch, BsonPatchProcessor processor, EnumS
while (operations.hasNext()) {
BsonValue bsonNode = operations.next();
if (!bsonNode.isDocument()) throw new InvalidBsonPatchException("Invalid BSON Patch payload (not an object)");
- Operation operation = Operation.fromRfcName(getPatchAttr(bsonNode, Constants.OP).asString().getValue().replaceAll("\"", ""));
- JsonPointer path = JsonPointer.parse(getPatchAttr(bsonNode, Constants.PATH).asString().getValue());
+ Operation operation = Operation.fromRfcName(getPatchStringAttr(bsonNode, Constants.OP).asString().getValue().replaceAll("\"", ""));
+ JsonPointer path = JsonPointer.parse(getPatchStringAttr(bsonNode, Constants.PATH).asString().getValue());
try {
switch (operation) {
@@ -85,13 +95,13 @@ private static void process(BsonArray patch, BsonPatchProcessor processor, EnumS
}
case MOVE: {
- JsonPointer fromPath = JsonPointer.parse(getPatchAttr(bsonNode, Constants.FROM).asString().getValue());
+ JsonPointer fromPath = JsonPointer.parse(getPatchStringAttr(bsonNode, Constants.FROM).asString().getValue());
processor.move(fromPath, path);
break;
}
case COPY: {
- JsonPointer fromPath = JsonPointer.parse(getPatchAttr(bsonNode, Constants.FROM).asString().getValue());
+ JsonPointer fromPath = JsonPointer.parse(getPatchStringAttr(bsonNode, Constants.FROM).asString().getValue());
processor.copy(fromPath, path);
break;
}
diff --git a/src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java b/src/main/java/io/github/bsonpatch/BsonPatchApplicationException.java
similarity index 86%
rename from src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java
rename to src/main/java/io/github/bsonpatch/BsonPatchApplicationException.java
index e589487..60454c1 100644
--- a/src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java
+++ b/src/main/java/io/github/bsonpatch/BsonPatchApplicationException.java
@@ -17,21 +17,29 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
public class BsonPatchApplicationException extends RuntimeException {
private static final long serialVersionUID = 7562538769544371424L;
-
- Operation operation;
- JsonPointer path;
+
+ final Operation operation;
+ final JsonPointer path;
public BsonPatchApplicationException(String message, Operation operation, JsonPointer path) {
super(message);
this.operation = operation;
this.path = path;
}
-
- @Override
+
+ public Operation getOperation() {
+ return operation;
+ }
+
+ public JsonPointer getPath() {
+ return path;
+ }
+
+ @Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (operation != null) sb.append('[').append(operation).append(" Operation] ");
diff --git a/src/main/java/com/ebay/bsonpatch/BsonPatchProcessor.java b/src/main/java/io/github/bsonpatch/BsonPatchProcessor.java
similarity index 97%
rename from src/main/java/com/ebay/bsonpatch/BsonPatchProcessor.java
rename to src/main/java/io/github/bsonpatch/BsonPatchProcessor.java
index 1c5c17d..ba0aef8 100644
--- a/src/main/java/com/ebay/bsonpatch/BsonPatchProcessor.java
+++ b/src/main/java/io/github/bsonpatch/BsonPatchProcessor.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import org.bson.BsonValue;
diff --git a/src/main/java/com/ebay/bsonpatch/CompatibilityFlags.java b/src/main/java/io/github/bsonpatch/CompatibilityFlags.java
similarity index 97%
rename from src/main/java/com/ebay/bsonpatch/CompatibilityFlags.java
rename to src/main/java/io/github/bsonpatch/CompatibilityFlags.java
index 4293ea7..3994fd0 100644
--- a/src/main/java/com/ebay/bsonpatch/CompatibilityFlags.java
+++ b/src/main/java/io/github/bsonpatch/CompatibilityFlags.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import java.util.EnumSet;
diff --git a/src/main/java/com/ebay/bsonpatch/Constants.java b/src/main/java/io/github/bsonpatch/Constants.java
similarity index 97%
rename from src/main/java/com/ebay/bsonpatch/Constants.java
rename to src/main/java/io/github/bsonpatch/Constants.java
index 7ebb358..158a3f0 100644
--- a/src/main/java/com/ebay/bsonpatch/Constants.java
+++ b/src/main/java/io/github/bsonpatch/Constants.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
final class Constants {
public static final String OP = "op";
diff --git a/src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java b/src/main/java/io/github/bsonpatch/CopyingApplyProcessor.java
similarity index 94%
rename from src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java
rename to src/main/java/io/github/bsonpatch/CopyingApplyProcessor.java
index e12bd51..ec25972 100644
--- a/src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java
+++ b/src/main/java/io/github/bsonpatch/CopyingApplyProcessor.java
@@ -17,11 +17,12 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import org.bson.BsonBinary;
import org.bson.BsonJavaScriptWithScope;
import org.bson.BsonValue;
+
import java.util.EnumSet;
class CopyingApplyProcessor extends InPlaceApplyProcessor {
@@ -32,8 +33,12 @@ class CopyingApplyProcessor extends InPlaceApplyProcessor {
CopyingApplyProcessor(BsonValue target, EnumSet flags) {
super(deepCopy(target), flags);
- }
-
+ }
+
+ @Override
+ protected boolean allowRootReplacement() {
+ return true;
+ }
static BsonValue deepCopy(BsonValue source) {
BsonValue result;
switch (source.getBsonType()) {
diff --git a/src/main/java/com/ebay/bsonpatch/Diff.java b/src/main/java/io/github/bsonpatch/Diff.java
similarity index 98%
rename from src/main/java/com/ebay/bsonpatch/Diff.java
rename to src/main/java/io/github/bsonpatch/Diff.java
index f798189..3b6350e 100644
--- a/src/main/java/com/ebay/bsonpatch/Diff.java
+++ b/src/main/java/io/github/bsonpatch/Diff.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import org.bson.BsonValue;
diff --git a/src/main/java/com/ebay/bsonpatch/DiffFlags.java b/src/main/java/io/github/bsonpatch/DiffFlags.java
similarity index 99%
rename from src/main/java/com/ebay/bsonpatch/DiffFlags.java
rename to src/main/java/io/github/bsonpatch/DiffFlags.java
index 6a60301..e065f7f 100644
--- a/src/main/java/com/ebay/bsonpatch/DiffFlags.java
+++ b/src/main/java/io/github/bsonpatch/DiffFlags.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import java.util.EnumSet;
diff --git a/src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java b/src/main/java/io/github/bsonpatch/InPlaceApplyProcessor.java
similarity index 90%
rename from src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java
rename to src/main/java/io/github/bsonpatch/InPlaceApplyProcessor.java
index c62fc71..0f00cb9 100644
--- a/src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java
+++ b/src/main/java/io/github/bsonpatch/InPlaceApplyProcessor.java
@@ -17,15 +17,11 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
-import java.util.EnumSet;
+import org.bson.*;
-import org.bson.BsonArray;
-import org.bson.BsonBinary;
-import org.bson.BsonDocument;
-import org.bson.BsonJavaScriptWithScope;
-import org.bson.BsonValue;
+import java.util.EnumSet;
class InPlaceApplyProcessor implements BsonPatchProcessor {
@@ -45,6 +41,10 @@ public BsonValue result() {
return target;
}
+ protected boolean allowRootReplacement() {
+ return false;
+ }
+
@Override
public void move(JsonPointer fromPath, JsonPointer toPath) throws JsonPointerEvaluationException {
BsonValue valueNode = fromPath.evaluate(target);
@@ -95,6 +95,8 @@ public void add(JsonPointer path, BsonValue value) throws JsonPointerEvaluationE
@Override
public void replace(JsonPointer path, BsonValue value) throws JsonPointerEvaluationException {
if (path.isRoot()) {
+ if (!allowRootReplacement())
+ throw new BsonPatchApplicationException("Cannot replace root document", Operation.REPLACE, path);
target = value;
return;
}
@@ -170,17 +172,19 @@ static BsonValue cloneBsonValue(BsonValue from) {
}
private void set(JsonPointer path, BsonValue value, Operation forOp) throws JsonPointerEvaluationException {
- if (path.isRoot())
+ if (path.isRoot()) {
+ if (!allowRootReplacement())
+ throw new BsonPatchApplicationException("Cannot replace root document", forOp, path);
target = value;
- else {
- BsonValue parentNode = path.getParent().evaluate(target);
- if (!parentNode.isDocument() && !parentNode.isArray())
- throw new BsonPatchApplicationException("Cannot reference past scalar value", forOp, path.getParent());
- else if (parentNode.isArray())
- addToArray(path, value, parentNode);
- else
- addToObject(path, parentNode, value);
+ return;
}
+ BsonValue parentNode = path.getParent().evaluate(target);
+ if (parentNode.getBsonType() != BsonType.DOCUMENT && parentNode.getBsonType() != BsonType.ARRAY)
+ throw new BsonPatchApplicationException("Cannot reference past scalar value", forOp, path.getParent());
+ else if (parentNode.isArray())
+ addToArray(path, value, parentNode);
+ else
+ addToObject(path, parentNode, value);
}
private void addToObject(JsonPointer path, BsonValue node, BsonValue value) {
diff --git a/src/main/java/com/ebay/bsonpatch/InternalUtils.java b/src/main/java/io/github/bsonpatch/InternalUtils.java
similarity index 98%
rename from src/main/java/com/ebay/bsonpatch/InternalUtils.java
rename to src/main/java/io/github/bsonpatch/InternalUtils.java
index ae1a448..2413d31 100644
--- a/src/main/java/com/ebay/bsonpatch/InternalUtils.java
+++ b/src/main/java/io/github/bsonpatch/InternalUtils.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import org.bson.BsonArray;
import org.bson.BsonValue;
diff --git a/src/main/java/com/ebay/bsonpatch/InvalidBsonPatchException.java b/src/main/java/io/github/bsonpatch/InvalidBsonPatchException.java
similarity index 97%
rename from src/main/java/com/ebay/bsonpatch/InvalidBsonPatchException.java
rename to src/main/java/io/github/bsonpatch/InvalidBsonPatchException.java
index 3a29a5b..e85d196 100644
--- a/src/main/java/com/ebay/bsonpatch/InvalidBsonPatchException.java
+++ b/src/main/java/io/github/bsonpatch/InvalidBsonPatchException.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
public class InvalidBsonPatchException extends BsonPatchApplicationException {
private static final long serialVersionUID = 1525480895357401013L;
diff --git a/src/main/java/com/ebay/bsonpatch/JsonPointer.java b/src/main/java/io/github/bsonpatch/JsonPointer.java
similarity index 66%
rename from src/main/java/com/ebay/bsonpatch/JsonPointer.java
rename to src/main/java/io/github/bsonpatch/JsonPointer.java
index 1fe9bfb..444c25d 100644
--- a/src/main/java/com/ebay/bsonpatch/JsonPointer.java
+++ b/src/main/java/io/github/bsonpatch/JsonPointer.java
@@ -1,14 +1,16 @@
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+import org.bson.BsonValue;
+
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.bson.BsonValue;
-
/**
* Implements RFC 6901 (JSON Pointer)
*
@@ -38,9 +40,11 @@
*
* @since 0.4.8
*/
-class JsonPointer {
+public class JsonPointer implements Serializable {
private final RefToken[] tokens;
+ private static final long serialVersionUID = 7876822196894534620L;
+
/** A JSON pointer representing the root node of a JSON document */
public final static JsonPointer ROOT = new JsonPointer(new RefToken[] {});
@@ -82,8 +86,12 @@ public static JsonPointer parse(String path) throws IllegalArgumentException {
// Escape sequences
case '~':
switch (path.charAt(++i)) {
- case '0': reftoken.append('~'); break;
- case '1': reftoken.append('/'); break;
+ case '0':
+ case '1':
+ case '2':
+ reftoken.append('~');
+ reftoken.append(path.charAt(i));
+ break;
default:
throw new IllegalArgumentException("Invalid escape sequence ~" + path.charAt(i) + " at index " + i);
}
@@ -91,7 +99,7 @@ public static JsonPointer parse(String path) throws IllegalArgumentException {
// New reftoken
case '/':
- result.add(new RefToken(reftoken.toString()));
+ result.add(RefToken.parse(reftoken.toString()));
reftoken.setLength(0);
break;
@@ -124,7 +132,7 @@ public boolean isRoot() {
*/
JsonPointer append(String field) {
RefToken[] newTokens = Arrays.copyOf(tokens, tokens.length + 1);
- newTokens[tokens.length] = new RefToken(field);
+ newTokens[tokens.length] = new RefToken(field, null, null);
return new JsonPointer(newTokens);
}
@@ -135,7 +143,9 @@ JsonPointer append(String field) {
* @return The new {@link JsonPointer} instance.
*/
JsonPointer append(int index) {
- return append(Integer.toString(index));
+ RefToken[] newTokens = Arrays.copyOf(tokens, tokens.length + 1);
+ newTokens[tokens.length] = new RefToken(Integer.toString(index), index, null);
+ return new JsonPointer(newTokens);
}
/** Returns the number of reference tokens comprising this instance. */
@@ -226,11 +236,27 @@ public BsonValue evaluate(final BsonValue document) throws JsonPointerEvaluation
final RefToken token = tokens[idx];
if (current.isArray()) {
- if (!token.isArrayIndex())
+ if (token.isArrayIndex()) {
+ if (token.getIndex() == LAST_INDEX || token.getIndex() >= current.asArray().size())
+ error(idx, "Array index " + token + " is out of bounds", document);
+ current = current.asArray().get(token.getIndex());
+ } else if (token.isArrayKeyRef()) {
+ KeyRef keyRef = token.getKeyRef();
+ BsonValue foundArrayNode = null;
+ for (int arrayIdx = 0; arrayIdx < current.asArray().size(); ++arrayIdx) {
+ BsonValue arrayNode = current.asArray().get(arrayIdx);
+ if (matches(keyRef, arrayNode)) {
+ foundArrayNode = arrayNode;
+ break;
+ }
+ }
+ if (foundArrayNode == null) {
+ error(idx, "Array has no matching object for key reference " + token, document);
+ }
+ current = foundArrayNode;
+ } else {
error(idx, "Can't reference field \"" + token.getField() + "\" on array", document);
- if (token.getIndex() == LAST_INDEX || token.getIndex() >= current.asArray().size())
- error(idx, "Array index " + token.toString() + " is out of bounds", document);
- current = current.asArray().get(token.getIndex());
+ }
}
else if (current.isDocument()) {
if (!current.asDocument().containsKey(token.getField()))
@@ -244,6 +270,20 @@ else if (current.isDocument()) {
return current;
}
+ private boolean matches(KeyRef keyRef, BsonValue arrayNode) {
+ boolean matches = false;
+ if (arrayNode.asDocument().containsKey(keyRef.key)) {
+ BsonValue valueNode = arrayNode.asDocument().get(keyRef.key);
+ if (valueNode.isString()) {
+ matches = Objects.equals(keyRef.value, valueNode.asString().getValue());
+ } else if (valueNode.isNumber() || valueNode.isBoolean()) {
+ matches = Objects.equals(keyRef.value, valueNode.toString());
+ }
+ }
+ return matches;
+ }
+
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -261,62 +301,103 @@ public int hashCode() {
}
/** Represents a single JSON Pointer reference token. */
- static class RefToken {
- private String decodedToken;
- transient private Integer index = null;
+ static class RefToken implements Serializable
+ {
+ private final String decodedToken;
+ private final Integer index;
+ private final KeyRef keyRef;
- public RefToken(String decodedToken) {
+ private static final long serialVersionUID = -8672427347472605093L;
+
+ private RefToken(String decodedToken, Integer arrayIndex, KeyRef arrayKeyRef) {
if (decodedToken == null) throw new IllegalArgumentException("Token can't be null");
this.decodedToken = decodedToken;
+ this.index = arrayIndex;
+ this.keyRef = arrayKeyRef;
}
private static final Pattern DECODED_TILDA_PATTERN = Pattern.compile("~0");
private static final Pattern DECODED_SLASH_PATTERN = Pattern.compile("~1");
+ private static final Pattern DECODED_EQUALS_PATTERN = Pattern.compile("~2");
private static String decodePath(Object object) {
String path = object.toString(); // see http://tools.ietf.org/html/rfc6901#section-4
path = DECODED_SLASH_PATTERN.matcher(path).replaceAll("/");
- return DECODED_TILDA_PATTERN.matcher(path).replaceAll("~");
+ path = DECODED_TILDA_PATTERN.matcher(path).replaceAll("~");
+ return DECODED_EQUALS_PATTERN.matcher(path).replaceAll("=");
}
private static final Pattern ENCODED_TILDA_PATTERN = Pattern.compile("~");
private static final Pattern ENCODED_SLASH_PATTERN = Pattern.compile("/");
+ private static final Pattern ENCODED_EQUALS_PATTERN = Pattern.compile("=");
private static String encodePath(Object object) {
String path = object.toString(); // see http://tools.ietf.org/html/rfc6901#section-4
path = ENCODED_TILDA_PATTERN.matcher(path).replaceAll("~0");
- return ENCODED_SLASH_PATTERN.matcher(path).replaceAll("~1");
+ path = ENCODED_SLASH_PATTERN.matcher(path).replaceAll("~1");
+ return ENCODED_EQUALS_PATTERN.matcher(path).replaceAll("~2");
}
private static final Pattern VALID_ARRAY_IND = Pattern.compile("-|0|(?:[1-9][0-9]*)");
+ private static final Pattern VALID_ARRAY_KEY_REF = Pattern.compile("([^=]+)=([^=]+)");
+
public static RefToken parse(String rawToken) {
if (rawToken == null) throw new IllegalArgumentException("Token can't be null");
- return new RefToken(decodePath(rawToken));
+
+ Integer index = null;
+ Matcher indexMatcher = VALID_ARRAY_IND.matcher(rawToken);
+ if (indexMatcher.matches()) {
+ if (indexMatcher.group().equals("-")) {
+ index = LAST_INDEX;
+ } else {
+ try {
+ int validInt = Integer.parseInt(indexMatcher.group());
+ index = validInt;
+ } catch (NumberFormatException ignore) {}
+ }
+ }
+
+ KeyRef keyRef = null;
+ Matcher arrayKeyRefMatcher = VALID_ARRAY_KEY_REF.matcher(rawToken);
+ if (arrayKeyRefMatcher.matches()) {
+ keyRef = new KeyRef(
+ decodePath(arrayKeyRefMatcher.group(1)),
+ decodePath(arrayKeyRefMatcher.group(2))
+ );
+ }
+ return new RefToken(decodePath(rawToken), index, keyRef);
}
public boolean isArrayIndex() {
- if (index != null) return true;
- Matcher matcher = VALID_ARRAY_IND.matcher(decodedToken);
- if (matcher.matches()) {
- index = matcher.group().equals("-") ? LAST_INDEX : Integer.parseInt(matcher.group());
- return true;
- }
- return false;
+ return index != null;
+ }
+
+ public boolean isArrayKeyRef() {
+ return keyRef != null;
}
public int getIndex() {
- if (!isArrayIndex()) throw new IllegalStateException("Object operation on array target");
+ if (!isArrayIndex()) throw new IllegalStateException("Object operation on array index target");
return index;
}
+ public KeyRef getKeyRef() {
+ if (!isArrayKeyRef()) throw new IllegalStateException("Object operation on array key ref target");
+ return keyRef;
+ }
+
public String getField() {
return decodedToken;
}
@Override
public String toString() {
- return encodePath(decodedToken);
+ if (isArrayKeyRef()) {
+ return encodePath(keyRef.key) + "=" + encodePath(keyRef.value);
+ } else {
+ return encodePath(decodedToken);
+ }
}
@Override
@@ -335,6 +416,34 @@ public int hashCode() {
}
}
+
+ static class KeyRef implements Serializable {
+ private String key;
+ private String value;
+
+ private static final long serialVersionUID = 6558265555055471373L;
+
+ public KeyRef(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ KeyRef keyRef = (KeyRef) o;
+
+ return Objects.equals(key, keyRef.key) && Objects.equals(value, keyRef.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(key, value);
+ }
+ }
+
/**
* Represents an array index pointing past the end of the array.
*
diff --git a/src/main/java/com/ebay/bsonpatch/JsonPointerEvaluationException.java b/src/main/java/io/github/bsonpatch/JsonPointerEvaluationException.java
similarity index 94%
rename from src/main/java/com/ebay/bsonpatch/JsonPointerEvaluationException.java
rename to src/main/java/io/github/bsonpatch/JsonPointerEvaluationException.java
index 192ee0c..3043ede 100644
--- a/src/main/java/com/ebay/bsonpatch/JsonPointerEvaluationException.java
+++ b/src/main/java/io/github/bsonpatch/JsonPointerEvaluationException.java
@@ -1,4 +1,4 @@
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import org.bson.BsonValue;
diff --git a/src/main/java/com/ebay/bsonpatch/NoopProcessor.java b/src/main/java/io/github/bsonpatch/NoopProcessor.java
similarity index 98%
rename from src/main/java/com/ebay/bsonpatch/NoopProcessor.java
rename to src/main/java/io/github/bsonpatch/NoopProcessor.java
index 71e0acf..38d5093 100644
--- a/src/main/java/com/ebay/bsonpatch/NoopProcessor.java
+++ b/src/main/java/io/github/bsonpatch/NoopProcessor.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import org.bson.BsonValue;
diff --git a/src/main/java/com/ebay/bsonpatch/Operation.java b/src/main/java/io/github/bsonpatch/Operation.java
similarity index 97%
rename from src/main/java/com/ebay/bsonpatch/Operation.java
rename to src/main/java/io/github/bsonpatch/Operation.java
index 63292ed..354848a 100644
--- a/src/main/java/com/ebay/bsonpatch/Operation.java
+++ b/src/main/java/io/github/bsonpatch/Operation.java
@@ -17,13 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-enum Operation {
+public enum Operation {
ADD("add"),
REMOVE("remove"),
REPLACE("replace"),
diff --git a/src/test/java/com/ebay/bsonpatch/TestUtils.java b/src/test/java/com/ebay/bsonpatch/TestUtils.java
deleted file mode 100644
index 9dbda3e..0000000
--- a/src/test/java/com/ebay/bsonpatch/TestUtils.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ebay.bsonpatch;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.commons.io.IOUtils;
-import org.bson.BsonDocument;
-import org.bson.BsonValue;
-
-public class TestUtils {
-
- private TestUtils() {
- }
-
- public static BsonValue loadResourceAsBsonValue(String path) throws IOException {
- String testData = loadFromResources(path);
- return BsonDocument.parse(testData);
- }
-
- public static String loadFromResources(String path) throws IOException {
- InputStream resourceAsStream = PatchTestCase.class.getResourceAsStream(path);
- return IOUtils.toString(resourceAsStream, "UTF-8");
- }
-}
\ No newline at end of file
diff --git a/src/test/java/com/ebay/bsonpatch/AbstractTest.java b/src/test/java/io/github/bsonpatch/AbstractTest.java
similarity index 78%
rename from src/test/java/com/ebay/bsonpatch/AbstractTest.java
rename to src/test/java/io/github/bsonpatch/AbstractTest.java
index 29c041d..4629575 100644
--- a/src/test/java/com/ebay/bsonpatch/AbstractTest.java
+++ b/src/test/java/io/github/bsonpatch/AbstractTest.java
@@ -17,16 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
-
-import static org.hamcrest.core.IsInstanceOf.instanceOf;
-import static org.hamcrest.core.StringContains.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
+package io.github.bsonpatch;
import org.apache.commons.io.output.StringBuilderWriter;
import org.bson.BsonArray;
@@ -38,6 +29,15 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
@RunWith(Parameterized.class)
public abstract class AbstractTest {
@@ -51,15 +51,24 @@ protected boolean matchOnErrors() {
}
@Test
- public void test() throws Exception {
+ public void testApply() throws Exception {
if (p.isOperation()) {
- testOperation();
+ testOperation(false);
+ } else {
+ testError(false);
+ }
+ }
+
+ @Test
+ public void testApplyInPlace() throws Exception {
+ if (p.isOperation() && p.isApplyInPlaceSupported()) {
+ testOperation(true);
} else {
- testError();
+ testError(true);
}
}
- private void testOperation() throws Exception {
+ private void testOperation(boolean inPlace) throws Exception {
BsonDocument node = p.getNode();
BsonValue doc = node.get("node");
@@ -67,7 +76,13 @@ private void testOperation() throws Exception {
BsonArray patch = node.getArray("op");
String message = node.containsKey("message") ? node.getString("message").getValue() : "";
- BsonValue result = BsonPatch.apply(patch, doc);
+ BsonValue result;
+ if (inPlace) {
+ result = CopyingApplyProcessor.deepCopy(doc);
+ BsonPatch.applyInPlace(patch, result);
+ } else {
+ result = BsonPatch.apply(patch, doc);
+ }
String failMessage = "The following test failed: \n" +
"message: " + message + '\n' +
"at: " + p.getSourceFile();
@@ -75,7 +90,7 @@ private void testOperation() throws Exception {
}
private Class> exceptionType(String type) throws ClassNotFoundException {
- return Class.forName(type.contains(".") ? type : "com.ebay.bsonpatch." + type);
+ return Class.forName(type.contains(".") ? type : "io.github.bsonpatch." + type);
}
private String errorMessage(String header) {
@@ -97,7 +112,7 @@ private String errorMessage(String header, Exception e) {
return res.toString();
}
- private void testError() throws ClassNotFoundException {
+ private void testError(boolean inPlace) throws ClassNotFoundException {
BsonDocument node = p.getNode();
BsonValue first = node.get("node");
BsonArray patch = node.getArray("op");
@@ -106,8 +121,12 @@ private void testError() throws ClassNotFoundException {
node.containsKey("type") ? exceptionType(node.getString("type").getValue()) : BsonPatchApplicationException.class;
try {
- BsonPatch.apply(patch, first);
-
+ if (inPlace) {
+ BsonValue target = CopyingApplyProcessor.deepCopy(first);
+ BsonPatch.applyInPlace(patch, target);
+ } else {
+ BsonPatch.apply(patch, first);
+ }
fail(errorMessage("Failure expected: " + message));
} catch (Exception e) {
if (matchOnErrors()) {
@@ -118,7 +137,7 @@ private void testError() throws ClassNotFoundException {
errorMessage("Operation failed but with wrong exception type", e),
e,
instanceOf(type));
- if (message != null) {
+ if (!message.isEmpty()) {
assertThat(
errorMessage("Operation failed but with wrong message", e),
e.toString(),
diff --git a/src/test/java/com/ebay/bsonpatch/AddOperationTest.java b/src/test/java/io/github/bsonpatch/AddOperationTest.java
similarity index 97%
rename from src/test/java/com/ebay/bsonpatch/AddOperationTest.java
rename to src/test/java/io/github/bsonpatch/AddOperationTest.java
index a992121..e467f9b 100644
--- a/src/test/java/com/ebay/bsonpatch/AddOperationTest.java
+++ b/src/test/java/io/github/bsonpatch/AddOperationTest.java
@@ -17,13 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.junit.runners.Parameterized.Parameters;
import java.io.IOException;
import java.util.Collection;
-import org.junit.runners.Parameterized.Parameters;
-
public class AddOperationTest extends AbstractTest {
@Parameters
diff --git a/src/test/java/com/ebay/bsonpatch/ApiTest.java b/src/test/java/io/github/bsonpatch/ApiTest.java
similarity index 98%
rename from src/test/java/com/ebay/bsonpatch/ApiTest.java
rename to src/test/java/io/github/bsonpatch/ApiTest.java
index 193901c..e6678fe 100644
--- a/src/test/java/com/ebay/bsonpatch/ApiTest.java
+++ b/src/test/java/io/github/bsonpatch/ApiTest.java
@@ -17,18 +17,18 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import org.bson.BsonArray;
+import org.bson.BsonDocument;
+import org.junit.Test;
import java.io.IOException;
import java.util.EnumSet;
-import org.bson.BsonArray;
-import org.bson.BsonDocument;
-import org.junit.Test;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
public class ApiTest {
diff --git a/src/test/java/com/ebay/bsonpatch/CompatibilityTest.java b/src/test/java/io/github/bsonpatch/CompatibilityTest.java
similarity index 91%
rename from src/test/java/com/ebay/bsonpatch/CompatibilityTest.java
rename to src/test/java/io/github/bsonpatch/CompatibilityTest.java
index cc9057c..23d1644 100644
--- a/src/test/java/com/ebay/bsonpatch/CompatibilityTest.java
+++ b/src/test/java/io/github/bsonpatch/CompatibilityTest.java
@@ -17,17 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
-
-import static com.ebay.bsonpatch.CompatibilityFlags.ALLOW_MISSING_TARGET_OBJECT_ON_REPLACE;
-import static com.ebay.bsonpatch.CompatibilityFlags.FORBID_REMOVE_MISSING_OBJECT;
-import static com.ebay.bsonpatch.CompatibilityFlags.MISSING_VALUES_AS_NULLS;
-import static com.ebay.bsonpatch.CompatibilityFlags.REMOVE_NONE_EXISTING_ARRAY_ELEMENT;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-import java.io.IOException;
-import java.util.EnumSet;
+package io.github.bsonpatch;
import org.bson.BsonArray;
import org.bson.BsonDocument;
@@ -35,6 +25,13 @@
import org.junit.Before;
import org.junit.Test;
+import java.io.IOException;
+import java.util.EnumSet;
+
+import static io.github.bsonpatch.CompatibilityFlags.*;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsEqual.equalTo;
+
public class CompatibilityTest {
BsonArray addNodeWithMissingValue;
diff --git a/src/test/java/com/ebay/bsonpatch/CopyOperationTest.java b/src/test/java/io/github/bsonpatch/CopyOperationTest.java
similarity index 97%
rename from src/test/java/com/ebay/bsonpatch/CopyOperationTest.java
rename to src/test/java/io/github/bsonpatch/CopyOperationTest.java
index 05e82c2..671aee7 100644
--- a/src/test/java/com/ebay/bsonpatch/CopyOperationTest.java
+++ b/src/test/java/io/github/bsonpatch/CopyOperationTest.java
@@ -17,13 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Collection;
-import org.junit.runners.Parameterized;
-
public class CopyOperationTest extends AbstractTest {
@Parameterized.Parameters
diff --git a/src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java b/src/test/java/io/github/bsonpatch/JsLibSamplesTest.java
similarity index 98%
rename from src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java
rename to src/test/java/io/github/bsonpatch/JsLibSamplesTest.java
index 2a1fafe..03bf422 100644
--- a/src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java
+++ b/src/test/java/io/github/bsonpatch/JsLibSamplesTest.java
@@ -17,13 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Collection;
-import org.junit.runners.Parameterized;
-
/**
* These tests comes from JS JSON-Patch libraries (
* https://github.com/Starcounter-Jack/JSON-Patch/blob/master/test/spec/json-patch-tests/tests.json
diff --git a/src/test/java/com/ebay/bsonpatch/JsonDiffTest.java b/src/test/java/io/github/bsonpatch/JsonDiffTest.java
similarity index 97%
rename from src/test/java/com/ebay/bsonpatch/JsonDiffTest.java
rename to src/test/java/io/github/bsonpatch/JsonDiffTest.java
index 8ecf788..e0d7ef6 100644
--- a/src/test/java/com/ebay/bsonpatch/JsonDiffTest.java
+++ b/src/test/java/io/github/bsonpatch/JsonDiffTest.java
@@ -17,7 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.apache.commons.io.IOUtils;
+import org.bson.*;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
@@ -27,16 +33,6 @@
import static org.junit.Assert.assertEquals;
-import org.apache.commons.io.IOUtils;
-import org.bson.BsonArray;
-import org.bson.BsonDocument;
-import org.bson.BsonInt32;
-import org.bson.BsonString;
-import org.bson.BsonValue;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
public class JsonDiffTest {
private static BsonArray jsonNode;
diff --git a/src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java b/src/test/java/io/github/bsonpatch/JsonDiffTest2.java
similarity index 93%
rename from src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java
rename to src/test/java/io/github/bsonpatch/JsonDiffTest2.java
index ed0191c..4f9e748 100644
--- a/src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java
+++ b/src/test/java/io/github/bsonpatch/JsonDiffTest2.java
@@ -17,21 +17,21 @@
* under the License.
*/
-package com.ebay.bsonpatch;
-
-import static org.hamcrest.core.IsEqual.equalTo;
-
-import java.io.IOException;
-import java.io.InputStream;
+package io.github.bsonpatch;
import org.apache.commons.io.IOUtils;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonValue;
-import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsEqual.equalTo;
+
public class JsonDiffTest2 {
private static BsonArray jsonNode;
@@ -54,7 +54,7 @@ public void testPatchAppliedCleanly() {
String message = node.containsKey("message") ? node.getString("message").getValue() : "";
BsonValue secondPrime = BsonPatch.apply(patch, first);
- Assert.assertThat(message, secondPrime, equalTo(second));
+ assertThat(message, secondPrime, equalTo(second));
}
}
diff --git a/src/test/java/com/ebay/bsonpatch/JsonPointerTest.java b/src/test/java/io/github/bsonpatch/JsonPointerTest.java
similarity index 68%
rename from src/test/java/com/ebay/bsonpatch/JsonPointerTest.java
rename to src/test/java/io/github/bsonpatch/JsonPointerTest.java
index c887374..fef6152 100644
--- a/src/test/java/com/ebay/bsonpatch/JsonPointerTest.java
+++ b/src/test/java/io/github/bsonpatch/JsonPointerTest.java
@@ -1,16 +1,11 @@
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import org.bson.*;
+import org.junit.Test;
import java.io.IOException;
-import org.bson.BsonArray;
-import org.bson.BsonInt32;
-import org.bson.BsonString;
-import org.bson.BsonValue;
-import org.junit.Test;
+import static org.junit.Assert.*;
public class JsonPointerTest {
@@ -33,7 +28,7 @@ public void parsesSingleSlashAsFieldReference() {
}
@Test
- public void parsesArrayIndirection() {
+ public void parsesArrayIndexIndirection() {
JsonPointer parsed = JsonPointer.parse("/0");
assertFalse(parsed.isRoot());
assertEquals(1, parsed.size());
@@ -41,6 +36,15 @@ public void parsesArrayIndirection() {
assertEquals(0, parsed.get(0).getIndex());
}
+ @Test
+ public void parsesArrayKeyRefIndirection() {
+ JsonPointer parsed = JsonPointer.parse("/id=ID_1");
+ assertFalse(parsed.isRoot());
+ assertEquals(1, parsed.size());
+ assertTrue(parsed.get(0).isArrayKeyRef());
+ assertEquals(new JsonPointer.KeyRef("id", "ID_1"), parsed.get(0).getKeyRef());
+ }
+
@Test
public void parsesArrayTailIndirection() {
JsonPointer parsed = JsonPointer.parse("/-");
@@ -99,9 +103,9 @@ public void parsesMultipleObjectIndirections() {
@Test
public void parsesMixedIndirections() {
- JsonPointer parsed = JsonPointer.parse("/0/a/1/b");
+ JsonPointer parsed = JsonPointer.parse("/0/a/1/b/id=2/c");
assertFalse(parsed.isRoot());
- assertEquals(4, parsed.size());
+ assertEquals(6, parsed.size());
assertTrue(parsed.get(0).isArrayIndex());
assertEquals(0, parsed.get(0).getIndex());
assertFalse(parsed.get(1).isArrayIndex());
@@ -110,6 +114,12 @@ public void parsesMixedIndirections() {
assertEquals(1, parsed.get(2).getIndex());
assertFalse(parsed.get(3).isArrayIndex());
assertEquals("b", parsed.get(3).getField());
+ assertFalse(parsed.get(4).isArrayIndex());
+ assertTrue(parsed.get(4).isArrayKeyRef());
+ assertEquals(new JsonPointer.KeyRef("id", "2"), parsed.get(4).getKeyRef());
+ assertFalse(parsed.get(5).isArrayIndex());
+ assertFalse(parsed.get(5).isArrayKeyRef());
+ assertEquals("c", parsed.get(5).getField());
}
@Test
@@ -130,6 +140,15 @@ public void parsesEscapedForwardSlash() {
assertEquals("/", parsed.get(0).getField());
}
+ @Test
+ public void parsesEscapedEqualsSign() {
+ JsonPointer parsed = JsonPointer.parse("/~2");
+ assertFalse(parsed.isRoot());
+ assertEquals(1, parsed.size());
+ assertFalse(parsed.get(0).isArrayIndex());
+ assertEquals("=", parsed.get(0).getField());
+ }
+
// Parsing error conditions --
@Test(expected = IllegalArgumentException.class)
@@ -139,7 +158,7 @@ public void throwsOnMissingLeadingSlash() {
@Test(expected = IllegalArgumentException.class)
public void throwsOnInvalidEscapedSequence1() {
- JsonPointer.parse("/~2");
+ JsonPointer.parse("/~3");
}
@Test(expected = IllegalArgumentException.class)
@@ -169,6 +188,27 @@ public void evaluatesAccordingToRFC6901() throws IOException, JsonPointerEvaluat
assertEquals(new BsonInt32(8), JsonPointer.parse("/m~0n").evaluate(testData));
}
+ @Test
+ public void evaluatesWithKeyReferences() throws IOException, JsonPointerEvaluationException {
+ BsonValue data = TestUtils.loadResourceAsBsonValue("/testdata/json-pointer-key-refs.json");
+ BsonValue testData = data.asDocument().get("testData");
+
+ assertEquals(BsonDocument.parse("{\"id\": \"ID_1\",\"some\": \"data_1\"}"), JsonPointer.parse("/objArray/id=ID_1").evaluate(testData));
+ assertEquals(new BsonString("data_1"), JsonPointer.parse("/objArray/id=ID_1/some").evaluate(testData));
+ assertEquals(new BsonString("data_2"), JsonPointer.parse("/objArray/id=ID_2/some").evaluate(testData));
+ assertEquals(new BsonString("some_more"), JsonPointer.parse("/objArray/id=ID_2/and").evaluate(testData));
+ assertEquals(new BsonInt32(7), JsonPointer.parse("/objArray/id=ID_2/num").evaluate(testData));
+ assertEquals(new BsonString("data_2"), JsonPointer.parse("/objArray/and=some_more/some").evaluate(testData));
+ assertEquals(new BsonString("data_3"), JsonPointer.parse("/objArray/id=ID_3/some").evaluate(testData));
+ assertEquals(new BsonString("data_4"), JsonPointer.parse("/objArray/id=ID_4/some").evaluate(testData));
+ assertEquals(new BsonString("data_4"), JsonPointer.parse("/objArray/3/some").evaluate(testData));
+
+ assertThrows(JsonPointerEvaluationException.class, () -> JsonPointer.parse("/objArray/id=ID_5").evaluate(testData));
+ assertThrows(JsonPointerEvaluationException.class, () -> JsonPointer.parse("/objArray/ref=REF").evaluate(testData));
+ assertThrows(JsonPointerEvaluationException.class, () -> JsonPointer.parse("/objArray/4").evaluate(testData));
+ }
+
+
// Utility methods --
@Test
@@ -189,5 +229,7 @@ public void symmetricalInParsingAndRendering() {
assertEquals("/k\"l", JsonPointer.parse("/k\"l").toString());
assertEquals("/ ", JsonPointer.parse("/ ").toString());
assertEquals("/m~0n", JsonPointer.parse("/m~0n").toString());
+ assertEquals("/m=n", JsonPointer.parse("/m=n").toString());
+ assertEquals("/m~2n", JsonPointer.parse("/m~2n").toString());
}
}
diff --git a/src/test/java/com/ebay/bsonpatch/JsonSplitReplaceOpTest.java b/src/test/java/io/github/bsonpatch/JsonSplitReplaceOpTest.java
similarity index 99%
rename from src/test/java/com/ebay/bsonpatch/JsonSplitReplaceOpTest.java
rename to src/test/java/io/github/bsonpatch/JsonSplitReplaceOpTest.java
index 74dc9dc..bb7f773 100644
--- a/src/test/java/com/ebay/bsonpatch/JsonSplitReplaceOpTest.java
+++ b/src/test/java/io/github/bsonpatch/JsonSplitReplaceOpTest.java
@@ -1,4 +1,4 @@
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import org.bson.BsonArray;
import org.bson.BsonDocument;
diff --git a/src/test/java/com/ebay/bsonpatch/MoveOperationTest.java b/src/test/java/io/github/bsonpatch/MoveOperationTest.java
similarity index 96%
rename from src/test/java/com/ebay/bsonpatch/MoveOperationTest.java
rename to src/test/java/io/github/bsonpatch/MoveOperationTest.java
index 96c2a82..43b0fd3 100644
--- a/src/test/java/com/ebay/bsonpatch/MoveOperationTest.java
+++ b/src/test/java/io/github/bsonpatch/MoveOperationTest.java
@@ -17,13 +17,7 @@
* under the License.
*/
-package com.ebay.bsonpatch;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.Assert.assertThat;
-
-import java.io.IOException;
-import java.util.Collection;
+package io.github.bsonpatch;
import org.bson.BsonArray;
import org.bson.BsonDocument;
@@ -31,6 +25,12 @@
import org.junit.Test;
import org.junit.runners.Parameterized;
+import java.io.IOException;
+import java.util.Collection;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
public class MoveOperationTest extends AbstractTest {
@Parameterized.Parameters
diff --git a/src/test/java/com/ebay/bsonpatch/PatchTestCase.java b/src/test/java/io/github/bsonpatch/PatchTestCase.java
similarity index 91%
rename from src/test/java/com/ebay/bsonpatch/PatchTestCase.java
rename to src/test/java/io/github/bsonpatch/PatchTestCase.java
index 81a96a2..273c0c4 100644
--- a/src/test/java/com/ebay/bsonpatch/PatchTestCase.java
+++ b/src/test/java/io/github/bsonpatch/PatchTestCase.java
@@ -17,16 +17,16 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.bson.BsonDocument;
+import org.bson.BsonValue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import org.bson.BsonDocument;
-import org.bson.BsonValue;
-
public class PatchTestCase {
private final boolean operation;
@@ -73,4 +73,9 @@ private static boolean isEnabled(BsonValue node) {
BsonValue disabled = node.asDocument().get("disabled");
return (disabled == null || !disabled.asBoolean().getValue());
}
+
+ public boolean isApplyInPlaceSupported() {
+ BsonValue allowInPlace = node.get("allowInPlace");
+ return (allowInPlace == null || allowInPlace.asBoolean().getValue());
+ }
}
diff --git a/src/test/java/com/ebay/bsonpatch/RFC6901Tests.java b/src/test/java/io/github/bsonpatch/RFC6901Tests.java
similarity index 95%
rename from src/test/java/com/ebay/bsonpatch/RFC6901Tests.java
rename to src/test/java/io/github/bsonpatch/RFC6901Tests.java
index 622846d..7eaa03f 100644
--- a/src/test/java/com/ebay/bsonpatch/RFC6901Tests.java
+++ b/src/test/java/io/github/bsonpatch/RFC6901Tests.java
@@ -1,14 +1,14 @@
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonValue;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-
import java.io.IOException;
+import static org.junit.Assert.assertEquals;
+
public class RFC6901Tests {
@Test
diff --git a/src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java b/src/test/java/io/github/bsonpatch/RemoveOperationTest.java
similarity index 97%
rename from src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java
rename to src/test/java/io/github/bsonpatch/RemoveOperationTest.java
index 7b8a4e6..46b4509 100644
--- a/src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java
+++ b/src/test/java/io/github/bsonpatch/RemoveOperationTest.java
@@ -17,13 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Collection;
-import org.junit.runners.Parameterized;
-
public class RemoveOperationTest extends AbstractTest {
@Parameterized.Parameters
diff --git a/src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java b/src/test/java/io/github/bsonpatch/ReplaceOperationTest.java
similarity index 97%
rename from src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java
rename to src/test/java/io/github/bsonpatch/ReplaceOperationTest.java
index 516745b..ef4a6ba 100644
--- a/src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java
+++ b/src/test/java/io/github/bsonpatch/ReplaceOperationTest.java
@@ -17,13 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Collection;
-import org.junit.runners.Parameterized;
-
public class ReplaceOperationTest extends AbstractTest {
@Parameterized.Parameters
diff --git a/src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java b/src/test/java/io/github/bsonpatch/Rfc6902SamplesTest.java
similarity index 97%
rename from src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java
rename to src/test/java/io/github/bsonpatch/Rfc6902SamplesTest.java
index 1109931..3484520 100644
--- a/src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java
+++ b/src/test/java/io/github/bsonpatch/Rfc6902SamplesTest.java
@@ -17,13 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Collection;
-import org.junit.runners.Parameterized;
-
public class Rfc6902SamplesTest extends AbstractTest {
@Parameterized.Parameters
diff --git a/src/test/java/com/ebay/bsonpatch/TestDataGenerator.java b/src/test/java/io/github/bsonpatch/TestDataGenerator.java
similarity index 99%
rename from src/test/java/com/ebay/bsonpatch/TestDataGenerator.java
rename to src/test/java/io/github/bsonpatch/TestDataGenerator.java
index 6237a3a..9b44b26 100644
--- a/src/test/java/com/ebay/bsonpatch/TestDataGenerator.java
+++ b/src/test/java/io/github/bsonpatch/TestDataGenerator.java
@@ -17,17 +17,17 @@
* under the License.
*/
-package com.ebay.bsonpatch;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
+package io.github.bsonpatch;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonInt32;
import org.bson.BsonString;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
public class TestDataGenerator {
private static Random random = new Random();
private static List name = Arrays.asList("summers", "winters", "autumn", "spring", "rainy");
diff --git a/src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java b/src/test/java/io/github/bsonpatch/TestNodesEmissionTest.java
similarity index 97%
rename from src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java
rename to src/test/java/io/github/bsonpatch/TestNodesEmissionTest.java
index c273b3e..23e4e69 100644
--- a/src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java
+++ b/src/test/java/io/github/bsonpatch/TestNodesEmissionTest.java
@@ -1,15 +1,15 @@
-package com.ebay.bsonpatch;
-
-import java.io.IOException;
-import java.util.EnumSet;
-
-import static org.junit.Assert.*;
+package io.github.bsonpatch;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonValue;
import org.junit.Test;
+import java.io.IOException;
+import java.util.EnumSet;
+
+import static org.junit.Assert.assertEquals;
+
public class TestNodesEmissionTest {
private static EnumSet flags;
diff --git a/src/test/java/com/ebay/bsonpatch/TestOperationTest.java b/src/test/java/io/github/bsonpatch/TestOperationTest.java
similarity index 97%
rename from src/test/java/com/ebay/bsonpatch/TestOperationTest.java
rename to src/test/java/io/github/bsonpatch/TestOperationTest.java
index f5c0648..a0c3bc7 100644
--- a/src/test/java/com/ebay/bsonpatch/TestOperationTest.java
+++ b/src/test/java/io/github/bsonpatch/TestOperationTest.java
@@ -17,13 +17,13 @@
* under the License.
*/
-package com.ebay.bsonpatch;
+package io.github.bsonpatch;
+
+import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Collection;
-import org.junit.runners.Parameterized;
-
public class TestOperationTest extends AbstractTest {
@Parameterized.Parameters
diff --git a/src/test/java/io/github/bsonpatch/TestUtils.java b/src/test/java/io/github/bsonpatch/TestUtils.java
new file mode 100644
index 0000000..ee2560e
--- /dev/null
+++ b/src/test/java/io/github/bsonpatch/TestUtils.java
@@ -0,0 +1,52 @@
+package io.github.bsonpatch;
+
+import org.apache.commons.io.IOUtils;
+import org.bson.BsonDocument;
+import org.bson.BsonValue;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class TestUtils {
+
+ private TestUtils() {
+ }
+
+ public static BsonValue loadResourceAsBsonValue(String path) throws IOException {
+ String testData = loadFromResources(path);
+ return BsonDocument.parse(testData);
+ }
+
+ public static String loadFromResources(String path) throws IOException {
+ InputStream resourceAsStream = PatchTestCase.class.getResourceAsStream(path);
+ return IOUtils.toString(resourceAsStream, "UTF-8");
+ }
+
+ public static String stripJsonComments(String s) {
+ StringBuilder out = new StringBuilder();
+ boolean inStr = false, esc = false, inLine = false, inBlock = false;
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i), n = (i + 1 < s.length()) ? s.charAt(i + 1) : '\0';
+ if (inLine) {
+ if (c == '\n') { inLine = false; out.append(c); }
+ continue;
+ }
+ if (inBlock) {
+ if (c == '*' && n == '/') { inBlock = false; i++; }
+ continue;
+ }
+ if (inStr) {
+ out.append(c);
+ if (!esc && c == '\\') { esc = true; }
+ else if (esc) { esc = false; }
+ else if (c == '"') { inStr = false; }
+ continue;
+ }
+ if (c == '"') { inStr = true; out.append(c); continue; }
+ if (c == '/' && n == '/') { inLine = true; i++; continue; }
+ if (c == '/' && n == '*') { inBlock = true; i++; continue; }
+ out.append(c);
+ }
+ return out.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/io/github/bsonpatch/ValidationTest.java b/src/test/java/io/github/bsonpatch/ValidationTest.java
new file mode 100644
index 0000000..cae9803
--- /dev/null
+++ b/src/test/java/io/github/bsonpatch/ValidationTest.java
@@ -0,0 +1,40 @@
+package io.github.bsonpatch;
+
+import org.bson.BsonArray;
+import org.bson.BsonValue;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class ValidationTest {
+
+ @ParameterizedTest
+ @MethodSource("argsForValidationTest")
+ public void testValidation(BsonArray patch) {
+ assertThrows(
+ InvalidBsonPatchException.class,
+ () -> BsonPatch.validate(patch)
+ );
+ }
+
+ public static Stream argsForValidationTest() throws IOException {
+ BsonValue patches = BsonArray.parse(
+ TestUtils.stripJsonComments(
+ TestUtils.loadFromResources("/testdata/invalid-patches.json")));
+
+ List args = new ArrayList<>();
+
+ for (BsonValue patch : patches.asArray()) {
+ args.add(Arguments.of(patch));
+ }
+
+ return args.stream();
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/testdata/invalid-patches.json b/src/test/resources/testdata/invalid-patches.json
new file mode 100644
index 0000000..bfdad2f
--- /dev/null
+++ b/src/test/resources/testdata/invalid-patches.json
@@ -0,0 +1,37 @@
+[
+ // no operation
+ [{"path": "/field1", "value": {"id":123}}],
+
+ // TEST operation with no path
+ [{"op": "test", "value": {"id":123}}],
+
+ // TEST operation with no value
+ [{"op": "test", "path": "/field1"}],
+
+ // TEST operation with non-text 'path' attribute
+ [{"op": "test", "path": 1, "value": {"id":123}}],
+
+ // ADD operation with no 'path' attribute
+ [{"op": "add", "value": "b"}],
+
+ // ADD operation with non-text 'path' attribute
+ [{"op": "add", "path": 123, "value": "b"}],
+
+ // ADD operation with no 'value' attribute
+ [{"op": "add", "path": "/field1/a"}],
+
+ // REPLACE operation patch with no 'value' attribute
+ [{"op": "replace", "path": "/field1/a"}],
+
+ // MOVE operation with no 'from' attribute
+ [{"op": "move", "path": "/field1/a"}],
+
+ // COPY operation with no 'from' attribute
+ [{"op": "move", "path": "/field1/a"}],
+
+ // MOVE operation with no non-text 'from' attribute
+ [{"op": "move", "path": "/field1/a", "from": 123}],
+
+ // COPY operation with no non-text 'from' attribute
+ [{"op": "copy", "path": "/field1/a", "from": 123}]
+]
\ No newline at end of file
diff --git a/src/test/resources/testdata/js-libs-samples.json b/src/test/resources/testdata/js-libs-samples.json
index 3a56ea0..2b71e35 100644
--- a/src/test/resources/testdata/js-libs-samples.json
+++ b/src/test/resources/testdata/js-libs-samples.json
@@ -75,12 +75,14 @@
{ "message": "replacing the root of the document is possible with add",
"node": {"foo": "bar"},
"op": [{"op": "add", "path": "", "value": {"baz": "qux"}}],
- "expected": {"baz":"qux"}},
+ "expected": {"baz":"qux"},
+ "allowInPlace": false },
{ "message": "replacing the root of the document is possible with add",
"node": {"foo": "bar"},
"op": [{"op": "add", "path": "", "value": ["baz", "qux"]}],
- "expected": ["baz", "qux"]},
+ "expected": ["baz", "qux"],
+ "allowInPlace": false },
{ "message": "empty list, empty docs",
"node": {},
@@ -235,7 +237,8 @@
{ "message": "replace whole document",
"node": {"foo": "bar"},
"op": [{"op": "replace", "path": "", "value": {"baz": "qux"}}],
- "expected": {"baz": "qux"} },
+ "expected": {"baz": "qux"},
+ "allowInPlace": false },
{ "node": {"foo": null},
"op": [{"op": "replace", "path": "/foo", "value": "truthy"}],
diff --git a/src/test/resources/testdata/json-pointer-key-refs.json b/src/test/resources/testdata/json-pointer-key-refs.json
new file mode 100644
index 0000000..0ef7338
--- /dev/null
+++ b/src/test/resources/testdata/json-pointer-key-refs.json
@@ -0,0 +1,26 @@
+{
+ "testData": {
+ "objArray": [
+ {
+ "id": "ID_1",
+ "some": "data_1"
+ },
+ {
+ "id": "ID_2",
+ "some": "data_2",
+ "and": "some_more",
+ "num": 7
+ },
+ {
+ "id": "ID_3",
+ "some": "data_3",
+ "and": "some_more"
+ },
+ {
+ "id": "ID_4",
+ "some": "data_4",
+ "and": "some_more"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/testdata/replace.json b/src/test/resources/testdata/replace.json
index 3865d52..9e31520 100644
--- a/src/test/resources/testdata/replace.json
+++ b/src/test/resources/testdata/replace.json
@@ -21,7 +21,8 @@
{
"op": [{ "op": "replace", "path": "", "value": false }],
"node": { "x": { "a": "b", "y": {} } },
- "expected": false
+ "expected": false,
+ "allowInPlace": false
},
{
"op": [{ "op": "replace", "path": "/x/y", "value": "hello" }],