package org.dcache.services.info.base;
import org.junit.Test;
import java.util.BitSet;
import static org.junit.Assert.*;
public class StatePathPredicateTests {
private static final String NON_APPEARING_PATH_ELEMENT = "Terpsichore";
private static final String WILDCARD_ELEMENT = "*";
@Test
public void testParsePathString() {
// Test some likely awkward cases
StatePathPredicate.parsePath("");
StatePathPredicate.parsePath(null);
}
@Test
public void testStatePathPredicateStatePath() {
String elements[] = { "foo", "bar", "baz", "bing", "bong"};
for( int depth = 1; depth <= elements.length; depth++) {
StatePath testPath = buildPath( elements, depth);
assertTrue( "Creating StatePathPredicate with a StatePath ("+testPath+") doesn't match creating StatePath", testBuildStatePath( testPath));
}
}
@Test
public void testStatePathPredicateString() {
// Test some likely awkward cases
new StatePathPredicate( (String)null);
new StatePathPredicate( "");
// Test individual cases.
String[] topElements = {"foo", "bar", "baz"};
for( String topElement : topElements) {
assertTrue("predicate match fails for " + topElement, testBuildStatePath(new StatePath(topElement)));
}
}
@Test
public void testMatches() {
// element names for the depths
String[] elements = {"foo", "bar", "baz"};
for( int depth = 1; depth < elements.length; depth++) {
StatePath testPath = buildPath( elements, depth);
StatePathPredicate predicate = new StatePathPredicate( testPath);
assertFalse( "predicate "+predicate+" matches null path", predicate.matches(null));
assertTrue( "predicate "+predicate+" doesn't match own path", predicate.matches( testPath));
StatePath childPath = testPath.newChild( "child");
assertFalse( "predicate "+predicate+" matches child of path " + childPath, predicate.matches( childPath));
if( depth > 1) {
StatePath parentPath = testPath.parentPath();
assertFalse( "predicate "+predicate+" matches parent "+parentPath, predicate.matches( parentPath));
// Try replacing the last element of the *path* with a wildcard. This shouldn't match.
StatePath lastWild = testPath.parentPath().newChild( WILDCARD_ELEMENT);
assertFalse( "predicate "+predicate+" matches path "+lastWild, predicate.matches(lastWild));
}
}
// +1 so we can store the extra bit after the final test (all wildcards).
BitSet wildcards = new BitSet( elements.length+1);
while( wildcards.length() <= elements.length) {
StatePathPredicate predicate = buildWildcardPredicate( elements, wildcards);
StatePath testPath = buildMatchingPath( elements, wildcards);
assertTrue("Predicate " + predicate.toString() + " failed to match path " + testPath.toString(), predicate.matches( testPath));
/**
* Magic that does a numerical increment. Note that
* numbers ending (. is either 0 or 1).
* .....0 -> .....1 (xor ...001)
* ....01 -> ....10 (xor ...011)
* ...011 -> ...100 (xor ...111)
*/
BitSet incr = new BitSet( elements.length+1);
incr.set(0, 1+wildcards.nextClearBit(0));
wildcards.xor( incr);
}
}
@Test
public void testMultipleWildcards() {
StatePathPredicate predicate = StatePathPredicate.parsePath("aaa.*.bbb.*");
assertMatching( "multiple wildcards", predicate, StatePath.parsePath("aaa.foo.bbb.bar"));
assertNotMatching( "multiple wildcards", predicate, StatePath.parsePath("aaa.foo.bbb"));
assertNotMatching( "multiple wildcards", predicate, StatePath.parsePath("aaa.foo.ccc.bar"));
assertNotMatching( "multiple wildcards", predicate, StatePath.parsePath("ccc.foo.bbb.bar"));
}
private void assertMatching( String msg, StatePathPredicate predicate, StatePath path) {
assertTrue( msg + "expected matching path " + path + " for " + predicate, predicate.matches( path));
}
private void assertNotMatching( String msg, StatePathPredicate predicate, StatePath path) {
assertFalse( msg + "expected matching path " + path + " for " + predicate, predicate.matches( path));
}
@Test
public void testChildPath() {
StatePath testPath = StatePath.parsePath( "foo.bar.baz");
StatePathPredicate predicate = new StatePathPredicate( testPath);
for( int i = 3; i > 0; i--) {
assertTrue( "predicate " + predicate + " does not match path " + testPath, predicate.matches(testPath));
testPath = testPath.childPath();
predicate = predicate.childPath();
if( i > 1) {
assertNotNull("testPath is null for loop " + i, testPath);
assertNotNull("testPathPredicate is null for loop "+i, predicate);
} else {
assertNull( "testPath not null", testPath);
assertNull( "testPathPredicate not null", predicate);
}
}
}
@Test
public void testTopElementMatches() {
// Check simple strings
StatePathPredicate nonWildPredicate = StatePathPredicate.parsePath( "aaa.bbb.ccc");
// Check some awkward cases
assertFalse( "topElementMatches() returned true for null", nonWildPredicate.topElementMatches( null));
assertFalse( "topElementMatches() returned true for wildcard character", nonWildPredicate.topElementMatches( WILDCARD_ELEMENT));
assertFalse( "topElementMatches() returned true for empty string", nonWildPredicate.topElementMatches( ""));
assertTrue( "topElement failed to match the element", nonWildPredicate.topElementMatches( "aaa"));
// Check wildcards
StatePathPredicate wildPredicate = StatePathPredicate.parsePath( "*.bbb.ccc");
assertTrue( "topElement failed to match the element", wildPredicate.topElementMatches( "aaa"));
assertTrue( "topElement failed to match the element", wildPredicate.topElementMatches( "bbb"));
}
/**
* P R I V A T E M E T H O D S
*/
/**
* Build a StatePathPredicate by composing multiple String elements up to the given depth.
* If a level has wildcard set, then a wildcard is used instead of that element.
* @param elements an array of elements
* @param wildcard a BitSet of element-depths to make wild
* @return A StatePathPredicate, built from elements, but with wildcard characters introduced.
*/
private StatePathPredicate buildWildcardPredicate( String[] elements, BitSet wildcards) {
StatePath path = null;
for( int i=0; i < elements.length; i++) {
String name = wildcards.get(i) ? WILDCARD_ELEMENT : elements [i];
path = path == null ? new StatePath( name) : path.newChild( name);
}
return new StatePathPredicate( path);
}
/**
* Build a StatePath based on elements array. However, wherever the wildcards has a
* corresponding bit set, that element is substituted by an element that otherwise
* doesn't exist. This, then, will only match if the wildcard is genuinely wild.
* @param elements an Array of elements to build the path from.
* @param wildcards a bitmap of which path elements to substitute with a wild value
* @return a StatePath, built from elements except for those elements with the corresponding bitmap bit is set.
*/
private StatePath buildMatchingPath( String[] elements, BitSet wildcards) {
StatePath path = null;
for( int i=0; i < elements.length; i++) {
String name = wildcards.get(i) ? NON_APPEARING_PATH_ELEMENT + "_" + i : elements [i];
path = path == null ? new StatePath( name) : path.newChild( name);
}
return path;
}
/**
* Build a StatePath from a list of string elements that has depth length.
* @param elements the list of elements
* @param length the depth of the elements
* @return the new StatePath
*/
private StatePath buildPath( String[] elements, int length) {
StatePath path = null;
assert length <= elements.length;
for( int i=0; i < length; i++) {
String name = elements [i];
path = path == null ? new StatePath( name) : path.newChild( name);
}
return path;
}
/**
* Test that, when building a StatePathPredicate from a StatePath, that the resulting StatePathPredicate
* matches the original StatePath.
* @param path the StatePath to test
* @return true if the resulting StatePathPredicate matches the creating StatePath.
*/
private boolean testBuildStatePath( StatePath path) {
StatePathPredicate predicate = new StatePathPredicate( path);
return predicate.matches( path);
}
}