mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 13:42:06 +00:00
Merge remote-tracking branch 'origin/GT-2961_ghizard_CategoryPath_delimiter_elimination'
This commit is contained in:
commit
d95fd43762
@ -57,13 +57,13 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||
this.name = name;
|
||||
this.parent = parent;
|
||||
|
||||
subcategoryMap = new LazyLoadingCachingMap<String, CategoryDB>(mgr.lock, CategoryDB.class) {
|
||||
subcategoryMap = new LazyLoadingCachingMap<>(mgr.lock, CategoryDB.class) {
|
||||
@Override
|
||||
public Map<String, CategoryDB> loadMap() {
|
||||
return buildSubcategoryMap();
|
||||
}
|
||||
};
|
||||
dataTypeMap = new LazyLoadingCachingMap<String, DataType>(mgr.lock, DataType.class) {
|
||||
dataTypeMap = new LazyLoadingCachingMap<>(mgr.lock, DataType.class) {
|
||||
@Override
|
||||
public Map<String, DataType> loadMap() {
|
||||
return createDataTypeMap();
|
||||
@ -273,9 +273,6 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||
if (categoryName == null || categoryName.length() == 0) {
|
||||
throw new InvalidNameException("Name cannot be null or zero length");
|
||||
}
|
||||
if (categoryName.indexOf(DELIMITER_CHAR) >= 0) {
|
||||
throw new InvalidNameException("Bad name: " + categoryName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1255,17 +1255,17 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
// try to deal with datatypes that have '/' chars in their name.
|
||||
Category category = getLowestLevelCategory(dataTypePath);
|
||||
// Use a category path to parse the datatype path because it knows how to deal with
|
||||
// escaped forward slashes.
|
||||
CategoryPath parsedPath = new CategoryPath(dataTypePath);
|
||||
CategoryPath categoryPath = parsedPath.getParent();
|
||||
String dataTypeName = parsedPath.getName();
|
||||
Category category = getCategory(categoryPath);
|
||||
|
||||
if (category != null) {
|
||||
CategoryPath categoryPath = category.getCategoryPath();
|
||||
String path = categoryPath.getPath();
|
||||
int dataTypeNameStartIndex = path.endsWith("/") ? path.length() : path.length() + 1; // +1 to get past the last '/'
|
||||
String dataTypeName = dataTypePath.substring(dataTypeNameStartIndex);
|
||||
return category.getDataType(dataTypeName);
|
||||
if (category == null) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
return category.getDataType(dataTypeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1273,19 +1273,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||
return getDataType(dataTypePath);
|
||||
}
|
||||
|
||||
private Category getLowestLevelCategory(String dataTypePath) {
|
||||
CategoryPath pathParser = new CategoryPath(dataTypePath); // Use a category path to parse the path.
|
||||
while (pathParser != null) {
|
||||
CategoryPath path = pathParser.getParent();
|
||||
Category category = getCategory(path);
|
||||
if (category != null) {
|
||||
return category;
|
||||
}
|
||||
pathParser = path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findEnumValueNames(long value, Set<String> enumValueNames) {
|
||||
buildEnumValueMap();
|
||||
|
@ -23,12 +23,6 @@ import ghidra.util.task.TaskMonitor;
|
||||
* Each data type resides in a given a category.
|
||||
*/
|
||||
public interface Category extends Comparable<Category> {
|
||||
public static final char DELIMITER_CHAR = '/'; // delimeter between categories
|
||||
|
||||
public static final String NAME_DELIMITER = "/"; // delimiter between names
|
||||
|
||||
public static final String DELIMITER_STRING = "" + DELIMITER_CHAR; // delimeter between categories
|
||||
|
||||
/**
|
||||
* Get the name of this category.
|
||||
*/
|
||||
|
@ -15,7 +15,9 @@
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
/**
|
||||
* A category path is the full path to a particular data type
|
||||
@ -24,51 +26,141 @@ public class CategoryPath implements Comparable<CategoryPath> {
|
||||
|
||||
public static final char DELIMITER_CHAR = '/';
|
||||
public static final String DELIMITER_STRING = "" + DELIMITER_CHAR;
|
||||
public static final String ESCAPED_DELIMITER_STRING = "\\" + DELIMITER_STRING;
|
||||
|
||||
public static final CategoryPath ROOT = new CategoryPath(null);
|
||||
public static final CategoryPath ROOT = new CategoryPath();
|
||||
|
||||
private static final String ILLEGAL_STRING = DELIMITER_STRING + DELIMITER_STRING;
|
||||
private static final int DIFF = ESCAPED_DELIMITER_STRING.length() - DELIMITER_STRING.length();
|
||||
|
||||
private final String parentPath;
|
||||
// parent can only be null for ROOT
|
||||
private final CategoryPath parent;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Create a category path given a string.
|
||||
*
|
||||
* @param path category path string.
|
||||
* Converts a non-escaped String into an escaped string suitable for being passed in as a
|
||||
* component of a single category path string to the constructor that takes a single
|
||||
* escaped category path string. The user is responsible for constructing the single
|
||||
* category path string from the escaped components.
|
||||
* @param nonEscapedString String that might need escaping for characters used for delimiting
|
||||
* @return escaped String
|
||||
* @see #unescapeString(String)
|
||||
*/
|
||||
public static String escapeString(String nonEscapedString) {
|
||||
return nonEscapedString.replace(DELIMITER_STRING, ESCAPED_DELIMITER_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an escaped String suitable for being passed in as a component of a single category
|
||||
* path string into an non-escaped string.
|
||||
* @param escapedString String that might need unescaping for characters used for delimiting
|
||||
* @return non-escaped String
|
||||
* @see #escapeString(String)
|
||||
*/
|
||||
public static String unescapeString(String escapedString) {
|
||||
return escapedString.replace(ESCAPED_DELIMITER_STRING, DELIMITER_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for internal creation of ROOT.
|
||||
*/
|
||||
private CategoryPath() {
|
||||
// parent can only be null for ROOT
|
||||
parent = null;
|
||||
name = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a CategoryPath from a parent and a hierarchical array of strings where each
|
||||
* string is the name of a category in the category path.
|
||||
*
|
||||
* @param parent the parent CategoryPath. Choose {@code ROOT} if needed.
|
||||
* @param subPathElements the array of names of sub-categories of the parent.
|
||||
* @throws IllegalArgumentException if the given array is null or empty.
|
||||
*/
|
||||
public CategoryPath(CategoryPath parent, String... subPathElements) {
|
||||
this(parent, Arrays.asList(subPathElements));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a CategoryPath from a parent and a hierarchical list of strings where each
|
||||
* string is the name of a category in the category path.
|
||||
*
|
||||
* @param parent the parent CategoryPath. Choose {@code ROOT} if needed.
|
||||
* @param subPathElements the hierarchical array of sub-categories of the parent.
|
||||
* @throws IllegalArgumentException if the given list is null or empty.
|
||||
*/
|
||||
public CategoryPath(CategoryPath parent, List<String> subPathElements) {
|
||||
Objects.requireNonNull(parent);
|
||||
if (CollectionUtils.isEmpty(subPathElements)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Category list must contain at least one string name!");
|
||||
}
|
||||
name = subPathElements.get(subPathElements.size() - 1);
|
||||
if (subPathElements.size() == 1) {
|
||||
this.parent = parent;
|
||||
}
|
||||
else {
|
||||
this.parent =
|
||||
new CategoryPath(parent, subPathElements.subList(0, subPathElements.size() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a category path given a forward-slash-delimited string (e.g., {@code "/aa/bb"}).
|
||||
* If an individual path component has one or more '/' characters in it, then it can be
|
||||
* <I><B>escaped</B></I> using the {@link #escapeString(String)} utility method. The
|
||||
* {@link #unescapeString(String)} method can be used to unescape an individual component.
|
||||
* <P>
|
||||
* <B>Refrain</B> from using this constructor in production code, and instead use one of the
|
||||
* other constructors that does not require escaping. Situations where using this constructor
|
||||
* is OK is in simple cases where a literal is passed in, such as in testing methods or in
|
||||
* scripts.
|
||||
* @param path category path string, delimited with '/' characters where individual components
|
||||
* may have '/' characters escaped. Must start with the '/' character.
|
||||
*/
|
||||
// NOTE: We purposefully did not create a constructor that takes varags only, as that
|
||||
// constructor, called with a single argument that would not be escaped, would conflict with
|
||||
// this constructor, which requires an escaped argument.
|
||||
public CategoryPath(String path) {
|
||||
if (path == null || path.length() == 0 || path.equals(DELIMITER_STRING)) {
|
||||
this.parentPath = this.name = "";
|
||||
// parent can only be null for ROOT
|
||||
parent = null;
|
||||
name = "";
|
||||
return;
|
||||
}
|
||||
else if (path.charAt(0) != DELIMITER_CHAR) {
|
||||
throw new IllegalArgumentException("Paths must start with " + DELIMITER_STRING);
|
||||
}
|
||||
else if (path.charAt(path.length() - 1) == DELIMITER_CHAR) {
|
||||
else if (endsWithNonEscapedDelimiter(path)) {
|
||||
throw new IllegalArgumentException("Paths must not end with " + DELIMITER_STRING);
|
||||
}
|
||||
else if (path.indexOf(ILLEGAL_STRING) >= 0) {
|
||||
throw new IllegalArgumentException("Paths must have non-empty elements");
|
||||
}
|
||||
else {
|
||||
int index = path.lastIndexOf(DELIMITER_CHAR);
|
||||
this.parentPath = path.substring(0, index);
|
||||
this.name = path.substring(index + 1);
|
||||
}
|
||||
|
||||
int delimiterIndex = findIndexOfLastNonEscapedDelimiter(path);
|
||||
this.parent = new CategoryPath(path.substring(0, delimiterIndex));
|
||||
this.name = unescapeString(path.substring(delimiterIndex + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a category path given a parent category and name.
|
||||
*
|
||||
* @param parent parent category this path will reside in.
|
||||
* @param name name of the category within the parent category.
|
||||
*/
|
||||
public CategoryPath(CategoryPath parent, String name) {
|
||||
if (name == null || name.length() == 0 || name.indexOf(DELIMITER_CHAR) >= 0) {
|
||||
throw new IllegalArgumentException("Bad name: " + name);
|
||||
private boolean endsWithNonEscapedDelimiter(String string) {
|
||||
return (string.charAt(string.length() - 1) == DELIMITER_CHAR &&
|
||||
string.lastIndexOf(ESCAPED_DELIMITER_STRING) != string.length() -
|
||||
ESCAPED_DELIMITER_STRING.length());
|
||||
}
|
||||
|
||||
private int findIndexOfLastNonEscapedDelimiter(String string) {
|
||||
int escapedIndex = string.length();
|
||||
int delimiterIndex = escapedIndex;
|
||||
while (delimiterIndex > 0) {
|
||||
escapedIndex = string.lastIndexOf(ESCAPED_DELIMITER_STRING, escapedIndex - 1);
|
||||
delimiterIndex = string.lastIndexOf(DELIMITER_CHAR, delimiterIndex - 1);
|
||||
if (delimiterIndex != escapedIndex + DIFF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.parentPath = parent.isRoot() ? "" : parent.getPath();
|
||||
this.name = name;
|
||||
return delimiterIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,56 +168,92 @@ public class CategoryPath implements Comparable<CategoryPath> {
|
||||
* @return true if this is a root category path
|
||||
*/
|
||||
public boolean isRoot() {
|
||||
return parentPath.length() == 0 && name.length() == 0;
|
||||
// parent can only be null for ROOT
|
||||
return parent == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of this category path
|
||||
* Return the parent category path.
|
||||
* @return the parent
|
||||
*/
|
||||
public CategoryPath getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the terminating name of this category path.
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full path to the category including the category name as a string.
|
||||
* Return the {@link String} representation of this category path including the category name,
|
||||
* where components are delimited with a forward slash. Any component that contains a forward
|
||||
* slash will be have the forward slash characters escaped.
|
||||
* @return the full category path
|
||||
*/
|
||||
public String getPath() {
|
||||
return parentPath + DELIMITER_CHAR + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent category path.
|
||||
*/
|
||||
public CategoryPath getParent() {
|
||||
if (parentPath.length() == 0 && name.length() == 0) {
|
||||
return null;
|
||||
if (isRoot()) {
|
||||
return DELIMITER_STRING;
|
||||
}
|
||||
return new CategoryPath(parentPath);
|
||||
if (parent.isRoot()) {
|
||||
return DELIMITER_CHAR + escapeString(name);
|
||||
}
|
||||
return parent.getPath() + DELIMITER_CHAR + escapeString(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof CategoryPath) {
|
||||
CategoryPath cp = (CategoryPath) obj;
|
||||
return cp.parentPath.equals(parentPath) && cp.name.equals(name);
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
CategoryPath other = (CategoryPath) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
if (parent == null) {
|
||||
if (other.parent != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!parent.equals(other.parent)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return parentPath.hashCode() + name.hashCode();
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the specified categoryPath is the same as, or an ancestor of, this category path.
|
||||
* @param categoryPath the category path to be checked.
|
||||
* @param candidateAncestorPath the category path to be checked.
|
||||
* @return true if the given path is the same as, or an ancestor of, this category path.
|
||||
*/
|
||||
public boolean isAncestorOrSelf(CategoryPath categoryPath) {
|
||||
public boolean isAncestorOrSelf(CategoryPath candidateAncestorPath) {
|
||||
|
||||
// Result categoryPath This
|
||||
// Result categoryPath This
|
||||
// ------ --------------------- ------------------------
|
||||
// True / /
|
||||
// True / /apple
|
||||
// False /apple /
|
||||
// True /apple /apple/sub
|
||||
@ -133,43 +261,47 @@ public class CategoryPath implements Comparable<CategoryPath> {
|
||||
// False /app /apple
|
||||
// False /pear /apple
|
||||
|
||||
if (categoryPath.isRoot()) {
|
||||
if (candidateAncestorPath.isRoot()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isRoot()) {
|
||||
return false;
|
||||
CategoryPath path = this;
|
||||
while (!path.isRoot()) {
|
||||
if (candidateAncestorPath.equals(path)) {
|
||||
return true;
|
||||
}
|
||||
path = path.getParent();
|
||||
}
|
||||
|
||||
String otherCategory = categoryPath.getPath();
|
||||
String myCategory = getPath();
|
||||
if (!myCategory.startsWith(otherCategory)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (myCategory.length() == otherCategory.length()) {
|
||||
// categoryPath is the same as this
|
||||
return true;
|
||||
}
|
||||
|
||||
return myCategory.charAt(otherCategory.length()) == DELIMITER_CHAR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of names in category path.
|
||||
* @return array of names
|
||||
*/
|
||||
public String[] getPathElements() {
|
||||
StringTokenizer tokenizer = new StringTokenizer(getPath(), DELIMITER_STRING);
|
||||
String[] tokens = new String[tokenizer.countTokens()];
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
tokens[i] = tokenizer.nextToken();
|
||||
}
|
||||
return tokens;
|
||||
return asArray();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(CategoryPath otherPath) {
|
||||
return getPath().compareTo(otherPath.getPath());
|
||||
public int compareTo(CategoryPath other) {
|
||||
if (isRoot() && other.isRoot()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isRoot() || other.isRoot()) {
|
||||
return isRoot() ? -1 : 1;
|
||||
}
|
||||
|
||||
int result = parent.compareTo(other.getParent());
|
||||
|
||||
if (result == 0) {
|
||||
result = name.compareTo(other.getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@ -180,4 +312,30 @@ public class CategoryPath implements Comparable<CategoryPath> {
|
||||
return getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hierarchical list of names of the categories in the category path, starting with
|
||||
* the name just below the {@code ROOT} category.
|
||||
*
|
||||
* @return a hierarchical list of names of the category in the category path.
|
||||
*/
|
||||
public List<String> asList() {
|
||||
if (isRoot()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<String> list = parent.asList();
|
||||
list.add(name);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hierarchical array of names of the categories in the category path, starting with
|
||||
* the name just below the {@code ROOT} category.
|
||||
*
|
||||
* @return a hierarchical array of names of the categories in the category path.
|
||||
*/
|
||||
public String[] asArray() {
|
||||
List<String> list = asList();
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,19 +39,20 @@ public class DataTypePath {
|
||||
* @param dataTypeName the name of the datatype.
|
||||
* @throws IllegalArgumentException if a null category path or dataTypeName is given.
|
||||
*/
|
||||
public DataTypePath(CategoryPath categoryPath, String datatypeName) {
|
||||
if (datatypeName == null || categoryPath == null) {
|
||||
public DataTypePath(CategoryPath categoryPath, String dataTypeName) {
|
||||
if (dataTypeName == null || categoryPath == null) {
|
||||
throw new IllegalArgumentException("null not allowed for categoryPath or datatypeName");
|
||||
}
|
||||
this.categoryPath = categoryPath;
|
||||
this.dataTypeName = datatypeName;
|
||||
this.dataTypeName = dataTypeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the categoryPath for the datatype represented by this datatype path.
|
||||
* (ie. the CategoryPath that contains the DataType that this DataTypePath points to).
|
||||
*
|
||||
* @return the parent {@link CategoryPath} of the {@link DataType} that this DataTypePath points to.
|
||||
* @return the parent {@link CategoryPath} of the {@link DataType} that this DataTypePath
|
||||
* points to.
|
||||
*/
|
||||
public CategoryPath getCategoryPath() {
|
||||
return categoryPath;
|
||||
@ -70,6 +71,7 @@ public class DataTypePath {
|
||||
|
||||
/**
|
||||
* Returns the name of the datatype.
|
||||
* @return the name
|
||||
*/
|
||||
public String getDataTypeName() {
|
||||
return dataTypeName;
|
||||
@ -79,6 +81,7 @@ public class DataTypePath {
|
||||
* Returns the full path of this datatype. NOTE: if the datatype name contains any
|
||||
* "/" characters, then the resulting path string may be ambiguous as to where the
|
||||
* category path ends and the datatype name begins.
|
||||
* @return the full path
|
||||
*/
|
||||
public String getPath() {
|
||||
StringBuffer buf = new StringBuffer(categoryPath.getPath());
|
||||
|
@ -21,18 +21,17 @@
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* To change the template for this generated type comment go to
|
||||
* Window>Preferences>Java>Code Generation>Code and Comments
|
||||
* {@link CategoryPath} tests.
|
||||
*/
|
||||
public class CategoryPathTest extends AbstractGenericTest {
|
||||
|
||||
@ -41,109 +40,275 @@ public class CategoryPathTest extends AbstractGenericTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor() {
|
||||
public void testEscapeStringEmpty() {
|
||||
String orig = "";
|
||||
String escaped = CategoryPath.escapeString(orig);
|
||||
String unescaped = CategoryPath.unescapeString(escaped);
|
||||
assertEquals(orig, unescaped);
|
||||
assertEquals("", escaped);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEscapeString1() {
|
||||
String orig = "/";
|
||||
String escaped = CategoryPath.escapeString(orig);
|
||||
String unescaped = CategoryPath.unescapeString(escaped);
|
||||
assertEquals(orig, unescaped);
|
||||
assertEquals("\\/", escaped);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEscapeString2() {
|
||||
String orig = "//";
|
||||
String escaped = CategoryPath.escapeString(orig);
|
||||
String unescaped = CategoryPath.unescapeString(escaped);
|
||||
assertEquals(orig, unescaped);
|
||||
assertEquals("\\/\\/", escaped);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorRoot1() {
|
||||
CategoryPath c = CategoryPath.ROOT;
|
||||
assertEquals("/", c.getPath());
|
||||
assertEquals("", c.getName());
|
||||
assertTrue(c.isRoot());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorRoot2() {
|
||||
CategoryPath c = new CategoryPath(null);
|
||||
Assert.assertEquals("/", c.getPath());
|
||||
Assert.assertEquals("", c.getName());
|
||||
assertEquals("/", c.getPath());
|
||||
assertEquals("", c.getName());
|
||||
assertTrue(c.isRoot());
|
||||
}
|
||||
|
||||
c = new CategoryPath("");
|
||||
Assert.assertEquals("/", c.getPath());
|
||||
Assert.assertEquals("", c.getName());
|
||||
@Test
|
||||
public void testConstructorRoot3() {
|
||||
CategoryPath c = new CategoryPath("");
|
||||
assertEquals("/", c.getPath());
|
||||
assertEquals("", c.getName());
|
||||
assertTrue(c.isRoot());
|
||||
}
|
||||
|
||||
c = new CategoryPath("/");
|
||||
Assert.assertEquals("/", c.getPath());
|
||||
Assert.assertEquals("", c.getName());
|
||||
@Test
|
||||
public void testConstructorRoot4() {
|
||||
CategoryPath c = new CategoryPath("/");
|
||||
assertEquals("/", c.getPath());
|
||||
assertEquals("", c.getName());
|
||||
assertTrue(c.isRoot());
|
||||
}
|
||||
|
||||
c = new CategoryPath("/apple");
|
||||
Assert.assertEquals("/apple", c.getPath());
|
||||
Assert.assertEquals("apple", c.getName());
|
||||
@Test
|
||||
public void testConstructorBasicString1() {
|
||||
CategoryPath c = new CategoryPath("/apple");
|
||||
assertEquals("/apple", c.getPath());
|
||||
assertEquals("apple", c.getName());
|
||||
}
|
||||
|
||||
c = new CategoryPath("/apple/pear");
|
||||
Assert.assertEquals("/apple/pear", c.getPath());
|
||||
Assert.assertEquals("pear", c.getName());
|
||||
@Test
|
||||
public void testConstructorBasicString2() {
|
||||
CategoryPath c = new CategoryPath("/apple/pear");
|
||||
assertEquals("/apple/pear", c.getPath());
|
||||
assertEquals("pear", c.getName());
|
||||
}
|
||||
|
||||
try {
|
||||
c = new CategoryPath("//");
|
||||
Assert.fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
}
|
||||
try {
|
||||
c = new CategoryPath("apple");
|
||||
Assert.fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
}
|
||||
try {
|
||||
c = new CategoryPath("/apple/");
|
||||
Assert.fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
}
|
||||
try {
|
||||
c = new CategoryPath("/apple//bob");
|
||||
Assert.fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
}
|
||||
@Test
|
||||
public void testConstructorParentVarargsSingle() {
|
||||
CategoryPath c = new CategoryPath("/apple/pear");
|
||||
c = new CategoryPath(c, "mango");
|
||||
assertEquals("/apple/pear/mango", c.getPath());
|
||||
assertEquals("mango", c.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorParentAndList() {
|
||||
CategoryPath parent = new CategoryPath("/universe/earth");
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("boy");
|
||||
list.add("bad");
|
||||
CategoryPath c = new CategoryPath(parent, list);
|
||||
assertEquals("/universe/earth/boy/bad", c.getPath());
|
||||
assertEquals("bad", c.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorParentAndVarargsArray() {
|
||||
CategoryPath parent = new CategoryPath("/apple/peaches");
|
||||
CategoryPath c = new CategoryPath(parent, new String[] { "pumpkin", "pie" });
|
||||
assertEquals("pie", c.getName());
|
||||
c = c.getParent();
|
||||
assertEquals("pumpkin", c.getName());
|
||||
c = c.getParent();
|
||||
assertEquals("peaches", c.getName());
|
||||
c = c.getParent();
|
||||
assertEquals("apple", c.getName());
|
||||
c = c.getParent();
|
||||
assertEquals("", c.getName());
|
||||
assertTrue(c.isRoot());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorParentAndVarargs() {
|
||||
CategoryPath parent = new CategoryPath("/apple/peaches");
|
||||
CategoryPath c = new CategoryPath(parent, "pumpkin", "pie");
|
||||
assertEquals("pie", c.getName());
|
||||
c = c.getParent();
|
||||
assertEquals("pumpkin", c.getName());
|
||||
c = c.getParent();
|
||||
assertEquals("peaches", c.getName());
|
||||
c = c.getParent();
|
||||
assertEquals("apple", c.getName());
|
||||
c = c.getParent();
|
||||
assertEquals("", c.getName());
|
||||
assertTrue(c.isRoot());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testBadCtorParam_empty_path_element() {
|
||||
public void testConstructorBadCtorParam_empty_path_element() {
|
||||
new CategoryPath("//");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testBadCtorParam_empty_path_element_2() {
|
||||
public void testConstructorBadCtorParam_empty_path_element_2() {
|
||||
new CategoryPath("/apple//bob");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testBadCtorParam_missing_leading_slash() {
|
||||
public void testConstructorBadCtorParam_missing_leading_slash() {
|
||||
new CategoryPath("apple");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testBadCtorParam_bad_trailing_slash() {
|
||||
public void testConstructorBadCtorParam_bad_trailing_slash() {
|
||||
new CategoryPath("/apple/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOtherConstructor() {
|
||||
CategoryPath a = new CategoryPath("/aaa");
|
||||
CategoryPath b = new CategoryPath(a, "bbb");
|
||||
Assert.assertEquals("/aaa/bbb", b.getPath());
|
||||
Assert.assertEquals("bbb", b.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParent() {
|
||||
CategoryPath c = new CategoryPath(null);
|
||||
CategoryPath c = CategoryPath.ROOT;
|
||||
assertNull(c.getParent());
|
||||
|
||||
c = new CategoryPath("/aaa/bbb/ccc");
|
||||
c = c.getParent();
|
||||
Assert.assertEquals("/aaa/bbb", c.getPath());
|
||||
assertEquals("/aaa/bbb", c.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAncestor() {
|
||||
|
||||
Assert.assertTrue(CategoryPath.ROOT.isAncestorOrSelf(CategoryPath.ROOT));
|
||||
public void testIsAncestorRootRoot() {
|
||||
assertTrue(CategoryPath.ROOT.isAncestorOrSelf(CategoryPath.ROOT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAncestorRootApple() {
|
||||
CategoryPath apple = new CategoryPath("/apple");
|
||||
Assert.assertTrue(apple.isAncestorOrSelf(CategoryPath.ROOT));
|
||||
Assert.assertFalse(CategoryPath.ROOT.isAncestorOrSelf(apple));
|
||||
assertTrue(apple.isAncestorOrSelf(CategoryPath.ROOT));
|
||||
assertFalse(CategoryPath.ROOT.isAncestorOrSelf(apple));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAncestorAppleSubApple() {
|
||||
CategoryPath apple = new CategoryPath("/apple");
|
||||
CategoryPath applesub = new CategoryPath("/apple/sub");
|
||||
Assert.assertTrue(applesub.isAncestorOrSelf(apple));
|
||||
Assert.assertTrue(applesub.isAncestorOrSelf(applesub));
|
||||
assertTrue(applesub.isAncestorOrSelf(apple));
|
||||
assertTrue(applesub.isAncestorOrSelf(applesub));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAncestorAppleSubNotApple() {
|
||||
CategoryPath applesub = new CategoryPath("/apple/sub");
|
||||
CategoryPath notapple = new CategoryPath("/notapple");
|
||||
Assert.assertFalse(applesub.isAncestorOrSelf(notapple));
|
||||
assertFalse(applesub.isAncestorOrSelf(notapple));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAncestorAppleSubApp() {
|
||||
CategoryPath applesub = new CategoryPath("/apple/sub");
|
||||
CategoryPath app = new CategoryPath("/app");
|
||||
Assert.assertFalse(applesub.isAncestorOrSelf(app));
|
||||
assertFalse(applesub.isAncestorOrSelf(app));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToArray() {
|
||||
CategoryPath path = new CategoryPath("/aaa/bbb/bob");
|
||||
String[] names = path.asArray();
|
||||
assertEquals("aaa", names[0]);
|
||||
assertEquals("bbb", names[1]);
|
||||
assertEquals("bob", names[2]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToList() {
|
||||
CategoryPath path = new CategoryPath("/aaa/bbb/bob");
|
||||
List<String> names = path.asList();
|
||||
assertEquals("aaa", names.get(0));
|
||||
assertEquals("bbb", names.get(1));
|
||||
assertEquals("bob", names.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorDelimeterEscape1() {
|
||||
CategoryPath path = new CategoryPath("/aaa/bbb/\\/bob");
|
||||
List<String> names = path.asList();
|
||||
assertEquals("aaa", names.get(0));
|
||||
assertEquals("bbb", names.get(1));
|
||||
assertEquals("/bob", names.get(2));
|
||||
assertEquals("/aaa/bbb/\\/bob", path.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorDelimeterEscape2() {
|
||||
// Should not complain about terminating slash
|
||||
CategoryPath path = new CategoryPath("/aaa/bbb/bob\\/");
|
||||
List<String> names = path.asList();
|
||||
assertEquals("aaa", names.get(0));
|
||||
assertEquals("bbb", names.get(1));
|
||||
assertEquals("bob/", names.get(2));
|
||||
assertEquals("/aaa/bbb/bob\\/", path.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorDelimeterEscape3() {
|
||||
CategoryPath path = new CategoryPath("/\\/aaa/bbb/bob");
|
||||
List<String> names = path.asList();
|
||||
assertEquals("/aaa", names.get(0));
|
||||
assertEquals("bbb", names.get(1));
|
||||
assertEquals("bob", names.get(2));
|
||||
assertEquals("/\\/aaa/bbb/bob", path.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorDelimeterEscape4() {
|
||||
CategoryPath path = new CategoryPath("/\\/\\/aaa/bbb/bob");
|
||||
List<String> names = path.asList();
|
||||
assertEquals("//aaa", names.get(0));
|
||||
assertEquals("bbb", names.get(1));
|
||||
assertEquals("bob", names.get(2));
|
||||
assertEquals("/\\/\\/aaa/bbb/bob", path.getPath());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@SuppressWarnings("unused")
|
||||
public void testDelimeterEscapeAtRoot() {
|
||||
CategoryPath path = new CategoryPath("\\//aaa/bbb/bob");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorParentVarargsNestedDelimiter1() {
|
||||
CategoryPath c = new CategoryPath("/apple/pear");
|
||||
// nested delimiter sequence should be ignored on constructor and getName(), but output on
|
||||
// getPath().
|
||||
c = new CategoryPath(c, "man/go");
|
||||
assertEquals("/apple/pear/man\\/go", c.getPath());
|
||||
assertEquals("man/go", c.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorParentVarargsNestedEscape1() {
|
||||
CategoryPath c = new CategoryPath("/apple/pear");
|
||||
// nested escape sequence should be ignored on constructor and getName(), but output on
|
||||
// getPath().
|
||||
c = new CategoryPath(c, "man\\/go");
|
||||
assertEquals("/apple/pear/man\\\\/go", c.getPath());
|
||||
assertEquals("man\\/go", c.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user