package test;
import java.io.File;
import java.util.Properties;
import java.util.jar.Manifest;
import aQute.bnd.header.Attrs;
import aQute.bnd.header.OSGiHeader;
import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Builder;
import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.JarResource;
import aQute.bnd.osgi.Verifier;
import aQute.lib.io.IO;
import junit.framework.TestCase;
@SuppressWarnings("resource")
public class VerifierTest extends TestCase {
/**
* Verify that an invalid namespace error is actually an error
*/
public void verifyNamespace() throws Exception {
Builder b = new Builder();
b.setProperty("Require-Capability", "+++,bla.bla");
b.setProperty("Provide-Capability", "===,bla.bla");
b.setIncludeResource("foo;literal='foo'");
Jar inner = b.build();
assertTrue(b.check("The Require-Capability with namespace \\+\\+\\+ is not a symbolic name",
"The Provide-Capability with namespace === is not a symbolic name"));
}
/**
* Verify that the Meta-Persistence header is correctly verified
*
* @throws Exception
*/
public void verifyMetaPersistence() throws Exception {
Builder b = new Builder();
b.setIncludeResource("foo.xml;literal='I exist'");
Jar inner = b.build();
assertTrue(b.check());
Jar outer = new Jar("x");
outer.putResource("foo.jar", new JarResource(inner));
Manifest m = new Manifest();
m.getMainAttributes().putValue(Constants.META_PERSISTENCE, "foo.jar, foo.jar!/foo.xml, absent.xml");
outer.setManifest(m);
Verifier v = new Verifier(outer);
v.verifyMetaPersistence();
assertTrue(v.check("Meta-Persistence refers to resources not in the bundle: \\[absent.xml\\]"));
}
/**
* Check for reserved file names (INVALIDFILENAMES)
*
* @throws Exception
*/
public void testInvalidFileNames() throws Exception {
testFileName("0ABC", null, true);
testFileName("0ABC", "[0-9].*|${@}", false);
testFileName("com1", null, false);
testFileName("COM1", null, false);
testFileName("cOm1", null, false);
testFileName("aux", null, false);
testFileName("AUX", null, false);
testFileName("XYZ", null, true);
testFileName("XYZ", "XYZ|${@}", false);
testFileName("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", ".{33,}|${@}", false);
testFileName("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", null, true);
testFileName("clock$", null, false);
testFileName("clock", null, true);
}
private void testFileName(String segment, String pattern, boolean answer) throws Exception {
testFilePath(segment, pattern, answer);
testFilePath("abc/" + segment, pattern, answer);
testFilePath("abc/" + segment + "/def", pattern, answer);
testFilePath(segment + "/def", pattern, answer);
}
private void testFilePath(String path, String pattern, boolean good) throws Exception {
Builder b = new Builder();
try {
b.setProperty("-includeresource", path + ";literal='x'");
if (pattern != null)
b.setProperty(Constants.INVALIDFILENAMES, pattern);
b.build();
if (good)
assertTrue(b.check());
else
assertTrue(b.check("Invalid file/directory"));
} finally {
b.close();
}
}
/**
* Create a require capality filter verification test
*
* @throws Exception
*/
public void testInvalidFilterOnRequirement() throws Exception {
Builder b = new Builder();
b.addClasspath(IO.getFile("jar/osgi.jar"));
b.setExportPackage("org.osgi.framework");
b.setProperty("Require-Capability",
"test; filter:=\"(&(test=aName)(version>=1.1.0))\", "
+ " test; filter:=\"(&(version>=1.1)(string~=astring))\", "
+ " test; filter:=\"(&(version>=1.1)(long>=99))\", "
+ " test; filter:=\"(&(version>=1.1)(double>=1.0))\", "
+ " test; filter:=\"(&(version>=1.1)(version.list=1.0)(version.list=1.1)(version.list=1.2))\", "
+ " test; filter:=\"(&(version>=1.1)(long.list=1)(long.list=2)(long.list=3)(long.list=4))\", "
+ " test; filter:=\"(&(version>=1.1)(double.list=1.001)(double.list=1.002)(double.list=1.003)(double.list<=1.3))\", "
+ " test; filter:=\"(&(version>=1.1)(string.list~=astring)(string.list~=bstring)(string.list=cString))\", "
+ " test; filter:=\"(&(version>=1.1)(string.list2=a\\\"quote)(string.list2=a\\,comma)(string.list2= aSpace )(string.list2=\\\"start)(string.list2=\\,start)(string.list2=end\\\")(string.list2=end\\,))\", "
+ " test; filter:=\"(&(version>=1.1)(string.list3= aString )(string.list3= bString )(string.list3= cString ))\", "
+ " test.effective; effective:=\"active\"; filter:=\"(willResolve=false)\", test.no.attrs");
b.build();
assertTrue(b.check());
}
/**
* Create a require capality directive test
*
* @throws Exception
*/
public void testValidDirectivesOnRequirement() throws Exception {
Builder b = new Builder();
b.addClasspath(IO.getFile("jar/osgi.jar"));
b.setExportPackage("org.osgi.framework");
b.setProperty("Require-Capability", "test; resolution:=mandatory, " + " test; resolution:=optional, "
+ " test; cardinality:=single, " + " test; cardinality:=multiple, " + " test; effective:=foo, "
+ " test; filter:=\"(&(version>=1.1)(long.list=1)(long.list=2))\", " + " test; x-custom:=bar, ");
b.build();
assertTrue(b.check());
}
/**
* Test the strict flag
*/
public void testStrict() throws Exception {
Builder bmaker = new Builder();
bmaker.addClasspath(IO.getFile("jar/osgi.jar"));
bmaker.addClasspath(new File("bin"));
bmaker.setProperty("Export-Package",
"org.osgi.service.eventadmin;version='[1,2)',org.osgi.framework;version=x13,test;-remove-attribute:=version,test.lib;specification-version=12,test.split");
bmaker.setProperty("Import-Package",
"foo;version=1,bar;version='[1,x2)',baz;version='[2,1)',baz2;version='(1,1)',*");
bmaker.setProperty("-strict", "true");
bmaker.setProperty("-fixupmessages", "^Exception: ");
Jar jar = bmaker.build();
assertTrue(bmaker.check(
"\\QInvalid syntax for version: x13, for cmd: range, arguments; [range, [==,+)]\\E",
"\\QImport Package org.osgi.framework has an invalid version range syntax ${range;[==,+)}\\E",
"\\QNo translation found for macro: range;[==,+)\\E",
"\\QExport-Package or -exportcontents refers to missing package 'org.osgi.service.eventadmin'\\E",
"Import Package clauses without version range \\(excluding javax\\.\\*\\):",
"Import Package bar has an invalid version range syntax \\[1,x2\\)",
"Import Package baz2 has an empty version range syntax \\(1,1\\), likely want to use \\[1.0.0,1.0.0\\]",
"Import Package baz has an invalid version range syntax \\[2,1\\): java.lang.IllegalArgumentException: Low Range is higher than High Range: 2.0.0-1.0.0",
"Import Package clauses which use a version instead of a version range. This imports EVERY later package and not as many expect until the next major number: \\[foo\\]",
"Export Package org.osgi.framework version has invalid syntax: x13",
"Export Package test.lib uses deprecated specification-version instead of version",
"Export Package org.osgi.service.eventadmin version is a range: \\[1,2\\); Exports do not allow for ranges."));
}
public static void testCapability() throws Exception {
Parameters h = OSGiHeader.parseHeader(
"test; version.list:List < Version > = \"1.0, 1.1, 1.2\"; effective:=\"resolve\"; test =\"aName\";version : Version=\"1.0\"; long :Long=\"100\"; "
+ "double: Double=\"1.001\"; string:String =\"aString\"; "
+ "long.list : List <Long >=\"1, 2, 3, 4\";double.list: List< Double>= \"1.001, 1.002, 1.003\"; "
+ "string.list :List<String >= \"aString,bString,cString\"");
assertEquals(Attrs.Type.VERSION, h.get("test").getType("version"));
assertEquals(Attrs.Type.LONG, h.get("test").getType("long"));
assertEquals(Attrs.Type.DOUBLE, h.get("test").getType("double"));
assertEquals(Attrs.Type.STRING, h.get("test").getType("string"));
assertEquals(Attrs.Type.STRING, h.get("test").getType("test"));
assertEquals(Attrs.Type.LONGS, h.get("test").getType("long.list"));
assertEquals(Attrs.Type.DOUBLES, h.get("test").getType("double.list"));
assertEquals(Attrs.Type.STRINGS, h.get("test").getType("string.list"));
assertEquals(Attrs.Type.VERSIONS, h.get("test").getType("version.list"));
}
public static void testFailedOSGiJar() throws Exception {
Jar jar = new Jar("jar/osgi.residential-4.3.0.jar");
Verifier v = new Verifier(jar);
assertTrue(v.check());
}
public static void testnativeCode() throws Exception {
Builder b = new Builder();
b.addClasspath(new File("bin"));
b.setProperty("-resourceonly", "true");
b.setProperty("Include-Resource", "native/win32/NTEventLogAppender-1.2.dll;literal='abc'");
b.setProperty("Bundle-NativeCode", "native/win32/NTEventLogAppender-1.2.dll; osname=Win32; processor=x86");
b.build();
Verifier v = new Verifier(b);
v.verifyNative();
System.err.println(v.getErrors());
assertEquals(0, v.getErrors().size());
v.close();
b.close();
}
public static void testFilter() {
testFilter("(&(a=b)(c=1))");
testFilter("(&(a=b)(!(c=1))(&(c=1))(c=1)(c=1)(c=1)(c=1)(c=1)(c=1)(c=1)(c=1))");
testFilter("(!(a=b))");
testInvalidFilter("(!(a=b)(c=2))");
testInvalidFilter("(axb)");
testInvalidFilter("(a=3 ");
testFilter("(room=*)");
testFilter("(room=bedroom)");
testFilter("(room~= B E D R O O M )");
testFilter("(room=abc)");
testFilter(" ( room >=aaaa)");
testFilter("(room <=aaaa)");
testFilter(" ( room =b*) ");
testFilter(" ( room =*m) ");
testFilter("(room=bed*room)");
testFilter(" ( room =b*oo*m) ");
testFilter(" ( room =*b*oo*m*) ");
testFilter(" ( room =b*b* *m*) ");
testFilter(" (& (room =bedroom) (channel ~=34))");
testFilter(" (& (room =b*) (room =*x) (channel=34))");
testFilter("(| (room =bed*)(channel=222)) ");
testFilter("(| (room =boom*)(channel=101)) ");
testFilter(" (! (room =ab*b*oo*m*) ) ");
testFilter(" (status =\\(o*\\\\\\)\\*) ");
testFilter(" (canRecord =true\\(x\\)) ");
testFilter("(max Record Time <=140) ");
testFilter("(shortValue >=100) ");
testFilter("(intValue <=100001) ");
testFilter("(longValue >=10000000000) ");
testFilter(" ( & ( byteValue <=100) ( byteValue >=10) ) ");
testFilter("(weirdValue =100) ");
testFilter("(bigIntValue =4123456) ");
testFilter("(bigDecValue =4.123456) ");
testFilter("(floatValue >=1.0) ");
testFilter("(doubleValue <=2.011) ");
testFilter("(charValue ~=a) ");
testFilter("(booleanValue =true) ");
testFilter("(primIntArrayValue =1) ");
testFilter("(primLongArrayValue =2) ");
testFilter("(primByteArrayValue =3) ");
testFilter("(primShortArrayValue =1) ");
testFilter("(primFloatArrayValue =1.1) ");
testFilter("(primDoubleArrayValue =2.2) ");
testFilter("(primCharArrayValue ~=D) ");
testFilter("(primBooleanArrayValue =false) ");
testFilter("(& (| (room =d*m) (room =bed*) (room=abc)) (! (channel=999)))");
testFilter("(room=bedroom)");
testFilter("(*=foo)");
testInvalidFilter("(! ab=b)");
testInvalidFilter("(| ab=b)");
testInvalidFilter("(&=c)");
testInvalidFilter("(!=c)");
testInvalidFilter("(|=c)");
testInvalidFilter("(& ab=b)");
testInvalidFilter("(!ab=*)");
testInvalidFilter("(|ab=*)");
testInvalidFilter("(&ab=*)");
testFilter("(empty=)");
testFilter("(empty=*)");
testFilter("(space= )");
testFilter("(space=*)");
testFilter("(intvalue=*)");
testFilter("(intvalue=b)");
testFilter("(intvalue=)");
testFilter("(longvalue=*)");
testFilter("(longvalue=b)");
testFilter("(longvalue=)");
testFilter("(shortvalue=*)");
testFilter("(shortvalue=b)");
testFilter("(shortvalue=)");
testFilter("(bytevalue=*)");
testFilter("(bytevalue=b)");
testFilter("(bytevalue=)");
testFilter("(charvalue=*)");
testFilter("(charvalue=)");
testFilter("(floatvalue=*)");
testFilter("(floatvalue=b)");
testFilter("(floatvalue=)");
testFilter("(doublevalue=*)");
testFilter("(doublevalue=b)");
testFilter("(doublevalue=)");
testFilter("(booleanvalue=*)");
testFilter("(booleanvalue=b)");
testFilter("(booleanvalue=)");
testInvalidFilter("");
testInvalidFilter("()");
testInvalidFilter("(=foo)");
testInvalidFilter("(");
testInvalidFilter("(abc = ))");
testInvalidFilter("(& (abc = xyz) (& (345))");
testInvalidFilter(" (room = b**oo!*m*) ) ");
testInvalidFilter(" (room = b**oo)*m*) ) ");
testInvalidFilter(" (room = *=b**oo*m*) ) ");
testInvalidFilter(" (room = =b**oo*m*) ) ");
testFilter("(shortValue =100*) ");
testFilter("(intValue =100*) ");
testFilter("(longValue =100*) ");
testFilter("( byteValue =1*00 )");
testFilter("(bigIntValue =4*23456) ");
testFilter("(bigDecValue =4*123456) ");
testFilter("(floatValue =1*0) ");
testFilter("(doubleValue =2*011) ");
testFilter("(charValue =a*) ");
testFilter("(booleanValue =t*ue) ");
}
private static void testFilter(String string) {
int index = Verifier.verifyFilter(string, 0);
while (index < string.length() && Character.isWhitespace(string.charAt(index)))
index++;
if (index != string.length())
throw new IllegalArgumentException("Characters after filter");
}
private static void testInvalidFilter(String string) {
try {
testFilter(string);
fail("Invalid filter");
} catch (Exception e) {}
}
public static void testBundleActivationPolicyNone() throws Exception {
Builder v = new Builder();
v.setProperty("Private-Package", "test.activator");
v.addClasspath(new File("bin"));
v.build();
assertTrue(v.check());
}
public static void testBundleActivationPolicyBad() throws Exception {
Builder v = new Builder();
v.setProperty("Private-Package", "test.activator");
v.addClasspath(new File("bin"));
v.setProperty(Constants.BUNDLE_ACTIVATIONPOLICY, "eager");
v.build();
assertTrue(v.check("Bundle-ActivationPolicy set but is not set to lazy: eager"));
}
public static void testBundleActivationPolicyGood() throws Exception {
Builder v = new Builder();
v.setProperty("Private-Package", "test.activator");
v.addClasspath(new File("bin"));
v.setProperty(Constants.BUNDLE_ACTIVATIONPOLICY, "lazy ; hello:=1");
v.build();
assertTrue(v.check());
}
public static void testBundleActivationPolicyMultiple() throws Exception {
Builder v = new Builder();
v.setProperty("Private-Package", "test.activator");
v.addClasspath(new File("bin"));
v.setProperty(Constants.BUNDLE_ACTIVATIONPOLICY, "lazy;hello:=1,2");
v.build();
assertTrue(v.check("Bundle-ActivationPolicy has too many arguments lazy;hello:=1,2"));
}
public static void testInvalidCaseForHeader() throws Exception {
Properties p = new Properties();
p.put("Export-package", "org.apache.mina.*");
p.put("Bundle-Classpath", ".");
Analyzer analyzer = new Analyzer();
analyzer.setProperties(p);
analyzer.getProperties();
System.err.println("Errors " + analyzer.getErrors());
System.err.println("Warnings " + analyzer.getWarnings());
assertEquals(0, analyzer.getErrors().size());
assertEquals(2, analyzer.getWarnings().size());
}
public static void testSimple() throws Exception {
Builder bmaker = new Builder();
bmaker.addClasspath(IO.getFile("jar/mina.jar"));
bmaker.set("Export-Package", "org.apache.mina.*;version=1");
bmaker.set("DynamicImport-Package", "org.slf4j");
Jar jar = bmaker.build();
assertTrue(bmaker.check());
Manifest m = jar.getManifest();
m.write(System.err);
assertTrue(m.getMainAttributes().getValue("Import-Package").indexOf("org.slf4j") >= 0);
assertTrue(m.getMainAttributes().getValue("DynamicImport-Package").indexOf("org.slf4j") >= 0);
}
}