Skip to content

Commit

Permalink
Merge branch 'holograph-issue-39'
Browse files Browse the repository at this point in the history
  • Loading branch information
vishwakarma committed Jul 26, 2017
2 parents 680de20 + 1b2dbb8 commit e7f2500
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 104 deletions.
163 changes: 80 additions & 83 deletions src/main/java/com/flipkart/zjsonpatch/InPlaceApplyProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ public JsonNode result() {

@Override
public void move(List<String> fromPath, List<String> toPath) {
JsonNode parentNode = getParentNode(fromPath);
JsonNode parentNode = getParentNode(fromPath, Operation.MOVE);
String field = fromPath.get(fromPath.size() - 1).replaceAll("\"", "");
JsonNode valueNode = parentNode.isArray() ? parentNode.get(Integer.parseInt(field)) : parentNode.get(field);
JsonNode valueNode = parentNode.isArray() ? parentNode.get(Integer.parseInt(field)) : parentNode.get(field);
remove(fromPath);
add(toPath, valueNode);
}

@Override
public void copy(List<String> fromPath, List<String> toPath) {
JsonNode parentNode = getParentNode(fromPath);
JsonNode parentNode = getParentNode(fromPath, Operation.COPY);
String field = fromPath.get(fromPath.size() - 1).replaceAll("\"", "");
JsonNode valueNode = parentNode.isArray() ? parentNode.get(Integer.parseInt(field)) : parentNode.get(field);
add(toPath, valueNode);
Expand All @@ -55,67 +55,61 @@ public void copy(List<String> fromPath, List<String> toPath) {
@Override
public void test(List<String> path, JsonNode value) {
if (path.isEmpty()) {
throw new JsonPatchApplicationException("[TEST Operation] path is empty , path : ");
error(Operation.TEST, "path is empty , path : ");
} else {
JsonNode parentNode = getParentNode(path);
if (parentNode == null) {
throw new JsonPatchApplicationException("[TEST Operation] noSuchPath in source, path provided : " + path);
} else {
String fieldToReplace = path.get(path.size() - 1).replaceAll("\"", "");
if (fieldToReplace.equals("") && path.size() == 1)
if(target.equals(value)){
target = value;
}else {
throw new JsonPatchApplicationException("[TEST Operation] value mismatch");
}
else if (!parentNode.isContainerNode())
throw new JsonPatchApplicationException("[TEST Operation] parent is not a container in source, path provided : " + path + " | node : " + parentNode);
else if (parentNode.isArray()) {
final ArrayNode target = (ArrayNode) parentNode;
String idxStr = path.get(path.size() - 1);

if ("-".equals(idxStr)) {
// see http://tools.ietf.org/html/rfc6902#section-4.1
if(!target.get(target.size()-1).equals(value)){
throw new JsonPatchApplicationException("[TEST Operation] value mismatch");
}
} else {
int idx = arrayIndex(idxStr.replaceAll("\"", ""), target.size());
if(!target.get(idx).equals(value)){
throw new JsonPatchApplicationException("[TEST Operation] value mismatch");
}
}
JsonNode parentNode = getParentNode(path, Operation.TEST);
String fieldToReplace = path.get(path.size() - 1).replaceAll("\"", "");
if (fieldToReplace.equals("") && path.size() == 1)
if(target.equals(value)){
target = value;
}else {
error(Operation.TEST, "value mismatch");
}
else {
final ObjectNode target = (ObjectNode) parentNode;
String key = path.get(path.size() - 1).replaceAll("\"", "");
if(!target.get(key).equals(value)){
throw new JsonPatchApplicationException("[TEST Operation] value mismatch");
else if (!parentNode.isContainerNode())
error(Operation.TEST, "parent is not a container in source, path provided : " + path + " | node : " + parentNode);
else if (parentNode.isArray()) {
final ArrayNode target = (ArrayNode) parentNode;
String idxStr = path.get(path.size() - 1);

if ("-".equals(idxStr)) {
// see http://tools.ietf.org/html/rfc6902#section-4.1
if(!target.get(target.size()-1).equals(value)){
error(Operation.TEST, "value mismatch");
}
} else {
int idx = arrayIndex(idxStr.replaceAll("\"", ""), target.size());
if(!target.get(idx).equals(value)){
error(Operation.TEST, "value mismatch");
}
}
}
else {
final ObjectNode target = (ObjectNode) parentNode;
String key = path.get(path.size() - 1).replaceAll("\"", "");
JsonNode actual = target.get(key);
if (actual == null)
error(Operation.TEST, "noSuchPath in source, path provided : " + path);
else if (!actual.equals(value))
error(Operation.TEST, "value mismatch");
}
}
}

@Override
public void add(List<String> path, JsonNode value) {
if (path.isEmpty()) {
throw new JsonPatchApplicationException("[ADD Operation] path is empty , path : ");
error(Operation.ADD, "path is empty , path : ");
} else {
JsonNode parentNode = getParentNode(path);
if (parentNode == null) {
throw new JsonPatchApplicationException("[ADD Operation] noSuchPath in source, path provided : " + path);
} else {
String fieldToReplace = path.get(path.size() - 1).replaceAll("\"", "");
if (fieldToReplace.equals("") && path.size() == 1)
target = value;
else if (!parentNode.isContainerNode())
throw new JsonPatchApplicationException("[ADD Operation] parent is not a container in source, path provided : " + path + " | node : " + parentNode);
else if (parentNode.isArray())
addToArray(path, value, parentNode);
else
addToObject(path, parentNode, value);
}
JsonNode parentNode = getParentNode(path, Operation.ADD);
String fieldToReplace = path.get(path.size() - 1).replaceAll("\"", "");
if (fieldToReplace.equals("") && path.size() == 1)
target = value;
else if (!parentNode.isContainerNode())
error(Operation.ADD, "parent is not a container in source, path provided : " + path + " | node : " + parentNode);
else if (parentNode.isArray())
addToArray(path, value, parentNode);
else
addToObject(path, parentNode, value);
}
}

Expand All @@ -141,48 +135,46 @@ private void addToArray(List<String> path, JsonNode value, JsonNode parentNode)
@Override
public void replace(List<String> path, JsonNode value) {
if (path.isEmpty()) {
throw new JsonPatchApplicationException("[Replace Operation] path is empty");
error(Operation.REPLACE, "path is empty");
} else {
JsonNode parentNode = getParentNode(path);
if (parentNode == null) {
throw new JsonPatchApplicationException("[Replace Operation] noSuchPath in source, path provided : " + path);
} else {
String fieldToReplace = path.get(path.size() - 1).replaceAll("\"", "");
if (Strings.isNullOrEmpty(fieldToReplace) && path.size() == 1)
target = value;
else if (parentNode.isObject())
((ObjectNode) parentNode).put(fieldToReplace, value);
else if (parentNode.isArray())
((ArrayNode) parentNode).set(arrayIndex(fieldToReplace, parentNode.size() - 1), value);
else
throw new JsonPatchApplicationException("[Replace Operation] noSuchPath in source, path provided : " + path);
}
JsonNode parentNode = getParentNode(path, Operation.REPLACE);
String fieldToReplace = path.get(path.size() - 1).replaceAll("\"", "");
if (Strings.isNullOrEmpty(fieldToReplace) && path.size() == 1)
target = value;
else if (parentNode.isObject())
((ObjectNode) parentNode).put(fieldToReplace, value);
else if (parentNode.isArray())
((ArrayNode) parentNode).set(arrayIndex(fieldToReplace, parentNode.size() - 1), value);
else
error(Operation.REPLACE, "noSuchPath in source, path provided : " + path);
}
}

@Override
public void remove(List<String> path) {
if (path.isEmpty()) {
throw new JsonPatchApplicationException("[Remove Operation] path is empty");
error(Operation.REMOVE, "path is empty");
} else {
JsonNode parentNode = getParentNode(path);
if (parentNode == null) {
throw new JsonPatchApplicationException("[Remove Operation] noSuchPath in source, path provided : " + path);
} else {
String fieldToRemove = path.get(path.size() - 1).replaceAll("\"", "");
if (parentNode.isObject())
((ObjectNode) parentNode).remove(fieldToRemove);
else if (parentNode.isArray())
((ArrayNode) parentNode).remove(arrayIndex(fieldToRemove, parentNode.size() - 1));
else
throw new JsonPatchApplicationException("[Remove Operation] noSuchPath in source, path provided : " + path);
}
JsonNode parentNode = getParentNode(path, Operation.REMOVE);
String fieldToRemove = path.get(path.size() - 1).replaceAll("\"", "");
if (parentNode.isObject())
((ObjectNode) parentNode).remove(fieldToRemove);
else if (parentNode.isArray())
((ArrayNode) parentNode).remove(arrayIndex(fieldToRemove, parentNode.size() - 1));
else
error(Operation.REMOVE, "noSuchPath in source, path provided : " + path);
}
}

private JsonNode getParentNode(List<String> fromPath) {
private void error(Operation forOp, String message) {
throw new JsonPatchApplicationException("[" + forOp + " Operation] " + message);
}

private JsonNode getParentNode(List<String> fromPath, Operation forOp) {
List<String> pathToParent = fromPath.subList(0, fromPath.size() - 1); // would never by out of bound, lets see
return getNode(target, pathToParent, 1);
JsonNode node = getNode(target, pathToParent, 1);
if (node == null) error(forOp, "noSuchPath in source, path provided: " + fromPath);
return node;
}

private JsonNode getNode(JsonNode ret, List<String> path, int pos) {
Expand All @@ -208,7 +200,12 @@ private JsonNode getNode(JsonNode ret, List<String> path, int pos) {
}

private int arrayIndex(String s, int max) {
int index = Integer.parseInt(s);
int index;
try {
index = Integer.parseInt(s);
} catch (NumberFormatException nfe) {
throw new JsonPatchApplicationException("Object operation on array target");
}
if (index < 0) {
throw new JsonPatchApplicationException("index Out of bound, index is negative");
} else if (index > max) {
Expand Down
63 changes: 57 additions & 6 deletions src/test/java/com/flipkart/zjsonpatch/AbstractTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@

package com.flipkart.zjsonpatch;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.output.StringBuilderWriter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;

import java.io.PrintWriter;
import java.io.StringWriter;

import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

Expand All @@ -32,16 +40,20 @@ public abstract class AbstractTest {
@Parameter
public PatchTestCase p;

protected boolean matchOnErrors() {
return true;
}

@Test
public void test() throws Exception {
if (p.isOperation()) {
testOpertaion();
testOperation();
} else {
testError();
}
}

private void testOpertaion() throws Exception {
private void testOperation() throws Exception {
JsonNode node = p.getNode();

JsonNode first = node.get("node");
Expand All @@ -54,17 +66,56 @@ private void testOpertaion() throws Exception {
assertThat(message, secondPrime, equalTo(second));
}

private void testError() {
JsonNode node = p.getNode();
private Class<?> exceptionType(String type) throws ClassNotFoundException {
return Class.forName(type.contains(".") ? type : "com.flipkart.zjsonpatch." + type);
}

private String errorMessage(String header) throws JsonProcessingException {
return errorMessage(header, null);
}
private String errorMessage(String header, Exception e) throws JsonProcessingException {
StringBuilder res =
new StringBuilder()
.append(header)
.append("\nFull test case (in file ")
.append(p.getSourceFile())
.append("):\n")
.append(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(p.getNode()));
if (e != null) {
res.append("\nFull error: ");
e.printStackTrace(new PrintWriter(new StringBuilderWriter(res)));
}
return res.toString();
}

private void testError() throws JsonProcessingException, ClassNotFoundException {
JsonNode node = p.getNode();
JsonNode first = node.get("node");
JsonNode patch = node.get("op");
JsonNode message = node.get("message");
Class<?> type =
node.has("type") ? exceptionType(node.get("type").textValue()) : JsonPatchApplicationException.class;

try {
JsonPatch.apply(patch, first);

fail("Failure expected: " + node.get("message"));
} catch (Exception ex) {
fail(errorMessage("Failure expected: " + message));
} catch (Exception e) {
if (matchOnErrors()) {
StringWriter fullError = new StringWriter();
e.printStackTrace(new PrintWriter(fullError));

assertThat(
errorMessage("Operation failed but with wrong exception type", e),
e,
instanceOf(type));
if (message != null) {
assertThat(
errorMessage("Operation failed but with wrong message", e),
e.getMessage(),
containsString(message.textValue())); // equalTo would be better, but fail existing tests
}
}
}
}
}
8 changes: 7 additions & 1 deletion src/test/java/com/flipkart/zjsonpatch/JsLibSamplesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@

package com.flipkart.zjsonpatch;

import org.junit.runners.Parameterized;

import java.io.IOException;
import java.util.Collection;
import org.junit.runners.Parameterized;

/**
* @author ctranxuan (streamdata.io).
Expand All @@ -33,4 +34,9 @@ public class JsLibSamplesTest extends AbstractTest {
public static Collection<PatchTestCase> data() throws IOException {
return PatchTestCase.load("js-libs-samples");
}

@Override
protected boolean matchOnErrors() {
return false;
}
}
Loading

0 comments on commit e7f2500

Please sign in to comment.