blob: f9fbd40973294922ce7794f106096846e1664dfc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.tests.filter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import junit.framework.AssertionFailedError;
import org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap;
import org.eclipse.osgi.tests.util.MapDictionary;
import org.junit.Assert;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
public abstract class FilterTests {
/**
* Fail with cause t.
*
* @param message Failure message.
* @param t Cause of the failure.
*/
public static void fail(String message, Throwable t) {
AssertionFailedError e = new AssertionFailedError(message + ": " + t.getMessage());
e.initCause(t);
throw e;
}
static final int ISTRUE = 1;
static final int ISFALSE = 2;
static final int ISILLEGAL = 3;
public abstract Filter createFilter(String filterString) throws InvalidSyntaxException;
private Dictionary getProperties() {
Dictionary props = new Hashtable();
props.put("room", "bedroom");
props.put("channel", new Object[] { Integer.valueOf(34), "101" });
props.put("status", "(on\\)*");
List vec = new ArrayList(10);
vec.add(Long.valueOf(150));
vec.add("100");
props.put("max record time", vec);
props.put("canrecord", "true(x)");
props.put("shortvalue", Short.valueOf((short) 1000));
props.put("intvalue", Integer.valueOf(100000));
props.put("longvalue", Long.valueOf(10000000000L));
props.put("bytevalue", Byte.valueOf((byte) 10));
props.put("floatvalue", Float.valueOf(1.01f));
props.put("doublevalue", Double.valueOf(2.01));
props.put("charvalue", Character.valueOf('A'));
props.put("booleanvalue", Boolean.TRUE);
props.put("weirdvalue", new Hashtable());
props.put("primintarrayvalue", new int[] { 1, 2, 3 });
props.put("primlongarrayvalue", new long[] { 1, 2, 3 });
props.put("primbytearrayvalue", new byte[] { (byte) 1, (byte) 2, (byte) 3 });
props.put("primshortarrayvalue", new short[] { (short) 1, (short) 2, (short) 3 });
props.put("primfloatarrayvalue", new float[] { (float) 1.1, (float) 2.2, (float) 3.3 });
props.put("primdoublearrayvalue", new double[] { 1.1, 2.2, 3.3 });
props.put("primchararrayvalue", new char[] { 'A', 'b', 'C', 'd' });
props.put("primbooleanarrayvalue", new boolean[] { false });
props.put("bigintvalue", new BigInteger("4123456"));
props.put("bigdecvalue", new BigDecimal("4.123456"));
props.put("*", "foo");
props.put("! ab", "b");
props.put("| ab", "b");
props.put("& ab", "b");
props.put("!", "c");
props.put("|", "c");
props.put("&", "c");
props.put("empty", "");
props.put("space", Character.valueOf(' '));
return props;
}
@Test
public void testFilter() {
Dictionary props = getProperties();
testFilter("(room=*)", props, ISTRUE);
testFilter("(room=bedroom)", props, ISTRUE);
testFilter("(room~= B E D R O O M )", props, ISTRUE);
testFilter("(room=abc)", props, ISFALSE);
testFilter(" ( room >=aaaa)", props, ISTRUE);
testFilter("(room <=aaaa)", props, ISFALSE);
testFilter(" ( room =b*) ", props, ISTRUE);
testFilter(" ( room =*m) ", props, ISTRUE);
testFilter("(room=bed*room)", props, ISTRUE);
testFilter(" ( room =b*oo*m) ", props, ISTRUE);
testFilter(" ( room =*b*oo*m*) ", props, ISTRUE);
testFilter(" ( room =b*b* *m*) ", props, ISFALSE);
testFilter(" (& (room =bedroom) (channel ~=34))", props, ISTRUE);
testFilter(" (& (room =b*) (room =*x) (channel=34))", props, ISFALSE);
testFilter("(| (room =bed*)(channel=222)) ", props, ISTRUE);
testFilter("(| (room =boom*)(channel=101)) ", props, ISTRUE);
testFilter(" (! (room =ab*b*oo*m*) ) ", props, ISTRUE);
testFilter(" (status =\\(o*\\\\\\)\\*) ", props, ISTRUE);
testFilter(" (canRecord =true\\(x\\)) ", props, ISTRUE);
testFilter("(max Record Time <=140) ", props, ISTRUE);
testFilter("(shortValue >=100) ", props, ISTRUE);
testFilter("(intValue <=100001) ", props, ISTRUE);
testFilter("(longValue >=10000000000) ", props, ISTRUE);
testFilter(" ( & ( byteValue <=100) ( byteValue >=10) ) ", props, ISTRUE);
testFilter("(weirdValue =100) ", props, ISFALSE);
testFilter("(bigIntValue =4123456) ", props, ISTRUE);
testFilter("(bigDecValue =4.123456) ", props, ISTRUE);
testFilter("(floatValue >=1.0) ", props, ISTRUE);
testFilter("(doubleValue <=2.011) ", props, ISTRUE);
testFilter("(charValue ~=a) ", props, ISTRUE);
testFilter("(booleanValue =true) ", props, ISTRUE);
testFilter("(primIntArrayValue =1) ", props, ISTRUE);
testFilter("(primLongArrayValue =2) ", props, ISTRUE);
testFilter("(primByteArrayValue =3) ", props, ISTRUE);
testFilter("(primShortArrayValue =1) ", props, ISTRUE);
testFilter("(primFloatArrayValue =1.1) ", props, ISTRUE);
testFilter("(primDoubleArrayValue =2.2) ", props, ISTRUE);
testFilter("(primCharArrayValue ~=D) ", props, ISTRUE);
testFilter("(primBooleanArrayValue =false) ", props, ISTRUE);
testFilter("(& (| (room =d*m) (room =bed*) (room=abc)) (! (channel=999)))", props, ISTRUE);
testFilter("(room=bedroom)", null, ISFALSE);
testFilter("(*=foo)", props, ISTRUE);
testFilter("(! ab=b)", props, ISTRUE);
testFilter("(| ab=b)", props, ISTRUE);
testFilter("(&=c)", props, ISTRUE);
testFilter("(!=c)", props, ISTRUE);
testFilter("(|=c)", props, ISTRUE);
testFilter("(& ab=b)", props, ISTRUE);
testFilter("(!ab=*)", props, ISFALSE);
testFilter("(|ab=*)", props, ISFALSE);
testFilter("(&ab=*)", props, ISFALSE);
testFilter("(empty=)", props, ISTRUE);
testFilter("(empty=*)", props, ISTRUE);
testFilter("(space= )", props, ISTRUE);
testFilter("(space=*)", props, ISTRUE);
}
@Test
public void testInvalidValues() {
Dictionary props = getProperties();
testFilter("(intvalue=*)", props, ISTRUE);
testFilter("(intvalue=b)", props, ISFALSE);
testFilter("(intvalue=)", props, ISFALSE);
testFilter("(longvalue=*)", props, ISTRUE);
testFilter("(longvalue=b)", props, ISFALSE);
testFilter("(longvalue=)", props, ISFALSE);
testFilter("(shortvalue=*)", props, ISTRUE);
testFilter("(shortvalue=b)", props, ISFALSE);
testFilter("(shortvalue=)", props, ISFALSE);
testFilter("(bytevalue=*)", props, ISTRUE);
testFilter("(bytevalue=b)", props, ISFALSE);
testFilter("(bytevalue=)", props, ISFALSE);
testFilter("(charvalue=*)", props, ISTRUE);
testFilter("(charvalue=)", props, ISFALSE);
testFilter("(floatvalue=*)", props, ISTRUE);
testFilter("(floatvalue=b)", props, ISFALSE);
testFilter("(floatvalue=)", props, ISFALSE);
testFilter("(doublevalue=*)", props, ISTRUE);
testFilter("(doublevalue=b)", props, ISFALSE);
testFilter("(doublevalue=)", props, ISFALSE);
testFilter("(booleanvalue=*)", props, ISTRUE);
testFilter("(booleanvalue=b)", props, ISFALSE);
testFilter("(booleanvalue=)", props, ISFALSE);
}
@Test
public void testIllegal() {
Dictionary props = getProperties();
testFilter("", props, ISILLEGAL);
testFilter("()", props, ISILLEGAL);
testFilter("(=foo)", props, ISILLEGAL);
testFilter("(", props, ISILLEGAL);
testFilter("(abc = ))", props, ISILLEGAL);
testFilter("(& (abc = xyz) (& (345))", props, ISILLEGAL);
testFilter(" (room = b**oo!*m*) ) ", props, ISILLEGAL);
testFilter(" (room = b**oo)*m*) ) ", props, ISILLEGAL);
testFilter(" (room = *=b**oo*m*) ) ", props, ISILLEGAL);
testFilter(" (room = =b**oo*m*) ) ", props, ISILLEGAL);
}
@Test
public void testScalarSubstring() {
Dictionary props = getProperties();
testFilter("(shortValue =100*) ", props, ISFALSE);
testFilter("(intValue =100*) ", props, ISFALSE);
testFilter("(longValue =100*) ", props, ISFALSE);
testFilter("( byteValue =1*00 )", props, ISFALSE);
testFilter("(bigIntValue =4*23456) ", props, ISFALSE);
testFilter("(bigDecValue =4*123456) ", props, ISFALSE);
testFilter("(floatValue =1*0) ", props, ISFALSE);
testFilter("(doubleValue =2*011) ", props, ISFALSE);
testFilter("(charValue =a*) ", props, ISFALSE);
testFilter("(booleanValue =t*ue) ", props, ISFALSE);
}
@Test
public void testNormalization() {
try {
Filter f1 = createFilter("( a = bedroom )");
Filter f2 = createFilter(" (a= bedroom ) ");
assertEquals("not equal", "(a= bedroom )", f1.toString());
assertEquals("not equal", "(a= bedroom )", f2.toString());
assertEquals("not equal", f1, f2);
assertEquals("not equal", f2, f1);
assertEquals("not equal", f1.hashCode(), f2.hashCode());
} catch (InvalidSyntaxException e) {
fail("unexpected invalid syntax", e);
}
}
private void testFilter(String query, Dictionary props, int expect) {
final ServiceReference ref = new DictionaryServiceReference(props);
Filter f1;
try {
f1 = createFilter(query);
if (expect == ISILLEGAL) {
Assert.fail("expected exception");
}
} catch (InvalidSyntaxException e) {
if (expect != ISILLEGAL) {
fail("exception", e);
}
return;
}
boolean val = f1.match(props);
assertEquals("wrong result", expect == ISTRUE, val);
val = f1.match(ref);
assertEquals("wrong result", expect == ISTRUE, val);
String normalized = f1.toString();
Filter f2;
try {
f2 = createFilter(normalized);
} catch (InvalidSyntaxException e) {
fail("exception", e);
return;
}
val = f2.match(props);
assertEquals("wrong result", expect == ISTRUE, val);
val = f2.match(ref);
assertEquals("wrong result", expect == ISTRUE, val);
assertEquals("normalized not equal", normalized, f2.toString());
}
@Test
public void testComparable() {
Filter f1 = null;
Object comp42 = new SampleComparable("42");
Object comp43 = new SampleComparable("43");
Hashtable hash = new Hashtable();
try {
f1 = createFilter("(comparable=42)");
} catch (InvalidSyntaxException e) {
fail("invalid syntax", e);
}
hash.put("comparable", comp42);
assertTrue("does not match filter", f1.match(hash));
assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash)));
hash.put("comparable", comp43);
assertFalse("does match filter", f1.match(hash));
assertFalse("does match filter", f1.match(new DictionaryServiceReference(hash)));
try {
f1 = createFilter("(comparable<=42)");
} catch (InvalidSyntaxException e) {
fail("invalid syntax", e);
}
hash.put("comparable", comp42);
assertTrue("does not match filter", f1.match(hash));
assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash)));
hash.put("comparable", comp43);
assertFalse("does match filter", f1.match(hash));
assertFalse("does match filter", f1.match(new DictionaryServiceReference(hash)));
try {
f1 = createFilter("(comparable>=42)");
} catch (InvalidSyntaxException e) {
fail("invalid syntax", e);
}
hash.put("comparable", comp42);
assertTrue("does not match filter", f1.match(hash));
assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash)));
hash.put("comparable", comp43);
assertTrue("does not match filter", f1.match(hash));
assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash)));
try {
f1 = createFilter("(comparable=4*2)");
} catch (InvalidSyntaxException e) {
fail("invalid syntax", e);
}
hash.put("comparable", comp42);
assertFalse("does match filter", f1.match(hash));
assertFalse("does match filter", f1.match(new DictionaryServiceReference(hash)));
}
@Test
public void testObject() {
Filter f1 = null;
Object obj42 = new SampleObject("42");
Object obj43 = new SampleObject("43");
Hashtable hash = new Hashtable();
try {
f1 = createFilter("(object=42)");
} catch (InvalidSyntaxException e) {
fail("invalid syntax", e);
}
hash.put("object", obj42);
assertTrue("does not match filter", f1.match(hash));
assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash)));
hash.put("object", obj43);
assertFalse("does match filter", f1.match(hash));
assertFalse("does match filter", f1.match(new DictionaryServiceReference(hash)));
try {
f1 = createFilter("(object=4*2)");
} catch (InvalidSyntaxException e) {
fail("invalid syntax", e);
}
hash.put("object", obj42);
assertFalse("does match filter", f1.match(hash));
assertFalse("does match filter", f1.match(new DictionaryServiceReference(hash)));
}
@Test
public void testNullValueMatch() throws InvalidSyntaxException {
Dictionary<String, Object> nullProps = new MapDictionary<>();
nullProps.put("test.null", null);
nullProps.put("test.non.null", "v1");
assertFalse(createFilter("(test.null=*)").match(nullProps));
assertTrue(createFilter("(&(!(test.null=*))(test.non.null=v1))").match(nullProps));
}
@Test
public void testNullKeyMatch() throws InvalidSyntaxException {
Dictionary<String, Object> nullProps = new MapDictionary<>();
nullProps.put(null, "null.v1");
nullProps.put("test.non.null", "v1");
assertTrue(createFilter("(test.non.null=v1)").match(nullProps));
}
public static class SampleComparable implements Comparable {
private int value = -1;
public SampleComparable(String value) {
this.value = Integer.parseInt(value);
}
@Override
public int compareTo(Object o) {
return value - ((SampleComparable) o).value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
public static class SampleObject {
private int value = -1;
public SampleObject(String value) {
this.value = Integer.parseInt(value);
}
@Override
public boolean equals(Object o) {
if (o instanceof SampleObject) {
return value == ((SampleObject) o).value;
}
return false;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
private static class DictionaryServiceReference implements ServiceReference {
private final Dictionary dictionary;
private final String[] keys;
DictionaryServiceReference(Dictionary dictionary) {
if (dictionary == null) {
this.dictionary = null;
this.keys = new String[] {};
return;
}
this.dictionary = dictionary;
List keyList = new ArrayList(dictionary.size());
for (Enumeration e = dictionary.keys(); e.hasMoreElements();) {
Object k = e.nextElement();
if (k instanceof String) {
String key = (String) k;
for (Iterator i = keyList.iterator(); i.hasNext();) {
if (key.equalsIgnoreCase((String) i.next())) {
throw new IllegalArgumentException();
}
}
keyList.add(key);
}
}
this.keys = (String[]) keyList.toArray(new String[keyList.size()]);
}
public Object getProperty(String k) {
for (int i = 0, length = keys.length; i < length; i++) {
String key = keys[i];
if (key.equalsIgnoreCase(k)) {
return dictionary.get(key);
}
}
return null;
}
public String[] getPropertyKeys() {
return keys.clone();
}
public int compareTo(Object reference) {
throw new UnsupportedOperationException();
}
public Bundle getBundle() {
throw new UnsupportedOperationException();
}
public Bundle[] getUsingBundles() {
throw new UnsupportedOperationException();
}
public boolean isAssignableTo(Bundle bundle, String className) {
throw new UnsupportedOperationException();
}
@Override
public Dictionary getProperties() {
if (dictionary == null) {
return new CaseInsensitiveDictionaryMap();
}
return new CaseInsensitiveDictionaryMap(dictionary);
}
}
}