You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2011/06/16 20:18:33 UTC
svn commit: r1136581 - in /jackrabbit/sandbox/microkernel/src:
main/java/org/apache/jackrabbit/mk/ main/java/org/apache/jackrabbit/mk/store/
main/java/org/apache/jackrabbit/mk/util/ test/java/org/apache/jackrabbit/mk/
Author: thomasm
Date: Thu Jun 16 18:18:32 2011
New Revision: 1136581
URL: http://svn.apache.org/viewvc?rev=1136581&view=rev
Log:
Support {../..} in path elements (so that JCR paths don't have to be escaped).
Added:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtils.java
- copied, changed from r1136369, jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtil.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/PathTest.java
Removed:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtil.java
Modified:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeUtils.java
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java?rev=1136581&r1=1136580&r2=1136581&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java Thu Jun 16 18:18:32 2011
@@ -25,7 +25,7 @@ import org.apache.jackrabbit.mk.store.Co
import org.apache.jackrabbit.mk.store.Node;
import org.apache.jackrabbit.mk.store.NodeDiffHandler;
import org.apache.jackrabbit.mk.store.NodeUtils;
-import org.apache.jackrabbit.mk.util.PathUtil;
+import org.apache.jackrabbit.mk.util.PathUtils;
import java.io.InputStream;
import java.util.ArrayList;
@@ -153,27 +153,27 @@ public class MicroKernelImpl implements
NodeUtils.diff(path, node1, node2, true, rep.getStore(), new NodeDiffHandler() {
public void propAdded(String nodePath, String propName, String value) {
buff.append("+ ").
- key(PathUtil.concat(nodePath, propName)).
+ key(PathUtils.concat(nodePath, propName)).
value(value).
append("\n");
}
public void propChanged(String nodePath, String propName, String oldValue, String newValue) {
buff.append("^ ").
- key(PathUtil.concat(nodePath, propName)).
+ key(PathUtils.concat(nodePath, propName)).
value(newValue).
append("\n");
}
public void propDeleted(String nodePath, String propName, String value) {
buff.append("- ").
- key(PathUtil.concat(nodePath, propName)).
+ key(PathUtils.concat(nodePath, propName)).
append("\n");
}
public void childNodeAdded(String nodePath, String childName, String id) {
buff.append("+ ").
- key(PathUtil.concat(nodePath, childName));
+ key(PathUtils.concat(nodePath, childName));
try {
toJson(buff, rep.getStore().getNode(id), childName, Integer.MAX_VALUE, 0, -1);
} catch (Exception e) {
@@ -184,7 +184,7 @@ public class MicroKernelImpl implements
public void childNodeDeleted(String nodePath, String childName, String id) {
buff.append("- ");
- buff.value(PathUtil.concat(nodePath, childName));
+ buff.value(PathUtils.concat(nodePath, childName));
buff.append("\n");
}
@@ -206,6 +206,7 @@ public class MicroKernelImpl implements
}
try {
+ // TODO exception handling for flow control is very slow
rep.getNode(revisionId, path);
return true;
} catch (Exception e) {
@@ -220,7 +221,7 @@ public class MicroKernelImpl implements
public String getNodes(String path, String revisionId, int depth, long offset, int count) throws MicroKernelException {
try {
JsopBuilder buf = new JsopBuilder().object();
- toJson(buf, rep.getNode(revisionId, path), PathUtil.getName(path), depth, offset, count);
+ toJson(buf, rep.getNode(revisionId, path), PathUtils.getName(path), depth, offset, count);
return buf.endObject().toString();
} catch (Exception e) {
throw new MicroKernelException(e);
@@ -256,9 +257,9 @@ public class MicroKernelImpl implements
String relPath = t.readString();
t.read(':');
t.read('{');
- String nodePath = PathUtil.concat(path, relPath);
- String parentPath = PathUtil.getParentPath(nodePath);
- String nodeName = PathUtil.getName(nodePath);
+ String nodePath = PathUtils.concat(path, relPath);
+ String parentPath = PathUtils.getParentPath(nodePath);
+ String nodeName = PathUtils.getName(nodePath);
// build the list of added nodes recursively
LinkedList<AddNodeOperation> list = new LinkedList<AddNodeOperation>();
addNode(list, parentPath, nodeName, t);
@@ -271,7 +272,7 @@ public class MicroKernelImpl implements
}
case '-': {
String relPath = t.readString();
- cb.removeNode(PathUtil.concat(path, relPath));
+ cb.removeNode(PathUtils.concat(path, relPath));
break;
}
case '^': {
@@ -283,16 +284,16 @@ public class MicroKernelImpl implements
} else {
value = t.readRawValue().trim();
}
- String nodePath = PathUtil.concat(path, relPath);
- String parentPath = PathUtil.getParentPath(nodePath);
- String propName = PathUtil.getName(nodePath);
+ String nodePath = PathUtils.concat(path, relPath);
+ String parentPath = PathUtils.getParentPath(nodePath);
+ String propName = PathUtils.getName(nodePath);
cb.setProperty(parentPath, propName, value);
break;
}
case '>': {
String relPath = t.readString();
String targetPath = t.readString();
- cb.moveNode(PathUtil.concat(path, relPath), targetPath);
+ cb.moveNode(PathUtils.concat(path, relPath), targetPath);
}
default:
throw new AssertionError("token type: " + t.getTokenType());
@@ -372,7 +373,7 @@ public class MicroKernelImpl implements
String key = t.readString();
t.read(':');
if (t.matches('{')) {
- addNode(list, PathUtil.concat(path, name), key, t);
+ addNode(list, PathUtils.concat(path, name), key, t);
} else {
op.props.put(key, t.readRawValue().trim());
}
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java?rev=1136581&r1=1136580&r2=1136581&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java Thu Jun 16 18:18:32 2011
@@ -20,7 +20,7 @@ import org.apache.jackrabbit.mk.store.Co
import org.apache.jackrabbit.mk.store.CommitBuilder;
import org.apache.jackrabbit.mk.store.Node;
import org.apache.jackrabbit.mk.store.ObjectStore;
-import org.apache.jackrabbit.mk.util.PathUtil;
+import org.apache.jackrabbit.mk.util.PathUtils;
import java.io.File;
@@ -104,16 +104,16 @@ public class Repository {
}
String[] /* array of node id's */ resolvePath(String revId, String path) throws Exception {
- if (!PathUtil.isAbsolute(path)) {
+ if (!PathUtils.isAbsolute(path)) {
throw new IllegalArgumentException("illegal path");
}
Commit commit = store.getCommit(revId);
- if (PathUtil.denotesRoot(path)) {
+ if (PathUtils.denotesRoot(path)) {
return new String[] { commit.getRootNodeId() };
}
- String[] names = path.substring(1).split("/");
+ String[] names = PathUtils.split(path);
String[] ids = new String[names.length + 1];
// get root node
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java?rev=1136581&r1=1136580&r2=1136581&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java Thu Jun 16 18:18:32 2011
@@ -17,7 +17,7 @@
package org.apache.jackrabbit.mk.store;
import org.apache.jackrabbit.mk.Repository;
-import org.apache.jackrabbit.mk.util.PathUtil;
+import org.apache.jackrabbit.mk.util.PathUtils;
import java.util.ArrayList;
import java.util.Collections;
@@ -61,15 +61,15 @@ public class CommitBuilder {
newChild.getProperties().putAll(properties);
modParent.getChildNodeEntries().put(nodeName, ""); // value will be computed on commit
- String newPath = PathUtil.concat(parentNodePath, nodeName);
+ String newPath = PathUtils.concat(parentNodePath, nodeName);
staged.put(newPath, newChild);
// update change log
changeLog.add(new AddNode(parentNodePath, nodeName, properties));
}
public void removeNode(String nodePath) throws Exception {
- String parentPath = PathUtil.getParentPath(nodePath);
- String nodeName = PathUtil.getName(nodePath);
+ String parentPath = PathUtils.getParentPath(nodePath);
+ String nodeName = PathUtils.getName(nodePath);
MutableNode parent = getOrCreateStagedNode(parentPath);
if (!parent.getChildNodeEntries().containsKey(nodeName)) {
@@ -86,11 +86,11 @@ public class CommitBuilder {
}
public void moveNode(String srcPath, String destPath) throws Exception {
- String srcParentPath = PathUtil.getParentPath(srcPath);
- String srcNodeName = PathUtil.getName(srcPath);
+ String srcParentPath = PathUtils.getParentPath(srcPath);
+ String srcNodeName = PathUtils.getName(srcPath);
- String destParentPath = PathUtil.getParentPath(destPath);
- String destNodeName = PathUtil.getName(destPath);
+ String destParentPath = PathUtils.getParentPath(destPath);
+ String destNodeName = PathUtils.getName(destPath);
MutableNode srcParent = getOrCreateStagedNode(srcParentPath);
String targetId = srcParent.getChildNodeEntries().get(srcNodeName);
@@ -110,11 +110,11 @@ public class CommitBuilder {
}
public void copyNode(String srcPath, String destPath) throws Exception {
- String srcParentPath = PathUtil.getParentPath(srcPath);
- String srcNodeName = PathUtil.getName(srcPath);
+ String srcParentPath = PathUtils.getParentPath(srcPath);
+ String srcNodeName = PathUtils.getName(srcPath);
- String destParentPath = PathUtil.getParentPath(destPath);
- String destNodeName = PathUtil.getName(destPath);
+ String destParentPath = PathUtils.getParentPath(destPath);
+ String destNodeName = PathUtils.getName(destPath);
MutableNode srcParent = getOrCreateStagedNode(srcParentPath);
String targetId = srcParent.getChildNodeEntries().get(srcNodeName);
@@ -219,8 +219,8 @@ public class CommitBuilder {
staged.put(nodePath, node);
// make sure all direct ancestors are staged as well
String p1 = nodePath;
- while (!PathUtil.denotesRoot(p1)) {
- String p0 = PathUtil.getParentPath(p1);
+ while (!PathUtils.denotesRoot(p1)) {
+ String p0 = PathUtils.getParentPath(p1);
MutableNode n0 = staged.get(p0);
if (n0 != null) {
break;
@@ -239,7 +239,7 @@ public class CommitBuilder {
staged.remove(srcPath);
staged.put(destPath, node);
for (String childName : node.getChildNodeEntries().keySet()) {
- moveStagedNodes(PathUtil.concat(srcPath, childName), PathUtil.concat(destPath, childName));
+ moveStagedNodes(PathUtils.concat(srcPath, childName), PathUtils.concat(destPath, childName));
}
}
}
@@ -249,7 +249,7 @@ public class CommitBuilder {
if (node != null) {
staged.remove(nodePath);
for (String childName : node.getChildNodeEntries().keySet()) {
- removeStagedNodes(PathUtil.concat(nodePath, childName));
+ removeStagedNodes(PathUtils.concat(nodePath, childName));
}
}
}
@@ -265,7 +265,7 @@ public class CommitBuilder {
}
int getDepth(String path) {
- return PathUtil.getDepth(path);
+ return PathUtils.getDepth(path);
}
});
// iterate over staged entries in depth-descending order
@@ -273,10 +273,10 @@ public class CommitBuilder {
for (String path : orderedPaths) {
// persist node
String id = store.putNode(staged.get(path));
- if (PathUtil.denotesRoot(path)) {
+ if (PathUtils.denotesRoot(path)) {
rootNodeId = id;
} else {
- staged.get(PathUtil.getParentPath(path)).getChildNodeEntries().put(PathUtil.getName(path), id);
+ staged.get(PathUtils.getParentPath(path)).getChildNodeEntries().put(PathUtils.getName(path), id);
}
}
if (rootNodeId == null) {
@@ -331,7 +331,7 @@ public class CommitBuilder {
// resolve/report merge conflicts
for (NodeDelta.Conflict conflict : conflicts) {
String conflictName = conflict.getName();
- String conflictPath = PathUtil.concat(path, conflictName);
+ String conflictPath = PathUtils.concat(path, conflictName);
switch (conflict.getType()) {
case PROPERTY_VALUE_CONFLICT:
throw new Exception(
@@ -348,7 +348,7 @@ public class CommitBuilder {
Node ourChild = store.getNode(ourNode.getChildNodeEntries().get(conflictName));
Node theirChild = store.getNode(theirNode.getChildNodeEntries().get(conflictName));
// merge the dirty subtrees recursively
- mergeNode(baseChild, ourChild, theirChild, PathUtil.concat(path, conflictName));
+ mergeNode(baseChild, ourChild, theirChild, PathUtils.concat(path, conflictName));
} else {
// todo handle/merge colliding node additions
}
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeUtils.java?rev=1136581&r1=1136580&r2=1136581&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeUtils.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeUtils.java Thu Jun 16 18:18:32 2011
@@ -16,7 +16,7 @@
*/
package org.apache.jackrabbit.mk.store;
-import org.apache.jackrabbit.mk.util.PathUtil;
+import org.apache.jackrabbit.mk.util.PathUtils;
import java.util.HashSet;
import java.util.Map;
@@ -98,7 +98,7 @@ public class NodeUtils {
node1 = store.getNode(entry.getValue());
node2 = store.getNode(id);
// do recurse
- diff(PathUtil.concat(path, entry.getKey()),
+ diff(PathUtils.concat(path, entry.getKey()),
node1, node2, deep, store, handler);
}
}
Copied: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtils.java (from r1136369, jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtil.java)
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtils.java?p2=jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtils.java&p1=jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtil.java&r1=1136369&r2=1136581&rev=1136581&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtil.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtils.java Thu Jun 16 18:18:32 2011
@@ -16,16 +16,17 @@
*/
package org.apache.jackrabbit.mk.util;
+import java.util.ArrayList;
+
/**
- *
+ * Utility methods to parse a JCR path.
*/
-public class PathUtil {
+public class PathUtils {
- private PathUtil() {
+ private PathUtils() {
+ // utility class
}
- // TODO support the syntax "{http://...}x/y" syntax
-
public static boolean denotesRoot(String path) {
return "/".equals(path);
}
@@ -35,18 +36,24 @@ public class PathUtil {
}
public static String getParentPath(String path) {
- int pos = path.lastIndexOf('/');
+ int pos = getPreviousSlash(path, path.length() - 1);
if (pos > 0) {
return path.substring(0, pos);
}
return "/";
}
+ /**
+ * Get the last element of the path
+ *
+ * @param path the complete path
+ * @return the last element
+ */
public static String getName(String path) {
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
- int pos = path.lastIndexOf('/');
+ int pos = getPreviousSlash(path, path.length() - 1);
if (pos != -1) {
return path.substring(pos + 1);
}
@@ -54,18 +61,46 @@ public class PathUtil {
}
public static int getDepth(String path) {
- if (PathUtil.denotesRoot(path)) {
+ if (PathUtils.denotesRoot(path)) {
return 0;
}
- int count = 0;
- for (char c : path.toCharArray()) {
- if (c == '/') {
- count++;
- }
+ int count = 0, i = 0;
+ if (path.startsWith("/")) {
+ i++;
+ }
+ for (; i > 0; i = getNextSlash(path, i) + 1) {
+ count++;
}
return count;
}
+ public static String[] split(String path) {
+ ArrayList<String> list = new ArrayList<String>();
+ if (path.startsWith("/")) {
+ if (path.length() == 1) {
+ return new String[0];
+ }
+ path = path.substring(1);
+ }
+ while(true) {
+ int index = getNextSlash(path, 0);
+ if (index < 0) {
+ list.add(path);
+ break;
+ }
+ if (index >= 0) {
+ String s = path.substring(0, index);
+ if (s.length() > 0) {
+ list.add(s);
+ }
+ }
+ path = path.substring(index + 1);
+ }
+ String[] array = new String[list.size()];
+ list.toArray(array);
+ return array;
+ }
+
public static String concat(String parentPath, String nameOrRelativePath) {
if (nameOrRelativePath.startsWith("/")) {
throw new IllegalArgumentException("can't append absolute path");
@@ -79,7 +114,7 @@ public class PathUtil {
}
/**
- * <code>relativize(path1, concat(path1, path2)) == path2</code>
+ * <code>relativize(parentPath, concat(parentPath, path)) == path2</code>
*/
public static String relativize(String parentPath, String path) {
String prefix = parentPath.charAt(parentPath.length() - 1) == '/'
@@ -89,8 +124,61 @@ public class PathUtil {
if (path.startsWith(prefix)) {
return path.substring(prefix.length());
}
- else {
- throw new IllegalAccessError("Cannot relativize " + path + " wrt. " + parentPath);
+ throw new IllegalArgumentException("Cannot relativize " + path + " wrt. " + parentPath);
+ }
+
+ /**
+ * Get the index of the next slash. This is similar to
+ * String.indexOf, except that escaping with { and } is supported.
+ *
+ * @param path the path
+ * @param index the starting index
+ * @return the index of the next slash (possibly the starting index), or
+ * -1 if not found
+ */
+ public static int getNextSlash(String path, int index) {
+ for (int len = path.length(); index < len; index++) {
+ char c = path.charAt(index);
+ if (c == '/') {
+ return index;
+ }
+ if (c == '{') {
+ do {
+ index++;
+ if (index >= len) {
+ throw new IllegalArgumentException(path);
+ }
+ } while (path.charAt(index) != '}');
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Get the index of the previous slash. This is similar to
+ * String.lastIndexOf, except that escaping with { and } is supported.
+ *
+ * @param path the path
+ * @param index the starting index
+ * @return the index of the previous slash (possibly the starting index), or
+ * -1 if not found
+ */
+ public static int getPreviousSlash(String path, int index) {
+ for (; index >= 0; index--) {
+ char c = path.charAt(index);
+ if (c == '/') {
+ break;
+ }
+ if (c == '}') {
+ do {
+ index--;
+ if (index < 0) {
+ throw new IllegalArgumentException(path);
+ }
+ } while (path.charAt(index) != '{');
+ }
}
+ return index;
}
+
}
Added: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/PathTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/PathTest.java?rev=1136581&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/PathTest.java (added)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/PathTest.java Thu Jun 16 18:18:32 2011
@@ -0,0 +1,118 @@
+/*
+ * 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.mk;
+
+import org.apache.jackrabbit.mk.util.PathUtils;
+import junit.framework.TestCase;
+
+public class PathTest extends TestCase {
+
+ public void test() {
+
+ try {
+ PathUtils.getNextSlash("/{error", 1);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ PathUtils.getPreviousSlash("error}", "error}".length() - 1);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ test("parent", "child");
+
+ test("{/}parent", "child");
+ test("{/}parent", "{/}child");
+ test("parent", "{/}child");
+
+ test("{x/y}parent", "child");
+ test("{x/y}parent", "{x/y}child");
+ test("parent", "{x/y}child");
+ }
+
+ private void test(String parent, String child) {
+
+ // split
+ assertEquals("/".split("/").length, PathUtils.split("/").length);
+ assertEquals("x".split("/").length, PathUtils.split("x").length);
+ assertEquals("x/x".split("/").length, PathUtils.split("x/x").length);
+ assertEquals(1, PathUtils.split("/" + parent).length);
+ assertEquals(2, PathUtils.split("/" + parent + "/" + child).length);
+
+ // concat
+ assertEquals(parent + "/" + child, PathUtils.concat(parent , child ));
+ assertEquals(parent + "/" + child, PathUtils.concat(parent + "/", child ));
+ try {
+ assertEquals(parent + "/" + child, PathUtils.concat(parent + "/", "/" + child));
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ assertEquals(parent + "/" + child, PathUtils.concat(parent , "/" + child));
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ // denotesRoot
+ assertTrue(PathUtils.denotesRoot("/"));
+ assertFalse(PathUtils.denotesRoot("/" + parent));
+
+ // getDepth
+ assertEquals(0, PathUtils.getDepth("/"));
+ assertEquals(1, PathUtils.getDepth("/" + parent));
+ assertEquals(2, PathUtils.getDepth("/" + parent + "/" + child));
+
+ // getName
+ assertEquals("", PathUtils.getName("/"));
+ assertEquals(parent , PathUtils.getName("/" + parent));
+ assertEquals(child , PathUtils.getName("/" + parent + "/" + child));
+
+ // getParentPath
+ assertEquals("/", PathUtils.getParentPath("/"));
+ assertEquals("/", PathUtils.getParentPath("/" + parent));
+ assertEquals("/" + parent, PathUtils.getParentPath("/" + parent + "/" + child));
+
+ // isAbsolute
+ assertEquals(true, PathUtils.isAbsolute("/"));
+ assertEquals(false, PathUtils.isAbsolute(parent ));
+ assertEquals(true, PathUtils.isAbsolute("/" + parent));
+ assertEquals(false, PathUtils.isAbsolute(child ));
+ assertEquals(true, PathUtils.isAbsolute("/" + parent + "/" + child));
+ assertEquals(false, PathUtils.isAbsolute(parent + "/" + child));
+
+ // relativize
+ assertEquals("", PathUtils.relativize("/", "/"));
+ assertEquals("", PathUtils.relativize("/" + parent, "/" + parent + "/"));
+ assertEquals(child , PathUtils.relativize("/" + parent, "/" + parent + "/" + child));
+ assertEquals(parent + "/" + child, PathUtils.relativize("/", "/" + parent + "/" + child));
+ try {
+ PathUtils.relativize("x/y", "y/x");
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+
+ }
+
+}