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); } }