/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.server.remoting.davex;
import junit.framework.TestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/** <code>DiffParserTest</code>... */
public class DiffParserTest extends TestCase {
public void testSetProperty() throws IOException, DiffException {
ArrayList<String> l = new ArrayList<String>();
l.add("\"simple string\"");
l.add("2345");
l.add("true");
l.add("false");
l.add("234.3455");
l.add("null");
for (final String value : l) {
String diff = "^/a/prop : " + value;
DummyDiffHandler handler = new DummyDiffHandler() {
@Override
public void setProperty(String targetPath, String diffValue) {
assertEquals(targetPath, "/a/prop");
assertEquals(value, diffValue);
}
};
DiffParser parser = new DiffParser(handler);
parser.parse(diff);
}
}
public void testSetPropertyMissing() throws IOException,
DiffException {
ArrayList<String> l = new ArrayList<String>();
l.add("");
l.add(null);
for (String value : l) {
String diff = "^/a/prop : " + ((value == null) ? "" : value);
DummyDiffHandler handler = new DummyDiffHandler() {
@Override
public void setProperty(String targetPath, String diffValue) {
assertEquals(targetPath, "/a/prop");
assertTrue(diffValue == null || "".equals(diffValue));
}
};
DiffParser parser = new DiffParser(handler);
parser.parse(diff);
}
}
public void testSetPropertyWithUnicodeChars() throws IOException,
DiffException {
final String value = "\"String value containing \u2355\u8723 unicode chars.\"";
String diff = "^/a/prop : " + value;
DiffHandler handler = new DummyDiffHandler() {
@Override
public void setProperty(String targetPath, String diffValue) {
assertEquals(targetPath, "/a/prop");
assertEquals(value, diffValue);
}
};
DiffParser parser = new DiffParser(handler);
parser.parse(diff);
}
public void testSetPropertyWithTrailingLineSep() throws IOException,
DiffException {
final String value = "\"String value ending with \r\r\n\n\r\n.\"";
String diff = "^/a/prop : " + value;
DiffHandler handler = new DummyDiffHandler() {
@Override
public void setProperty(String targetPath, String diffValue) {
assertEquals(targetPath, "/a/prop");
assertEquals(value, diffValue);
}
};
DiffParser parser = new DiffParser(handler);
parser.parse(diff);
}
public void testSetPropertyWithSpecialChar() throws IOException, DiffException {
final String value = "+abc \\r+ \\n-ab >c \r\\r\\n+";
String diff = "^/a/prop : " + value;
DiffHandler handler = new DummyDiffHandler() {
@Override
public void setProperty(String targetPath, String diffValue) {
assertEquals(targetPath, "/a/prop");
assertEquals(value, diffValue);
}
};
DiffParser parser = new DiffParser(handler);
parser.parse(diff);
}
public void testSetPropertyUnterminatedString() throws IOException,
DiffException {
final String value = "\"String value ending with \r\r\n\n\r\n.";
String diff = "^/a/prop : " + value;
DiffHandler handler = new DummyDiffHandler() {
@Override
public void setProperty(String targetPath, String diffValue) {
assertEquals(targetPath, "/a/prop");
assertEquals(value, diffValue);
}
};
DiffParser parser = new DiffParser(handler);
parser.parse(diff);
}
public void testSetPropertyWithUnescapedAction() throws IOException,
DiffException {
String diff = "^abc : \r+def : \n-ghi : \r\n^jkl : \n\r>mno : \n";
DiffHandler handler = new DummyDiffHandler() {
@Override
public void addNode(String targetPath, String diffValue) {
assertEquals("def", targetPath);
assertEquals("", diffValue);
}
@Override
public void setProperty(String targetPath, String diffValue) {
assertTrue("abc".equals(targetPath) || "jkl".equals(targetPath));
assertEquals("", diffValue);
}
@Override
public void remove(String targetPath, String diffValue) {
assertEquals("ghi", targetPath);
assertEquals("", diffValue);
}
@Override
public void move(String targetPath, String diffValue) {
assertEquals("mno", targetPath);
assertEquals("\n", diffValue);
}
};
DiffParser parser = new DiffParser(handler);
parser.parse(diff);
}
public void testValidDiffs() throws IOException, DiffException {
List<String[]> l = new ArrayList<String[]>();
// unquoted string value
l.add(new String[] {"+/a/b : 134", "/a/b","134"});
l.add(new String[] {"+/a/b : 2.3", "/a/b","2.3"});
l.add(new String[] {"+/a/b : true", "/a/b","true"});
// quoted string value
l.add(new String[] {"+/a/b : \"true\"", "/a/b","\"true\""});
l.add(new String[] {"+/a/b : \"string value containing \u3456 unicode char.\"", "/a/b","\"string value containing \u3456unicode char.\""});
// value consisting of quotes
l.add(new String[] {"+/a/b : \"", "/a/b","\""});
l.add(new String[] {"+/a/b : \"\"", "/a/b","\"\""});
// value consisting of single
l.add(new String[] {"+/a/b : '", "/a/b","'"});
l.add(new String[] {"+/a/b : ''''", "/a/b","''''"});
// value consisting of space(s) only
l.add(new String[] {"+/a/b : ", "/a/b"," "});
l.add(new String[] {"+/a/b : ", "/a/b"," "});
// value consisting of line separators only
l.add(new String[] {"+/a/b : \n", "/a/b","\n"});
l.add(new String[] {"+/a/b : \r", "/a/b","\r"});
l.add(new String[] {"+/a/b : \r\n", "/a/b","\r\n"});
l.add(new String[] {"+/a/b : \r\n\n\r", "/a/b","\r\n\n\r"});
// path containing white space
l.add(new String[] {"+/a /b : 123", "/a /b","123"});
l.add(new String[] {"+/a\r\t/b : 123", "/a\r\t/b","123"});
// path having trailing white space
l.add(new String[] {"+/a/b : 123", "/a/b","123"});
l.add(new String[] {"+/a/b\r : 123", "/a/b\r","123"});
l.add(new String[] {"+/a/b\r\n\n\r\n: 123", "/a/b\r\n\n\r\n","123"});
// path containing reserved characters
l.add(new String[] {"++abc+ : val", "+abc+","val"});
l.add(new String[] {"++++++ : val", "+++++","val"});
// value containing reserved characters
l.add(new String[] {"+/a/b : +", "/a/b","+"});
l.add(new String[] {"+/a/b : +->+-", "/a/b","+->+-"});
l.add(new String[] {"+/a/b : \"+->+-\"", "/a/b","\"+->+-\""});
// other white space than ' ' used as key-value separator
l.add(new String[] {"+/a/b :\r123", "/a/b","123"});
l.add(new String[] {"+/a/b\r: 123", "/a/b","123"});
l.add(new String[] {"+/a/b\r:\r123", "/a/b","123"});
l.add(new String[] {"+/a/b\r:\n123", "/a/b","123"});
l.add(new String[] {"+/a/b\t:\r123", "/a/b","123"});
l.add(new String[] {"+/a/b\t:\t123", "/a/b","123"});
// path containing colon
l.add(new String[] {"+/a:b/c:d : 123", "/a:b/c:d","123"});
// value starting with colon -> ok
l.add(new String[] {"+/a/b : : val", "/a/b",": val"});
// missing value
l.add(new String[] {"+/a/b : ", "/a/b", ""});
l.add(new String[] {"+/a/b :\n", "/a/b", ""});
for (final String[] strs : l) {
DiffHandler hndl = new DummyDiffHandler() {
@Override
public void setProperty(String targetPath, String diffValue) {
assertEquals(strs[1], targetPath);
assertEquals(strs[2], diffValue);
}
};
DiffParser parser = new DiffParser(hndl);
parser.parse(strs[0]);
}
List<String> l2 = new ArrayList<String>();
// multiple commands
l2.add("+abc :\n\n+def : val");
l2.add("+abc :\n\n+def : val\n");
l2.add("+abc : \r+def : val");
l2.add("+/a/b : val\r+abc : \r ");
l2.add("+/a/b : val\r+abc :\n\n ");
// missing value in the last action.
l2.add("+/a/b : \r+abc :\n");
l2.add("+/a/b : \\r+abc : abc\r\r+abc :\r");
l2.add("+abc :\n\n+def : val\r\r>abc : ");
for (String diff : l2) {
final List<String> li = new ArrayList<String>();
DiffHandler dh = new DummyDiffHandler() {
@Override
public void addNode(String targetPath, String diffValue) {
li.add(diffValue);
}
};
DiffParser parser = new DiffParser(dh);
parser.parse(diff);
assertEquals(2, li.size());
}
}
public void testSeparatorLines() throws IOException, DiffException {
String diff = "+abc :\n\n+val : val";
DiffHandler dh = new DummyDiffHandler() {
@Override
public void addNode(String targetPath, String diffValue) {
if ("abc".equals(targetPath)) {
assertEquals("", diffValue);
} else {
assertEquals("val", diffValue);
}
}
};
new DiffParser(dh).parse(diff);
diff = "+abc :\n+val : val";
dh = new DummyDiffHandler() {
@Override
public void addNode(String targetPath, String diffValue) {
assertEquals("+val : val", diffValue);
}
};
new DiffParser(dh).parse(diff);
// TODO: check again: currently all line separation chars before an diff-char are ignored unless they are escaped in way the handler understands (e.g. JSON does: \\r for \r).
diff = "+abc :\r\r\r+def : val";
dh = new DummyDiffHandler() {
@Override
public void addNode(String targetPath, String diffValue) {
if ("abc".equals(targetPath)) {
assertEquals("", diffValue);
} else {
assertEquals("val", diffValue);
}
}
};
new DiffParser(dh).parse(diff);
diff = "+abc : val\r+def :\n\n ";
dh = new DummyDiffHandler() {
@Override
public void addNode(String targetPath, String diffValue) {
if ("abc".equals(targetPath)) {
assertEquals("val", diffValue);
} else {
assertEquals("\n ", diffValue);
}
}
};
new DiffParser(dh).parse(diff);
}
public void testUnicodeLineSep() throws IOException, DiffException {
String diff = "+abc : val" + new String(new byte[] {Character.LINE_SEPARATOR}, "utf-8") + "+abc : val";
DiffHandler dh = new DummyDiffHandler() {
@Override
public void addNode(String targetPath, String diffValue) {
assertEquals("abc", targetPath);
assertEquals("val", diffValue);
}
};
new DiffParser(dh).parse(diff);
}
public void testInvalidDiff() throws IOException, DiffException {
List<String> l = new ArrayList<String>();
l.add("");
// path, separator and value missing
l.add("+");
l.add("+/a/b : val\r+");
// path starting with white space, separator and value missing
l.add("+\n");
// separator and value missing
l.add("+/a/b");
l.add("+/a/b : val\r+abc\n");
l.add("+/a/b :");
// invalid for separator and value are missing (all : and white space
// is interpreted as part of the path.
l.add("+/a/b:");
l.add("+/a/b:val");
l.add("+/a/b: val");
l.add("+/a/b:\rval");
l.add("+/a/b :: val");
// diff starting with white space
l.add(" +/a/b: val");
l.add("\r\r\r\r\r\r+/a/b: val");
// key starting with white space
l.add("+\r/a/b : 123");
l.add("+ /a/b : 123");
// key starting with colon
l.add("+:/a/b : 123");
for (String diff : l) {
try {
DiffParser parser = new DiffParser(new DummyDiffHandler());
parser.parse(diff);
fail(diff + " is not a valid diff string -> should throw DiffException.");
} catch (DiffException e) {
// ok
}
}
}
private class DummyDiffHandler implements DiffHandler {
public void addNode(String targetPath, String diffValue)
throws DiffException {
// does nothing
}
public void setProperty(String targetPath, String diffValue)
throws DiffException {
// does nothing
}
public void remove(String targetPath, String diffValue)
throws DiffException {
// does nothing
}
public void move(String targetPath, String diffValue) throws DiffException {
// does nothing
}
}
}