Package test

Source Code of test.BuilderTest

package test;

import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.util.regex.*;

import aQute.bnd.header.*;
import aQute.bnd.osgi.*;
import aQute.bnd.test.*;
import aQute.bnd.version.*;
import aQute.lib.collections.*;
import aQute.lib.hex.*;
import aQute.lib.io.*;
import aQute.service.reporter.Report.Location;

@SuppressWarnings("resource")
public class BuilderTest extends BndTestCase {

  /**
   * Test if the Manifest gets the last modified date
   */

  public void testLastModifiedForManifest() throws Exception {
    File file = new File("tmp.jar");
    try {
      long time = System.currentTimeMillis();

      Builder b = new Builder();
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.setExportPackage("org.osgi.framework");
      Jar build = b.build();
      try {
        assertTrue(b.check());

        build.write("tmp.jar");
        Jar ajr = new Jar(file);
        try {
          Resource r = ajr.getResource("META-INF/MANIFEST.MF");
          assertNotNull(r);
          long t = r.lastModified();
          Date date = new Date(t);
          System.out.println(date + " " + t);
          // TODO we need to adapt the timestamp handling
          assertTrue(date + " " + t, t ==1142555622000L);
        }
        finally {
          ajr.close();
        }
      }
      finally {
        build.close();
      }
    }
    finally {
      file.delete();
    }

  }

  /**
   * A Require-Bundle should not fail on missing imports, just warn
   *
   * @throws Exception
   */

  public void testMissingImportWithRequireBundle() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(new File("bin"));
      b.setPedantic(true);
      b.setExportPackage("test.classreference;version=1");
      b.setImportPackage("!*");
      b.setProperty("Require-Bundle", "com.abc");
      b.build();
      assertTrue(b.check());

      Verifier v = new Verifier(b.getJar());
      v.verify();
      assertTrue(v.check());
    }
    finally {
      b.close();
    }
  }

  /**
   * #479 I have now tested this locally. Apparently the fix doesn't change
   * the reported behavior. In my test bundle, I have removed all imports. Bnd
   * builds this with no errors reported. I add: DynamicImport-Package: dummy
   */

  public void testMissingImportsWithDynamicImport() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(new File("bin"));
      b.setPedantic(true);
      b.setExportPackage("test.classreference;version=1");
      b.setImportPackage("!*");
      b.setProperty(Constants.DYNAMICIMPORT_PACKAGE, "dummy");
      b.build();
      assertTrue(b.check());

      Verifier v = new Verifier(b.getJar());
      try {
        v.verify();
        assertTrue(v.check("Unresolved references to \\[javax.swing\\] by class\\(es\\)"));
      }
      finally {
        v.close();
      }
    }
    finally {
      b.close();
    }
  }

  /**
   * #479 I have now tested this locally. Apparently the fix doesn't change
   * the reported behavior. In my test bundle, I have removed all imports. Bnd
   * builds this with no errors reported. I add: DynamicImport-Package: dummy
   */

  public void testMissingImportsWithoutDynamicImport() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(new File("bin"));
      b.setPedantic(true);
      b.setExportPackage("test.classreference;version=1");
      b.setImportPackage("!*");
      b.build();
      assertTrue(b.check());

      Verifier v = new Verifier(b.getJar());
      try {
        v.verify();
        assertTrue(v.check("Unresolved references to \\[javax.swing\\] by class\\(es\\)"));
      }
      finally {
        v.close();
      }
    }
    finally {
      b.close();
    }

  }

  /**
   * <pre>
   * [2013-12-11 15:55:14] BJ Hargrave: init:
   *      [echo] Enter project org.osgi.test.cases.prefs (${top})
   * [bndprepare] 2 WARNINGS
   * [bndprepare]  No translation found for macro: classes;extending;junit.framework.TestCase;concrete
   * [bndprepare]  No translation found for macro: classes,concrete
   * [2013-12-11 15:55:31] BJ Hargrave: I am getting this on the latest bnd.master in the OSGi test projects
   * </pre>
   *
   * @throws Exception
   */

  public static void testClassQuery() throws Exception {
    Builder a = new Builder();
    try {
      a.addClasspath(new File("bin"));
      a.setExportPackage("test.component");
      a.setProperty("testcases", "${sort;${classes;extending;junit.framework.TestCase;concrete}}");
      a.setProperty("Test-Cases", "${testcases}");
      Jar jar = a.build();
      assertTrue(a.check());
      Manifest m = jar.getManifest();
      Parameters p = new Parameters(m.getMainAttributes().getValue("Test-Cases"));
      assertTrue(p.size() >= 4);
    }
    finally {
      a.close();
    }
  }

  /**
   * Bundle ActivationPolicy
   *
   * @throws Exception
   */
  public void testBundleActivationPolicy() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("bin"));
      ;
      b.setProperty("Bundle-ActivationPolicy", "lazy");
      b.setProperty("Export-Package", "test.activator");
      b.build();
      assertTrue(b.check());
    }
    finally {
      b.close();
    }
  }

  /**
   * #388 Manifest header to get GIT head
   */
  public void testGitHead() {
    Builder b = new Builder();
    try {
      String s = b.getReplacer().process("${githead}");
      assertTrue(Hex.isHex(s));
    }
    finally {
      b.close();
    }
  }

  /**
   * If a package-info.java + packageinfo are present then normally
   * package-info takes precedence if it sets a Version. This test sees that
   * if no version is sets, packageinfo is used.
   */
  public void testPackageInfo_no_version() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(new File("bin"));
      b.setExportPackage("test.packageinfo.both_no_version");
      Jar build = b.build();
      assertTrue(b.check());

      Attrs imports = b.getExports().getByFQN("test.packageinfo.both_no_version");
      assertEquals("1.2.3", imports.getVersion());
    }
    finally {
      b.close();
    }

  }

  /**
   * An old osgi 3.0.0 jar had an old packageinfo in it. This included some
   * never well developed syntax which now clashes with the proprty syntax.
   *
   * @throws Exception
   */
  public void testVeryOldPackageInfo() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi-3.0.0.jar"));
      b.setExportPackage("org.osgi.util.measurement;version=100, org.osgi.util.tracker;version=100, *");
      Jar build = b.build();
      assertTrue(b.check("Version for package org.osgi.util.measurement is set to different values in the source ", "Version for package org.osgi.util.tracker is set to different values in the source"));
    }
    finally {
      b.close();
    }

  }

  /**
   * Using a package info without the version keyword gives strange results in
   * the manifest, should generate an error.
   */

  public void testBadPackageInfo() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(new File("bin"));
      b.setExportPackage("test.package_info_versioniskey");
      b.build();

      String message = b.getErrors().get(0);
      assertTrue("The lacking version error first",
          message.contains("package info for test.package_info_versioniskey attribute [1.0.0=''],"));
      Location location = b.getLocation(message);
      assertNotNull("Supposed to have a location", location);
      assertNotNull("And that must have a file", location.file);
      assertEquals("Which should be the packaginfo file", "packageinfo", new File(location.file).getName());
      assertEquals(4, location.line);
      assertEquals(5, location.length);

      assertTrue(b.check("package info for test.package_info_versioniskey attribute \\[1.0.0=''\\],"));
    }
    finally {
      b.close();
    }
  }

  /**
   * https://github.com/bndtools/bnd/issues/359 Starts with a bundle that has
   * one package 'a' containing classes A and B. First removes B from 'a', and
   * checks that the last modified date of the resulting bundle changed. Then
   * removes A from 'a', and checks again that the last modified data changed.
   */
  public static void testRemoveClassFromPackage() throws Exception {
    try {
      Builder b = new Builder();
      try {
        IO.getFile("bin/a1/a").mkdirs();
        IO.copy(IO.getFile("bin/a/A.class"), IO.getFile("bin/a1/a/A.class"));
        IO.copy(IO.getFile("bin/a/B.class"), IO.getFile("bin/a1/a/B.class"));
        Jar classpath = new Jar(IO.getFile("bin/a1"));
        b.addClasspath(classpath);
        b.setPrivatePackage("a");
        Jar result = b.build();
        Resource ra = result.getResource("a/A.class");
        Resource rb = result.getResource("a/B.class");
        long lm1 = result.lastModified();
        assertTrue("Last modified date of bundle > 0", lm1 > 0);

        if (isWindows())
          Thread.sleep(1000); // windows has a very low resolution
                    // sometimes

        IO.getFile("bin/a1/a/B.class").delete();
        classpath.remove("a/B.class");
        classpath.updateModified(System.currentTimeMillis(), "Removed file B");
        result = b.build();
        long lm2 = result.lastModified();
        assertTrue("Last modified date of bundle has increased after deleting class from package", lm2 > lm1);

        if (isWindows())
          Thread.sleep(1000); // windows has a very low resolution
                    // sometimes

        IO.getFile("bin/a1/a/A.class").delete();
        classpath.remove("a/A.class");
        classpath.updateModified(System.currentTimeMillis(), "Removed file A");

        if (isWindows())
          Thread.sleep(1000); // windows has a very low resolution
                    // sometimes

        result = b.build();
        long lm3 = result.lastModified();
        assertTrue("Last modified date of bundle has increased after deleting last class from package",
            lm3 > lm2);
      }
      finally {
        b.close();
      }
    }
    finally {
      try {
        IO.getFile("bin/a1/a/A.class").delete();
      }
      catch (Exception e) {}
      try {
        IO.getFile("bin/a1/a/B.class").delete();
      }
      catch (Exception e) {}
      try {
        IO.getFile("bin/a1/a").delete();
      }
      catch (Exception e) {}
      try {
        IO.getFile("bin/a1").delete();
      }
      catch (Exception e) {}
    }
  }

  private static boolean isWindows() {
    return File.separatorChar == '\\';
  }

  /**
   * https://github.com/bndtools/bnd/issues/315 Turns out bnd doesn't seem to
   * support a class in a capitalized package name. I accidentally called a
   * package with a capital letter and I get the strange error message and a
   * refusal to build it. (See title for error message) My package could be
   * named "Coffee" and the package named "CoffeeClient", The bnd.bnd file
   * could have: Private-Package: Coffee I'm running 2.0.0REL with Eclipse
   * Juno.
   */
  public static void testUpperCasePackage() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("bin"));
      b.setExportPackage("UPPERCASEPACKAGE");
      b.build();
      assertTrue(b.check());
      b.getExports().containsFQN("UPPERCASEPACKAGE");
    }
    finally {
      b.close();
    }
  }

  /**
   * Dave Smith <dave.smith@candata.com> I have pulled the latest from git and
   * am testing out 2.0 with our current application. I am getting the
   * following error message on the bnd.bnd file null, for cmd : classes,
   * arguments [classes;CONCRETE;ANNOTATION;javax.persistence.Entity] My bnd
   * file does have the following line ... Hibernate-Db =
   * ${classes;CONCRETE;ANNOTATION;javax.persistence.Entity}
   *
   * @throws Exception
   */

  public static void testClasses() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("x", "${classes;CONCRETE;ANNOTATION;aQute.bnd.annotation.component.Component}");
      b.setProperty("y", "${classes;CONCRETE;ANNOTATED;aQute.bnd.annotation.component.Component}");
      b.setProperty("z", "${classes;CONCRETE;ANNOTATEDX;x.y.Z}");
      b.setPrivatePackage("test");
      b.addClasspath(IO.getFile("bin"));
      b.build();
      String s = b.getProperty("x");
      assertEquals(s, b.getProperty("y"));
      assertTrue(s.contains("test.Target"));
      assertEquals("${classes;CONCRETE;ANNOTATEDX;x.y.Z}", b.getProperty("z"));
      assertTrue(b.check("ANNOTATEDX"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Check if we can create digests
   *
   * @throws Exception
   */

  public static void testDigests() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile(new File(""), "jar/osgi.jar"));
      b.setExportPackage("org.osgi.framework");
      b.setProperty(Constants.DIGESTS, "MD5, SHA1");
      Jar jar = b.build();
      assertTrue(b.check());
      File f = File.createTempFile("test", ".jar");
      jar.write(f);

      Jar other = new Jar(f);
      Manifest manifest = other.getManifest();
      assertNotNull(manifest);
      Attributes attrs = manifest.getAttributes("org/osgi/framework/BundleActivator.class");
      assertNotNull(attrs);
      assertEquals("RTRhr3kadnulINegRhpmog==", attrs.getValue("MD5-Digest"));
      assertEquals("BfVfpnE3Srx/0UWwtzNecrAGf8A=", attrs.getValue("SHA-Digest"));
      other.close();
    }
    finally {
      b.close();
    }
  }

  /**
   * FELIX-3407 Utterly confusing example that states that generic references
   * are not picked up. The classes under test are in {@link A},{@link B}, and
   * {@link C}.
   */
  public static void testGenericPickup() throws Exception {
    Builder b = new Builder();
    try {
      b.setPrivatePackage("test.genericinterf.a");
      b.addClasspath(new File("bin"));
      b.build();
      assertTrue(b.check());
      System.out.println(b.getImports());
      assertTrue(b.getImports().containsFQN("test.genericinterf.b"));
      assertTrue(b.getImports().containsFQN("test.genericinterf.c"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Github #130 Consider the following descriptor file: Bundle-Activator:
   * org.example.Activator Private-Package: org.example Now suppose that at
   * build time, bnd cannot find the package org.example, or it is empty. Bnd
   * sees the Bundle-Activator instruction as creating a dependency, so it
   * generates a manifest containing an import for that package:
   * Import-Package: org.example This is unexpected. If a Private-Package
   * instruction is given with a specific package name (i.e. not a wildcard),
   * and that package does not exist or is empty, then bnd should fail or
   * print an error.
   *
   * @throws Exception
   */
  public static void testPrivatePackageNonExistent() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.setBundleActivator("com.example.Activator");
      b.setPrivatePackage("com.example");
      b.setIncludeResource("p;literal='x'");

      b.build();
      assertTrue(b.check("on the class path: \\[com.example\\]",
          "Bundle-Activator com.example.Activator is being imported"));
    }
    finally {
      b.close();
    }
  }

  /**
   * #41 Test the EE macro
   */

  public static void testEEMacro() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/ifc112.jar"));
      b.setPrivatePackage("netscape.util.*");
      b.setBundleRequiredExecutionEnvironment("${ee}");
      Jar jar = b.build();
      assertTrue(b.check());

      Domain domain = Domain.domain(jar.getManifest());
      Parameters ee = domain.getBundleRequiredExecutionEnvironment();
      System.err.println(ee);
      assertTrue(ee.containsKey("JRE-1.1"));
    }
    finally {
      b.close();
    }
  }

  public static void testEEMacro2() throws Exception {
    String[] packages = {
        "eclipse_1_1", "eclipse_1_2", "eclipse_1_3", "eclipse_1_4", "eclipse_1_5", "eclipse_1_6",
        "eclipse_1_7", "eclipse_jsr14", "sun_1_8"
    };

    String[] ees = {
        "JRE-1.1", "J2SE-1.2", "J2SE-1.3", "J2SE-1.4", "J2SE-1.5", "JavaSE-1.6", "JavaSE-1.7", "J2SE-1.4",
        "JavaSE-1.8"
    };
    String[] versions = {
        "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.4", "1.8"
    };
    Pattern p = Pattern.compile("\\(&\\(osgi.ee=JavaSE\\)\\(version=(" + Version.VERSION_STRING + ")\\)\\)");
    for (int i = 0; i < packages.length; i++) {
      Builder b = new Builder();
      try {
        b.addClasspath(IO.getFile("compilerversions/compilerversions.jar"));
        b.setPrivatePackage(packages[i]);
        b.setBundleRequiredExecutionEnvironment("${ee}");
        Jar jar = b.build();
        assertTrue(b.check());
        Domain domain = Domain.domain(jar.getManifest());
        Parameters ee = domain.getBundleRequiredExecutionEnvironment();
        System.err.println(ee);
        assertEquals(ees[i], ee.toString());

        //
        // Check the requirements
        //
        Parameters een = domain.getRequireCapability();
        assertFalse(een.isEmpty());
        Attrs attrs = een.get("osgi.ee");
        String filter = attrs.get("filter:");
        Matcher m = p.matcher(filter);
        assertTrue(m.matches());
        assertEquals(versions[i], m.group(1));
      }
      finally {
        b.close();
      }
    }
  }

  /**
   * bnd issues Consider the following descriptor file:
   *
   * <pre>
   * Bundle-Activator: org.example.Activator
   * Private-Package: org.example
   * </pre>
   *
   * Now suppose that at build time, bnd cannot find the package org.example,
   * or it is empty. Bnd sees the Bundle-Activator instruction as creating a
   * dependency, so it generates a manifest containing an import for that
   * package:
   *
   * <pre>
   * Import-Package: org.example
   * </pre>
   *
   * This is unexpected. If a Private-Package instruction is given with a
   * specific package name (i.e. not a wildcard), and that package does not
   * exist or is empty, then bnd should fail or print an error.
   */

  public static void testReportEmptyPrivatePackage() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(new File("bin"));
      b.setPrivatePackage("does.not.exist");
      b.build();
      assertTrue(b.check("The JAR is empty", "Unused Private-Package instruction"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Test the name section
   */

  public static void testNamesection() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.setProperty(Constants.NAMESECTION,
          "org/osgi/service/event/*;MD5='${md5;${@}}';SHA1='${sha1;${@}}';MD5H='${md5;${@};hex}'");
      b.setProperty(Constants.PRIVATEPACKAGE, "org.osgi.service.event");
      Jar build = b.build();
      assertOk(b);
      build.calcChecksums(new String[] {
          "MD5", "SHA1"
      });
      assertTrue(b.check());
      Manifest m = build.getManifest();
      m.write(System.err);

      assertNotNull(m.getAttributes("org/osgi/service/event/EventAdmin.class").getValue("MD5"));
      assertNotNull(m.getAttributes("org/osgi/service/event/EventAdmin.class").getValue("SHA1"));
      assertEquals(m.getAttributes("org/osgi/service/event/EventAdmin.class").getValue("MD5-Digest"), m
          .getAttributes("org/osgi/service/event/EventAdmin.class").getValue("MD5"));
    }
    finally {
      b.close();
    }

  }

  /**
   * Test the digests
   */

  // public void testDigests() throws Exception {
  // Builder b = new Builder();
  // b.addClasspath(IO.getFile("jar/osgi.jar"));
  // b.setProperty(Constants.DIGESTS, "MD5, SHA1");
  // b.setProperty(Constants.PRIVATE_PACKAGE, "*");
  // Jar build = b.build();
  // assertOk(b);
  //
  // Manifest m = build.getManifest();
  // assertEquals(261, build.getResources().size());
  //
  // for (Entry<String,Resource> e : build.getResources().entrySet()) {
  // System.out.println("Path " + e.getKey());
  //
  // Attributes attrs = m.getAttributes(e.getKey());
  // assertNotNull(e.getKey(), attrs);
  // boolean md5 = false, sha1 = false;
  //
  // for (Entry<Object,Object> ee : attrs.entrySet()) {
  // String name = ee.getKey().toString().toLowerCase();
  // if (name.endsWith("-digest")) {
  // String value = ee.getValue().toString().trim();
  // assertNotNull("original digest", value);
  //
  // byte[] original = Base64.decodeBase64(value);
  // assertNotNull("original digest", original);
  //
  // String alg = name.substring(0, name.length() - 7);
  // if (alg.equals("md5"))
  // md5 = true;
  // if (alg.equals("sha1"))
  // sha1 = true;
  //
  // MessageDigest md = MessageDigest.getInstance(alg);
  // InputStream in = e.getValue().openInputStream();
  // byte[] buffer = new byte[8000];
  // int size = in.read(buffer);
  // while (size > 0) {
  // md.update(buffer, 0, size);
  // size = in.read(buffer);
  // }
  // byte calculated[] = md.digest();
  // assertTrue("comparing digests " + e.getKey() + " " + value + " " +
  // Base64.encodeBase64(calculated),
  // Arrays.equals(original, calculated));
  // }
  // }
  // assertTrue("expected md5", md5);
  // assertTrue("expected sha1", sha1);
  // }
  // }

  /**
   * Check of the use of x- directives are not skipped. bnd allows x-
   * directives in the import/export clauses but strips other ones.
   *
   * @throws Exception
   */
  public static void testXDirectives() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.setProperty("Export-Package", "org.osgi.framework;x-foo:=true;bar:=false");
      Jar jar = b.build();
      assertTrue(b.check("bar:"));
      Manifest m = jar.getManifest();
      String s = m.getMainAttributes().getValue("Export-Package");
      assertTrue(s.contains("x-foo:"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Check of SNAPSHOT is replaced with the -snapshot instr
   *
   * @throws Exception
   */
  public static void testSnapshot() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("-resourceonly", "true");
      b.setProperty("-snapshot", "TIMESTAMP");
      b.setProperty("Bundle-Version", "1.0-SNAPSHOT");
      Jar jar = b.build();
      assertTrue(b.check("The JAR is empty"));
      Manifest m = jar.getManifest();
      assertEquals("1.0.0.TIMESTAMP", m.getMainAttributes().getValue("Bundle-Version"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Check if do not copy works on files
   */

  public static void testDoNotCopy() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("-resourceonly", "true");
      b.setProperty("-donotcopy", ".*\\.jar|\\..*");
      b.setProperty("Include-Resource", "jar");
      b.build();
      assertTrue(b.check());

      Set<String> names = b.getJar().getResources().keySet();
      assertEquals(11, names.size());
      assertTrue(names.contains("AnnotationWithJSR14.jclass"));
      assertTrue(names.contains("mandatorynoversion.bnd"));
      assertTrue(names.contains("mina.bar"));
      assertTrue(names.contains("minax.bnd"));
      assertTrue(names.contains("rox.bnd"));
      assertTrue(names.contains("WithAnnotations.jclass"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Check if do not copy works on files
   */

  public static void testDoNotCopyDS() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("-resourceonly", "true");
      b.setProperty("Include-Resource", "jar/");
      b.build();
      assertTrue(b.check());

      Set<String> names = b.getJar().getResources().keySet();
      assertFalse(names.contains(".DS_Store"));
    }
    finally {
      b.close();
    }
  }

  /**
   * No error is generated when a file is not found.
   */

  public static void testFileNotFound() throws Exception {
    Builder b = new Builder();
    try {
      b.setPedantic(true);
      b.setProperty("-classpath", "xyz.jar");
      b.setProperty("Include-Resource", "lib=lib, jar/osgi.jar");
      b.setProperty("-resourceonly", "true");
      b.build();
      assertTrue(b.check("Input file does not exist: lib", "Cannot find entry on -classpath: xyz.jar"));
    }
    finally {
      b.close();
    }
  }

  /**
   * bnd seems to pick the wrong version if a packageinfo is available
   * multiple times.
   *
   * @throws Exception
   */

  public static void testMultiplePackageInfo() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(IO.getFile("jar/osgi.core.jar"));
      b.setProperty(Constants.PRIVATEPACKAGE, "org.osgi.service.packageadmin;-split-package:=first");
      b.build();
      assertTrue(b.check());
      String version = b.getImports().getByFQN("org.osgi.framework").get(Constants.VERSION_ATTRIBUTE);
      assertEquals("[1.3,2)", version);
    }
    finally {
      b.close();
    }
  }

  /**
   * Test the from: directive on expanding packages.
   */
  public static void testFromOSGiDirective() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(IO.getFile("jar/org.eclipse.osgi-3.5.0.jar"));
      b.setProperty("Export-Package", "org.osgi.framework;from:=osgi");
      b.build();
      assertTrue(b.check());

      assertEquals("1.3", b.getExports().getByFQN("org.osgi.framework").get("version"));
    }
    finally {
      b.close();
    }

  }

  public static void testFromEclipseDirective() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(IO.getFile("jar/org.eclipse.osgi-3.5.0.jar"));
      b.setProperty("Export-Package", "org.osgi.framework;from:=org.eclipse.osgi-3.5.0");
      b.build();
      assertTrue(b.check());

      assertEquals("1.3", b.getExports().getByFQN("org.osgi.framework").get("version"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Test the provide package
   */
  public static void testProvidedVersion() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(new File("bin"));
      b.setProperty(Constants.EXPORT_PACKAGE, "org.osgi.service.event;provide:=true");
      b.setProperty("Private-Package", "test.refer");
      Jar jar = b.build();
      assertTrue(b.check());
      String ip = jar.getManifest().getMainAttributes().getValue(Constants.IMPORT_PACKAGE);
      Parameters map = Processor.parseHeader(ip, null);
      assertEquals("[1.0,1.1)", map.get("org.osgi.service.event").get("version"));
    }
    finally {
      b.close();
    }
  }

  public static void testUnProvidedVersion() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(new File("bin"));
      b.setProperty(Constants.EXPORT_PACKAGE, "org.osgi.service.event;provide:=false");
      b.setProperty("Private-Package", "test.refer");
      Jar jar = b.build();
      assertTrue(b.check());
      String ip = jar.getManifest().getMainAttributes().getValue(Constants.IMPORT_PACKAGE);
      Parameters map = Processor.parseHeader(ip, null);
      assertEquals("[1.0,2)", map.get("org.osgi.service.event").get("version"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Complaint that exported versions were not picked up from external bundle.
   */

  public static void testExportedVersionsNotPickedUp() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/jsr311-api-1.1.1.jar"));
      b.setProperty("Export-Package", "javax.ws.rs.core");
      Jar jar = b.build();
      assertTrue(b.check());
      String ip = jar.getManifest().getMainAttributes().getValue(Constants.EXPORT_PACKAGE);
      Parameters map = Processor.parseHeader(ip, null);
      assertEquals("1.1.1", map.get("javax.ws.rs.core").get("version"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Test where the version comes from: Manifest or packageinfo
   *
   * @throws Exception
   */
  public static void testExportVersionSource() throws Exception {
    Manifest manifest = new Manifest();
    manifest.getMainAttributes().putValue("Export-Package", "org.osgi.service.event;version=100");

    // Remove packageinfo
    Jar manifestOnly = new Jar(IO.getFile("jar/osgi.jar"));
    try {
      manifestOnly.remove("org/osgi/service/event/packageinfo");
      manifestOnly.setManifest(manifest);

      // Remove manifest
      Jar packageInfoOnly = new Jar(IO.getFile("jar/osgi.jar"));
      packageInfoOnly.setManifest(new Manifest());

      Jar both = new Jar(IO.getFile("jar/osgi.jar"));
      both.setManifest(manifest);

      // Only version in manifest
      Builder bms = new Builder();
      try {
        bms.addClasspath(manifestOnly);
        bms.setProperty("Export-Package", "org.osgi.service.event");
        bms.build();
        assertTrue(bms.check());

        String s = bms.getExports().getByFQN("org.osgi.service.event").get("version");
        assertEquals("100", s);

        // Only version in packageinfo
        Builder bpinfos = new Builder();
        bpinfos.addClasspath(packageInfoOnly);
        bpinfos.setProperty("Export-Package", "org.osgi.service.event");
        bpinfos.build();
        assertTrue(bpinfos.check());

        s = bpinfos.getExports().getByFQN("org.osgi.service.event").get("version");
        assertEquals("1.0.1", s);
      }
      finally {
        bms.close();
      }
    }
    finally {
      manifestOnly.close();
    }

  }

  /**
   * Test where the version comes from: Manifest or packageinfo
   *
   * @throws Exception
   */
  public static void testImportVersionSource() throws Exception {
    Jar fromManifest = new Jar("manifestsource");
    Jar fromPackageInfo = new Jar("packageinfosource");
    Jar fromBoth = new Jar("both");
    try {
      Manifest mms = new Manifest();
      mms.getMainAttributes().putValue("Export-Package", "org.osgi.service.event; version=100");
      fromManifest.setManifest(mms);

      fromPackageInfo.putResource("org/osgi/service/event/packageinfo",
          new EmbeddedResource("version 99".getBytes(), 0));

      Manifest mboth = new Manifest();
      mboth.getMainAttributes().putValue("Export-Package", "org.osgi.service.event; version=101");
      fromBoth.putResource("org/osgi/service/event/packageinfo",
          new EmbeddedResource("version 199".getBytes(), 0));
      fromBoth.setManifest(mboth);

      // Only version in manifest
      Builder bms = new Builder();
      try {
        bms.addClasspath(fromManifest);
        bms.setProperty("Import-Package", "org.osgi.service.event");
        bms.build();
        assertTrue(bms.check("The JAR is empty"));
        String s = bms.getImports().getByFQN("org.osgi.service.event").get("version");
        assertEquals("[100.0,101)", s);
        // Only version in packageinfo
        Builder bpinfos = new Builder();
        try {
          bpinfos.addClasspath(fromPackageInfo);
          bpinfos.setProperty("Import-Package", "org.osgi.service.event");
          bpinfos.build();
          assertTrue(bms.check());
          s = bpinfos.getImports().getByFQN("org.osgi.service.event").get("version");
          assertEquals("[99.0,100)", s);

          // Version in manifest + packageinfo
          Builder bboth = new Builder();
          try {
            bboth.addClasspath(fromBoth);
            bboth.setProperty("Import-Package", "org.osgi.service.event");
            bboth.build();
            assertTrue(bms.check());
            s = bboth.getImports().getByFQN("org.osgi.service.event").get("version");
            assertEquals("[101.0,102)", s);
          }
          finally {
            bboth.close();
          }
        }
        finally {
          bpinfos.close();
        }
      }
      finally {
        bms.close();
      }

    }
    finally {
      fromManifest.close();
      fromPackageInfo.close();
      fromBoth.close();
    }
  }

  public static void testNoImportDirective() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("Export-Package", "org.osgi.util.measurement, org.osgi.service.http;-noimport:=true");
      b.setProperty("Private-Package", "org.osgi.framework, test.refer");
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(new File("bin"));
      Jar jar = b.build();
      assertTrue(b.check());

      Manifest m = jar.getManifest();
      String imports = m.getMainAttributes().getValue("Import-Package");
      assertTrue(imports.contains("org.osgi.util.measurement")); // referred
                                    // to
                                    // but
                                    // no
                                    // private
                                    // references
                                    // (does
                                    // not
                                    // use
                                    // fw).
      assertFalse(imports.contains("org.osgi.service.http")); // referred
                                  // to
                                  // but no
                                  // private
                                  // references
                                  // (does not
                                  // use
                                  // fw).
    }
    finally {
      b.close();
    }

  }

  public static void testNoImportDirective2() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("Export-Package", "org.osgi.util.measurement;-noimport:=true, org.osgi.service.http");
      b.setProperty("Private-Package", "org.osgi.framework, test.refer");
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(new File("bin"));
      Jar jar = b.build();
      assertTrue(b.check());

      Manifest m = jar.getManifest();
      String imports = m.getMainAttributes().getValue("Import-Package");
      assertFalse(imports.contains("org.osgi.util.measurement")); // referred
                                    // to
                                    // but
                                    // no
                                    // private
                                    // references
                                    // (does
                                    // not
                                    // use
                                    // fw).
      assertTrue(imports.contains("org.osgi.service.http")); // referred
                                  // to
                                  // but no
                                  // private
                                  // references
                                  // (does not
                                  // use
                                  // fw).

    }
    finally {
      b.close();
    }
  }

  public static void testAutoNoImport() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty(
          "Export-Package",
          "org.osgi.service.event, org.osgi.service.packageadmin, org.osgi.util.measurement, org.osgi.service.http;-noimport:=true");
      b.setProperty("Private-Package", "org.osgi.framework, test.refer");
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(new File("bin"));
      Jar jar = b.build();
      assertTrue(b.check("has 1,  private references"));

      Manifest m = jar.getManifest();
      String imports = m.getMainAttributes().getValue("Import-Package");
      assertFalse(imports.contains("org.osgi.service.packageadmin")); // no
                                      // internal
                                      // references
      assertFalse(imports.contains("org.osgi.util.event")); // refers to
                                  // private
                                  // framework
      assertTrue(imports.contains("org.osgi.util.measurement")); // referred
                                    // to
                                    // but
                                    // no
                                    // private
                                    // references
                                    // (does
                                    // not
                                    // use
                                    // fw).
      assertFalse(imports.contains("org.osgi.service.http")); // referred
                                  // to
                                  // but no
                                  // private
                                  // references
                                  // (does not
                                  // use
                                  // fw).
    }
    finally {
      b.close();
    }
  }

  public static void testSimpleWab() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("-wab", "");
      b.setProperty("Private-Package", "org.osgi.service.event");
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      Jar jar = b.build();
      assertTrue(b.check());

      Manifest m = jar.getManifest();
      m.write(System.err);
      assertNotNull(b.getImports().getByFQN("org.osgi.framework"));
    }
    finally {
      b.close();
    }

  }

  public static void testWab() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("-wablib", "jar/asm.jar, jar/easymock.jar");
      b.setProperty("-wab", "jar/osgi.jar");
      b.setProperty("-includeresource", "OSGI-INF/xml/x.xml;literal=\"text\"");
      b.setProperty("Private-Package", "org.osgi.framework");
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      Jar jar = b.build();
      assertTrue(b.check());

      Manifest m = jar.getManifest();
      assertNotNull(m);
      assertEquals("WEB-INF/classes,WEB-INF/lib/asm.jar,WEB-INF/lib/easymock.jar", m.getMainAttributes()
          .getValue("Bundle-ClassPath"));
      assertNotNull(jar.getResource("WEB-INF/lib/asm.jar"));
      assertNotNull(jar.getResource("WEB-INF/classes/org/osgi/framework/BundleContext.class"));
      assertNotNull(jar.getResource("osgi.jar"));
      assertNotNull(jar.getResource("OSGI-INF/xml/x.xml"));
    }
    finally {
      b.close();
    }
  }

  public static void testRemoveHeaders() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("Private-Package", "org.osgi.framework");
      b.setProperty("T1", "1");
      b.setProperty("T2", "1");
      b.setProperty("T1_2", "1");
      b.setProperty("-removeheaders", "!T1_2,T1*");
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      Jar jar = b.build();
      assertTrue(b.check());

      Manifest m = jar.getManifest();
      assertNotNull(m);
      assertEquals("1", m.getMainAttributes().getValue("T2"));
      assertEquals("1", m.getMainAttributes().getValue("T1_2"));
      assertEquals(null, m.getMainAttributes().getValue("T1"));
    }
    finally {
      b.close();
    }
  }

  public static void testNoManifest() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("-nomanifest", "true");
      b.setProperty(Constants.BUNDLE_CLASSPATH, "WEB-INF/classes");
      b.setProperty("Include-Resource", "WEB-INF/classes=@jar/asm.jar");
      Jar jar = b.build();
      assertTrue(b.check());

      File f = new File("tmp.jar");
      f.deleteOnExit();
      jar.write(f);

      JarInputStream jin = new JarInputStream(new FileInputStream(f));
      Manifest m = jin.getManifest();
      assertNull(m);
    }
    finally {
      b.close();
    }
  }

  public static void testClassesonNoBCP() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("-resourceonly", "true");
      b.setProperty("Include-Resource", "WEB-INF/classes=@jar/asm.jar");
      b.setProperty("-nomanifest", "true");
      b.build();
      assertTrue(b.check("Classes found in the wrong directory"));
    }
    finally {
      b.close();
    }
  }

  public static void testClassesonBCP() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("-resourceonly", "true");
      b.setProperty("Include-Resource", "WEB-INF/classes=@jar/asm.jar");
      b.setProperty("Bundle-ClassPath", "WEB-INF/classes");
      b.build();
      assertTrue(b.check());
    }
    finally {
      b.close();
    }
  }

  /**
   * #196 StringIndexOutOfBoundsException in Builder.getClasspathEntrySuffix
   * If a class path entry was changed the isInScope threw an exception
   * because it assumed all cpes were directories.
   *
   * @throws Exception
   */
  public static void testInScopeClasspathEntry() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("Export-Package", "aQute.bnd.*");
      b.addClasspath(new File("bin"));
      b.addClasspath(IO.getFile("jar/osgi.jar"));

      List<File> project = Arrays.asList(b.getFile("bin/aQute/bnd/build/Project.class"));
      assertTrue(b.isInScope(project));
      List<File> cpe = Arrays.asList(b.getFile("jar/osgi.jar"));
      assertTrue(b.isInScope(cpe));
    }
    finally {
      b.close();
    }
  }

  public static void testInScopeExport() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("Export-Package", "aQute.bnd.*");
      b.addClasspath(new File("bin"));
      List<File> project = Arrays.asList(b.getFile("bin/aQute/bnd/build/Project.class"));
      assertTrue(b.isInScope(project));
      List<File> nonexistent = Arrays.asList(b.getFile("bin/aQute/bnd/build/Abc.xyz"));
      assertTrue(b.isInScope(nonexistent));
      List<File> outside = Arrays.asList(b.getFile("bin/test/AnalyzerTest.class"));
      assertFalse(b.isInScope(outside));
    }
    finally {
      b.close();
    }
  }

  public static void testInScopePrivate() throws Exception {
    Builder b = new Builder();
    b.setProperty("Private-Package", "!aQute.bnd.build,aQute.bnd.*");
    b.addClasspath(new File("bin"));
    List<File> project = Arrays.asList(b.getFile("bin/aQute/bnd/build/Project.class"));
    assertFalse(b.isInScope(project));
    List<File> nonexistent = Arrays.asList(b.getFile("bin/aQute/bnd/acb/Def.xyz"));
    assertTrue(b.isInScope(nonexistent));
    List<File> outside = Arrays.asList(b.getFile("bin/test/AnalyzerTest.class"));
    assertFalse(b.isInScope(outside));
  }

  public static void testInScopeResources() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("Include-Resource",
          "@a.jar/!xya.txt,{@b.jar/!xya.txt}, -@c.jar/!xya.txt, dir, x=dirb, {-x=dirc}");
      assertFalse(b.isInScope(Arrays.asList(b.getFile("x.jar"))));
      assertTrue(b.isInScope(Arrays.asList(b.getFile("a.jar"))));
      assertTrue(b.isInScope(Arrays.asList(b.getFile("b.jar"))));
      assertTrue(b.isInScope(Arrays.asList(b.getFile("dir/a.jar"))));
      assertTrue(b.isInScope(Arrays.asList(b.getFile("dir/x.jar"))));
      assertTrue(b.isInScope(Arrays.asList(b.getFile("dir/x.jar"))));
      assertTrue(b.isInScope(Arrays.asList(b.getFile("dirb/x.jar"))));
      assertTrue(b.isInScope(Arrays.asList(b.getFile("dirb/x.jar"))));
      assertTrue(b.isInScope(Arrays.asList(b.getFile("dirc/x.jar"))));
    }
    finally {
      b.close();
    }
  }

  public static void testExtra() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("Include-Resource",
          "jar/osgi.jar;extra=itworks, www/xyz.jar=jar/osgi.jar;extra='italsoworks'");
      b.setProperty("-resourceonly", "true");
      Jar jar = b.build();
      assertTrue(b.check());

      Resource r = jar.getResource("osgi.jar");
      assertNotNull(r);
      assertEquals("itworks", r.getExtra());
      Resource r2 = jar.getResource("www/xyz.jar");
      assertNotNull(r2);
      assertEquals("italsoworks", r2.getExtra());
    }
    finally {
      b.close();
    }
  }

  /**
   * Got a split package warning during verify when private overlaps with
   * export
   */
  public static void testSplitWhenPrivateOverlapsExport() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.setProperty("Private-Package", "org.osgi.service.*");
      b.setProperty("Export-Package", "org.osgi.service.event");
      b.build();
      assertTrue(b.check());
    }
    finally {
      b.close();
    }
  }

  /**
   * This test checks if
   *
   * @throws Exception
   */

  public static void testMacroBasedExpansion() throws Exception {
    Processor proc = new Processor();

    Builder builder = new Builder(proc);
    try {
      builder.setProperty("Export-Package", "${spec.packages}");
      proc.setProperty("spec.packages", "${core.packages}, ${cmpn.packages}, ${mobile.packages}");
      proc.setProperty("core.specs", "org.osgi.service.packageadmin, org.osgi.service.permissionadmin");
      proc.setProperty("core.packages", "${replace;${core.specs};.+;$0.*}");
      proc.setProperty("cmpn.specs", "org.osgi.service.event, org.osgi.service.cu");
      proc.setProperty("cmpn.packages", "${replace;${cmpn.specs};.+;$0.*}");
      proc.setProperty("mobile.specs", "org.osgi.service.wireadmin, org.osgi.service.log, org.osgi.service.cu");
      proc.setProperty("mobile.packages", "${replace;${mobile.specs};.+;$0.*}");
      builder.addClasspath(IO.getFile("jar/osgi.jar"));

      Jar jar = builder.build();
      // The total set is not uniqued so we're having an unused pattern
      // this could be solved with ${uniq;${spec.packages}} but this is
      // just
      // another test
      assertTrue(builder.check("Unused Export-Package instructions: \\[org.osgi.service.cu.\\*~\\]"));
      Domain domain = Domain.domain(jar.getManifest());

      Parameters h = domain.getExportPackage();
      assertTrue(h.containsKey("org.osgi.service.cu"));
      assertTrue(h.containsKey("org.osgi.service.cu.admin"));
    }
    finally {
      builder.close();
      proc.close();
    }
  }

  /**
   * Make resolution dependent on the fact that a package is on the classpath
   * or not
   */

  public static void testConditionalResolution() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty("res", "${if;${exporters;${@package}};mandatory;optional}");
      b.setProperty("Import-Package", "*;resolution:=\\${res}");
      b.setProperty("Export-Package", "org.osgi.service.io, org.osgi.service.log");
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.build();
      assertTrue(b.check());

      Map<String,String> ioimports = b.getImports().getByFQN("javax.microedition.io");
      Map<String,String> fwimports = b.getImports().getByFQN("org.osgi.framework");

      assertNotNull(ioimports);
      assertNotNull(fwimports);
      assertTrue(ioimports.containsKey("resolution:"));
      assertTrue(fwimports.containsKey("resolution:"));
      assertEquals("optional", ioimports.get("resolution:"));
      assertEquals("mandatory", fwimports.get("resolution:"));
    }
    finally {
      b.close();
    }

  }

  /**
   * Test private imports. We first build a jar with a import:=private packge.
   * Then place it
   *
   * @throws Exception
   */

  public static void testClassnames() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.addClasspath(IO.getFile("jar/ds.jar"));
      b.addClasspath(IO.getFile("jar/ifc112.jar"));
      b.setProperty("Export-Package", "*");
      b.setProperty("C1", "${classes;implementing;org.osgi.service.component.*}");
      b.setProperty("C2", "${classes;extending;org.xml.sax.helpers.*}");
      b.setProperty("C3", "${classes;importing;org.xml.sax}");
      b.setProperty("C4", "${classes;named;*Parser*}");
      b.setProperty("C5", "${classes;named;*Parser*;version;45.*}");
      Jar jar = b.build();
      assertTrue(b.check());

      Manifest m = jar.getManifest();
      m.write(System.err);
      Attributes main = m.getMainAttributes();
      assertList(
          asl("org.eclipse.equinox.ds.service.ComponentContextImpl,org.eclipse.equinox.ds.service.ComponentFactoryImpl,org.eclipse.equinox.ds.service.ComponentInstanceImpl"),
          asl(main.getValue("C1")));
      assertList(asl("org.eclipse.equinox.ds.parser.ElementHandler, "
          + "org.eclipse.equinox.ds.parser.IgnoredElement,"
          + "org.eclipse.equinox.ds.parser.ImplementationElement,"
          + "org.eclipse.equinox.ds.parser.ParserHandler, "
          + "org.eclipse.equinox.ds.parser.PropertiesElement,"
          + "org.eclipse.equinox.ds.parser.PropertyElement, "
          + "org.eclipse.equinox.ds.parser.ProvideElement, "
          + "org.eclipse.equinox.ds.parser.ReferenceElement, "
          + "org.eclipse.equinox.ds.parser.ServiceElement,"
          + "org.eclipse.equinox.ds.parser.ComponentElement"), asl(main.getValue("C2")));
      assertList(
          asl("org.eclipse.equinox.ds.parser.ComponentElement,org.eclipse.equinox.ds.parser.ElementHandler,org.eclipse.equinox.ds.parser.IgnoredElement,org.eclipse.equinox.ds.parser.ImplementationElement,org.eclipse.equinox.ds.parser.Parser,org.eclipse.equinox.ds.parser.ParserHandler,org.eclipse.equinox.ds.parser.PropertiesElement,org.eclipse.equinox.ds.parser.PropertyElement,org.eclipse.equinox.ds.parser.ProvideElement,org.eclipse.equinox.ds.parser.ReferenceElement,org.eclipse.equinox.ds.parser.ServiceElement"),
          asl(main.getValue("C3")));
      assertList(
          asl("org.eclipse.equinox.ds.parser.XMLParserNotAvailableException,org.eclipse.equinox.ds.parser.Parser,org.eclipse.equinox.ds.parser.ParserHandler,netscape.application.HTMLParser,org.eclipse.equinox.ds.parser.ParserConstants,org.osgi.util.xml.XMLParserActivator"),
          asl(main.getValue("C4")));
      assertEquals("netscape.application.HTMLParser", main.getValue("C5"));
    }
    finally {
      b.close();
    }
  }

  static void assertList(Collection<String> a, Collection<String> b) {
    List<String> onlyInA = new ArrayList<String>();
    onlyInA.addAll(a);
    onlyInA.removeAll(b);

    List<String> onlyInB = new ArrayList<String>();
    onlyInB.addAll(b);
    onlyInB.removeAll(a);

    if (onlyInA.isEmpty() && onlyInB.isEmpty())
      return;

    fail("Lists are not equal, only in A: " + onlyInA + ",\n   and only in B: " + onlyInB);
  }

  static Collection<String> asl(String s) {
    return new TreeSet<String>(Processor.split(s));
  }

  public static void testImportMicroNotTruncated() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.setProperty("Import-Package", "org.osgi.service.event;version=${@}");
      b.build();
      assertTrue(b.check("The JAR is empty"));
      String s = b.getImports().getByFQN("org.osgi.service.event").get("version");
      assertEquals("1.0.1", s);
    }
    finally {
      b.close();
    }
  }

  public static void testImportMicroTruncated() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/osgi.jar"));
      b.setProperty("Import-Package", "org.osgi.service.event");
      b.build();
      assertTrue(b.check("The JAR is empty"));

      String s = b.getImports().getByFQN("org.osgi.service.event").get("version");
      assertEquals("[1.0,2)", s);
    }
    finally {
      b.close();
    }

  }

  public static void testMultipleExport2() throws Exception {
    File cp[] = {
      IO.getFile("jar/asm.jar")
    };
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.setProperty("Export-Package",
          "org.objectweb.asm;version=1.1, org.objectweb.asm;version=1.2, org.objectweb.asm;version=2.3");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      jar.getManifest().write(System.err);
      Manifest m = jar.getManifest();
      m.write(System.err);
      String ip = m.getMainAttributes().getValue("Export-Package");
      assertTrue(ip.indexOf("org.objectweb.asm;version=\"1.1\"") >= 0);
      assertTrue(ip.indexOf("org.objectweb.asm;version=\"1.2\"") >= 0);
      assertTrue(ip.indexOf("org.objectweb.asm;version=\"2.3\"") >= 0);
    }
    finally {
      bmaker.close();
    }
  }

  public static void testBsnAssignmentNoFile() throws Exception {
    Properties p = new Properties();
    p.setProperty("Private-Package", "org.objectweb.asm");
    Attributes m = setup(p, null).getMainAttributes();

    // We use properties so the default BSN is then the project name
    // because that is the base directory
    assertEquals(m.getValue("Bundle-SymbolicName"), "biz.aQute.bndlib.tests");

    // The file name for the properties is not bnd.bnd, so the
    // name of the properties file is the default bsn
    m = setup(null, IO.getFile("src/test/com.acme/defaultbsn.bnd")).getMainAttributes();
    assertEquals("com.acme.defaultbsn", m.getValue("Bundle-SymbolicName"));

    // If the file is called bnd.bnd, then we take the parent directory
    m = setup(null, IO.getFile("src/test/com.acme/bnd.bnd")).getMainAttributes();
    assertEquals("com.acme", m.getValue("Bundle-SymbolicName"));

    // If the file is called bnd.bnd, then we take the parent directory
    m = setup(null, IO.getFile("src/test/com.acme/setsbsn.bnd")).getMainAttributes();
    assertEquals("is.a.set.bsn", m.getValue("Bundle-SymbolicName"));

    // This sets the bsn, se we should see it back
    p.setProperty("Bundle-SymbolicName", "this.is.my.test");
    m = setup(p, null).getMainAttributes();
    assertEquals(m.getValue("Bundle-SymbolicName"), "this.is.my.test");
  }

  public static Manifest setup(Properties p, File f) throws Exception {
    File cp[] = {
      IO.getFile("jar/asm.jar")
    };
    Builder bmaker = new Builder();
    if (f != null)
      bmaker.setProperties(f);
    else
      bmaker.setProperties(p);
    bmaker.setClasspath(cp);
    Jar jar = bmaker.build();
    assertTrue(bmaker.check());
    Manifest m = jar.getManifest();
    return m;
  }

  public static void testDuplicateExport() throws Exception {
    File cp[] = {
      IO.getFile("jar/asm.jar")
    };
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.setProperty("Import-Package", "*");
      p.setProperty("Export-Package", "org.*;version=1.2,org.objectweb.asm;version=1.3");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      Manifest m = jar.getManifest();
      m.write(System.err);
      String ip = m.getMainAttributes().getValue("Export-Package");
      assertTrue(ip.indexOf("org.objectweb.asm;version=\"1.2\"") >= 0);
    }
    finally {
      bmaker.close();
    }
  }

  public static void testNoExport() throws Exception {
    File cp[] = {
      IO.getFile("jar/asm.jar")
    };
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.setProperty("Import-Package", "*");
      p.setProperty("Export-Package", "org.*'");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      jar.getManifest().write(System.err);
      Manifest m = jar.getManifest();
      String ip = m.getMainAttributes().getValue("Export-Package");
      assertTrue(ip.indexOf("org.objectweb.asm") >= 0);
    }
    finally {
      bmaker.close();
    }
  }

  public static void testHardcodedImport() throws Exception {
    File cp[] = {
      IO.getFile("jar/asm.jar")
    };
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.setProperty("Import-Package", "whatever,*");
      p.setProperty("Export-Package", "org.*");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      Manifest m = jar.getManifest();
      String ip = m.getMainAttributes().getValue("Import-Package");
      assertTrue(ip.indexOf("whatever") >= 0);
    }
    finally {
      bmaker.close();
    }
  }

  public static void testCopyDirectory() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.setProperty("-resourceonly", "true");
      p.setProperty("Include-Resource", "bnd=bnd");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      Map<String,Resource> map = jar.getDirectories().get("bnd");
      assertNotNull(map);
      assertEquals(2, map.size());
    }
    finally {
      bmaker.close();
    }
  }

  /**
   * There is an error that gives a split package when you export a package
   * that is also private I think.
   *
   * @throws Exception
   */
  public static void testSplitOnExportAndPrivate() throws Exception {
    File cp[] = {
      IO.getFile("jar/asm.jar")
    };
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.setProperty("Export-Package", "org.objectweb.asm.signature");
      p.setProperty("Private-Package", "org.objectweb.asm");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      bmaker.build();
      assertTrue(bmaker.check());
    }
    finally {
      bmaker.close();
    }
  }

  public static void testConduit() throws Exception {
    Properties p = new Properties();
    p.setProperty("-conduit", "jar/asm.jar");
    Builder b = new Builder();
    try {
      b.setProperties(p);
      Jar jars[] = b.builds();
      assertTrue(b.check());
      assertNotNull(jars);
      assertEquals(1, jars.length);
      assertEquals("ASM", jars[0].getManifest().getMainAttributes().getValue("Implementation-Title"));
    }
    finally {
      b.close();
    }
  }

  /**
   * Export a package that was loaded with resources
   *
   * @throws Exception
   */
  public static void testExportSyntheticPackage() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.setProperty("-resourceonly", "true");
      p.setProperty("Include-Resource", "resources=jar");
      p.setProperty("-exportcontents", "resources");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      Manifest manifest = jar.getManifest();
      String header = manifest.getMainAttributes().getValue("Export-Package");
      System.err.println(header);
      assertTrue(header.indexOf("resources") >= 0);
    }
    finally {
      bmaker.close();
    }
  }

  /**
   * Exporting packages in META-INF
   *
   * @throws Exception
   */
  public static void testMETAINF() throws Exception {
    File cp[] = {
        new File("src"), IO.getFile("jar/asm.jar")
    };
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.setProperty("Include-Resource", "META-INF/xyz/asm.jar=jar/asm.jar");
      p.setProperty("Export-Package", "META-INF/xyz, org.*");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check("Invalid package name: 'META-INF"));

      jar.getManifest().write(System.err);
      Manifest manifest = jar.getManifest();
      String header = manifest.getMainAttributes().getValue("Export-Package");
      assertTrue(header.indexOf("META-INF.xyz") >= 0);
    }
    finally {
      bmaker.close();
    }
  }

  /**
   * Bnd cleans up versions if they do not follow the OSGi rule. Check a
   * number of those versions.
   *
   * @throws Exception
   */
  public static void testVersionCleanup() throws Exception {
    assertVersion("1.201209072340200", "1.0.0.201209072340200");
    assertVersion("000001.0003.00000-SNAPSHOT", "1.3.0.SNAPSHOT");
    assertVersion("000000.0000.00000-SNAPSHOT", "0.0.0.SNAPSHOT");
    assertVersion("0-SNAPSHOT", "0.0.0.SNAPSHOT");
    assertVersion("1.3.0.0-0-01-0-SNAPSHOT", "1.3.0.0-0-01-0-SNAPSHOT");
    assertVersion("1.3.0.0-0-01-0", "1.3.0.0-0-01-0");
    assertVersion("0.9.0.1.2.3.4.5-incubator-SNAPSHOT", "0.9.0.incubator-SNAPSHOT");
    assertVersion("0.4aug123", "0.0.0.4aug123");
    assertVersion("0.9.4aug123", "0.9.0.4aug123");
    assertVersion("0.9.0.4aug123", "0.9.0.4aug123");

    assertVersion("1.2.3", "1.2.3");
    assertVersion("1.2.3-123", "1.2.3.123");
    assertVersion("1.2.3.123", "1.2.3.123");
    assertVersion("1.2.3.123x", "1.2.3.123x");
    assertVersion("1.123x", "1.0.0.123x");

    assertVersion("0.9.0.4.3.2.1.0.4aug123", "0.9.0.4aug123");
    assertVersion("0.9.0.4aug123", "0.9.0.4aug123");

    assertVersion("0.9.0.4.3.4.5.6.6", "0.9.0.6");

    assertVersion("0.9.0-incubator-SNAPSHOT", "0.9.0.incubator-SNAPSHOT");
    assertVersion("1.2.3.x", "1.2.3.x");
    assertVersion("1.2.3", "1.2.3");
    assertVersion("1.2", "1.2");
    assertVersion("1", "1");
    assertVersion("1.2.x", "1.2.0.x");
    assertVersion("1.x", "1.0.0.x");
    assertVersion("1.2.3-x", "1.2.3.x");
    assertVersion("1.2:x", "1.2.0.x");
    assertVersion("1.2-snapshot", "1.2.0.snapshot");
    assertVersion("1#x", "1.0.0.x");
    assertVersion("1.&^%$#date2007/03/04", "1.0.0.date20070304");
  }

  static void assertVersion(String input, String expected) {
    assertEquals(expected, Builder.cleanupVersion(input));
  }

  /**
   * -exportcontents provides a header that is only relevant in the analyze
   * phase, it augments the Export-Package header.
   */

  public static void testExportContents() throws Exception {
    Builder builder = new Builder();
    try {
      builder.setProperty(Analyzer.INCLUDE_RESOURCE, "test/activator/inherits=src/test/activator/inherits");
      builder.setProperty("-exportcontents", "*;x=true;version=1");
      builder.build();
      assertTrue(builder.check());
      Manifest manifest = builder.calcManifest();
      Attributes main = manifest.getMainAttributes();
      Parameters map = OSGiHeader.parseHeader(main.getValue("Export-Package"));
      Map<String,String> export = map.get("test.activator.inherits");
      assertNotNull(export);
      assertEquals("1", export.get("version"));
      assertEquals("true", export.get("x"));
    }
    finally {
      builder.close();
    }
  }

  /**
   * Check Conditional package. First import a subpackage then let the
   * subpackage import a super package. This went wrong in the OSGi build. We
   * see such a pattern in the Spring jar. The package
   * org.springframework.beans.factory.access refers to
   * org.springframework.beans.factory and org.springframework.beans. The
   */
  public static void testConditionalBaseSuper() throws Exception {
    Builder b = new Builder();
    try {
      b.setProperty(Constants.CONDITIONALPACKAGE, "test.top.*");
      b.setProperty(Constants.PRIVATEPACKAGE, "test.top.middle.bottom");
      b.addClasspath(new File("bin"));
      Jar dot = b.build();
      assertTrue(b.check());

      assertNotNull(dot.getResource("test/top/middle/bottom/Bottom.class"));
      assertNotNull(dot.getResource("test/top/middle/Middle.class"));
      assertNotNull(dot.getResource("test/top/Top.class"));

      assertFalse(b.getImports().getByFQN("test.top") != null);
      assertFalse(b.getImports().getByFQN("test.top.middle") != null);
      assertFalse(b.getImports().getByFQN("test.top.middle.bottom") != null);
    }
    finally {
      b.close();
    }
  }

  /**
   * It looks like Conditional-Package can add the same package multiple
   * times. So lets test this.
   */
  public static void testConditional2() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.EXPORT_PACKAGE, "org.osgi.service.log");
    base.put(Analyzer.CONDITIONAL_PACKAGE, "org.osgi.*");
    Builder analyzer = new Builder();
    try {
      analyzer.setProperties(base);
      analyzer.setClasspath(new File[] {
        IO.getFile("jar/osgi.jar")
      });
      analyzer.build();
      assertTrue(analyzer.check("private references"));
      Jar jar = analyzer.getJar();
      assertTrue(analyzer.check());
      assertNotNull(analyzer.getExports().getByFQN("org.osgi.service.log"));
      assertNotNull(jar.getDirectories().get("org/osgi/framework"));
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * Test the strategy: error
   */
  public static void testStrategyError() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.EXPORT_PACKAGE, "*;-split-package:=error");
    Builder analyzer = new Builder();
    try {
      analyzer.setClasspath(new File[] {
          IO.getFile("jar/asm.jar"), IO.getFile("jar/asm.jar")
      });
      analyzer.setProperties(base);
      analyzer.build();
      assertTrue(analyzer.check("The JAR is empty", "Split package"));
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * Test the strategy: default
   */
  public static void testStrategyDefault() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.EXPORT_PACKAGE, "*");
    Builder analyzer = new Builder();
    try {
      analyzer.setClasspath(new File[] {
          IO.getFile("jar/asm.jar"), IO.getFile("jar/asm.jar")
      });
      analyzer.setProperties(base);
      analyzer.build();
      assertEquals(2, analyzer.getWarnings().size());
      assertTrue(analyzer.check("Split package"));
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * Test the strategy: merge-first
   */
  public static void testStrategyMergeFirst() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.EXPORT_PACKAGE, "*;-split-package:=merge-first");
    Builder analyzer = new Builder();
    try {
      analyzer.setClasspath(new File[] {
          IO.getFile("jar/asm.jar"), IO.getFile("jar/asm.jar")
      });
      analyzer.setProperties(base);
      analyzer.build();
      assertTrue(analyzer.check());
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * Test the strategy: merge-last
   */
  public static void testStrategyMergeLast() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.EXPORT_PACKAGE, "*;-split-package:=merge-last");
    Builder analyzer = new Builder();
    try {
      analyzer.setClasspath(new File[] {
          IO.getFile("jar/asm.jar"), IO.getFile("jar/asm.jar")
      });
      analyzer.setProperties(base);
      analyzer.build();
      assertTrue(analyzer.check());
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * Test Resource inclusion that do not exist
   *
   * @throws Exception
   */
  public static void testResourceNotFound() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.EXPORT_PACKAGE, "*;x-test:=true");
    base.put(Analyzer.INCLUDE_RESOURCE, "does_not_exist");
    Builder analyzer = new Builder();
    try {
      analyzer.setClasspath(new File[] {
        IO.getFile("jar/asm.jar")
      });
      analyzer.setProperties(base);
      analyzer.build();
      assertTrue(analyzer.check("file does not exist: does_not_exist"));
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * Check if we can use findpath to build the Bundle-Classpath.
   */

  public static void testFindPathInBundleClasspath() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.INCLUDE_RESOURCE, "jar=jar");
    base.put(Analyzer.BUNDLE_CLASSPATH, "${findpath;jar/.{1,4}\\.jar}");
    Builder analyzer = new Builder();
    try {
      analyzer.setProperties(base);
      analyzer.build();
      assertTrue(analyzer.check());

      Manifest manifest = analyzer.getJar().getManifest();
      String bcp = manifest.getMainAttributes().getValue("Bundle-Classpath");

      assertTrue(bcp.indexOf("ds.jar") >= 0);
      assertTrue(bcp.indexOf("asm.jar") >= 0);
      assertTrue(bcp.indexOf("bcel.jar") >= 0);
      assertTrue(bcp.indexOf("mina.jar") >= 0);
      assertTrue(bcp.indexOf("rox.jar") >= 0);
      assertTrue(bcp.indexOf("osgi.jar") >= 0);
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * Check if we export META-INF when we export the complete classpath.
   */

  public static void testVersionCleanupAll() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.EXPORT_PACKAGE, "*");
    base.put(Analyzer.BUNDLE_VERSION, "0.9.0-incubator-SNAPSHOT");
    Builder analyzer = new Builder();
    try {
      analyzer.setClasspath(new File[] {
        IO.getFile("jar/asm.jar")
      });
      analyzer.setProperties(base);
      analyzer.build();

      assertTrue(analyzer.check());
      Manifest manifest = analyzer.getJar().getManifest();
      String version = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_VERSION);
      assertEquals("0.9.0.incubator-SNAPSHOT", version);
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * We are only adding privately the core equinox ds package. We then add
   * conditionally all packages that should belong to this as well as any OSGi
   * interfaces.
   *
   * @throws Exception
   */
  public static void testConditional() throws Exception {
    File cp[] = {
        IO.getFile("jar/osgi.jar"), IO.getFile("jar/ds.jar")
    };
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Import-Package", "*");
      p.put("Private-Package", "org.eclipse.equinox.ds");
      p.put("Conditional-Package", "org.eclipse.equinox.ds.*, org.osgi.service.*");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      bmaker.build();
      assertTrue(bmaker.check());

      assertTrue(bmaker.getContained().getByFQN("org.eclipse.equinox.ds.instance") != null);
      assertTrue(bmaker.getContained().getByFQN("org.eclipse.equinox.ds.model") != null);
      assertTrue(bmaker.getContained().getByFQN("org.eclipse.equinox.ds.parser") != null);
      assertTrue(bmaker.getContained().getByFQN("org.osgi.service.cm") != null);
      assertTrue(bmaker.getContained().getByFQN("org.osgi.service.component") != null);
      assertFalse(bmaker.getContained().getByFQN("org.osgi.service.wireadmin") != null);
    }
    finally {
      bmaker.close();
    }
  }

  /**
   * Check if we export META-INF when we export the complete classpath.
   */

  public static void testMetaInfExport() throws Exception {
    Properties base = new Properties();
    base.put(Analyzer.EXPORT_PACKAGE, "*");
    Builder analyzer = new Builder();
    try {
      analyzer.setClasspath(new File[] {
        IO.getFile("jar/asm.jar")
      });
      analyzer.setProperties(base);
      analyzer.build();
      assertTrue(analyzer.check());
      assertFalse(analyzer.getExports().getByFQN("META-INF") != null);
      assertTrue(analyzer.getExports().getByFQN("org.objectweb.asm") != null);
    }
    finally {
      analyzer.close();
    }
  }

  /**
   * Check that the activator is found.
   *
   * @throws Exception
   */
  public static void testFindActivator() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Bundle-Activator", "test.activator.Activator");
      p.put("build", "xyz"); // for @Version annotation
      p.put("Private-Package", "test.*");
      bmaker.setProperties(p);
      bmaker.setClasspath(new File[] {
        new File("bin")
      });
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      report("testFindActivator", bmaker, jar);
      assertEquals(0, bmaker.getErrors().size());
      assertEquals(0, bmaker.getWarnings().size());
    }
    finally {
      bmaker.close();
    }
  }

  public static void testImportVersionRange() throws Exception {
    assertVersionEquals("[1.1,2.0)", "[1.1,2.0)");
    assertVersionEquals("[${@},2.0)", "[1.3,2.0)");
    assertVersionEquals("[${@},${@}]", "[1.3,1.3]");
  }

  static void assertVersionEquals(String input, String output) throws Exception {
    File cp[] = {
      IO.getFile("jar/osgi.jar")
    };
    Builder bmaker = new Builder();
    try {
      bmaker.setClasspath(cp);
      Properties p = new Properties();
      p.put(Analyzer.EXPORT_PACKAGE, "test.activator");
      p.put(Analyzer.IMPORT_PACKAGE, "org.osgi.framework;version=\"" + input + "\"");
      bmaker.setProperties(p);
      bmaker.build();
      assertTrue(bmaker.check("The JAR is empty"));
      Packages imports = bmaker.getImports();
      Map<String,String> framework = imports.get(bmaker.getPackageRef("org.osgi.framework"));
      assertEquals(output, framework.get("version"));
    }
    finally {
      bmaker.close();
    }

  }

  public static void testImportExportBadVersion() throws Exception {
    Builder b = new Builder();
    try {
      b.addClasspath(IO.getFile("jar/ds.jar"));
      b.set(Analyzer.BUNDLE_VERSION, "0.9.5-@#SNAPSHOT");
      b.set(Analyzer.EXPORT_PACKAGE, "*;version=0.9.5-@#SNAPSHOT");
      b.set(Analyzer.IMPORT_PACKAGE, "*;version=0.9.5-@#SNAPSHOT");

      Jar jar = b.build();
      assertTrue(b.check());
      Manifest m = jar.getManifest();
      m.write(System.err);
      assertEquals(m.getMainAttributes().getValue("Bundle-Version"), "0.9.5.SNAPSHOT");

      assertNotNull(b.getExports().getByFQN("org.eclipse.equinox.ds.parser"));
      assertEquals("0.9.5.SNAPSHOT", b.getExports().getByFQN("org.eclipse.equinox.ds.parser").getVersion());

      assertNotNull(b.getImports().getByFQN("org.osgi.framework"));
      assertEquals("0.9.5.SNAPSHOT", b.getImports().getByFQN("org.osgi.framework").getVersion());
    }
    finally {
      b.close();
    }
  }

  /**
   * Check if can find an activator in the bundle while using a complex bundle
   * classpath.
   *
   * @throws Exception
   */
  public static void testBundleClasspath3() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Export-Package", "test.activator;-split-package:=merge-first");
      p.put("Bundle-Activator", "test.activator.Activator");
      p.put("Import-Package", "*");
      p.put("Include-Resource", "ds.jar=jar/ds.jar");
      p.put("Bundle-ClassPath", ".,ds.jar");
      bmaker.setProperties(p);
      bmaker.setClasspath(new File[] {
          new File("bin"), new File("src")
      });
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      report("testBundleClasspath3", bmaker, jar);
      assertEquals(0, bmaker.getErrors().size());
      assertEquals(0, bmaker.getWarnings().size());
    }
    finally {
      bmaker.close();
    }

  }

  /**
   * Check if can find an activator in a embedded jar while using a complex
   * bundle classpath.
   *
   * @throws Exception
   */
  public static void testBundleClasspath2() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Bundle-Activator", "org.eclipse.equinox.ds.Activator");
      p.put("Private-Package", "test.activator;-split-package:=merge-first");
      p.put("Import-Package", "*");
      p.put("Include-Resource", "ds.jar=jar/ds.jar");
      p.put("Bundle-ClassPath", ".,ds.jar");
      bmaker.setProperties(p);
      bmaker.setClasspath(new File[] {
          new File("bin"), new File("src")
      });
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      report("testBundleClasspath2", bmaker, jar);
      assertEquals(bmaker.getErrors().size(), 0);
      assertEquals(bmaker.getWarnings().size(), 0);
    }
    finally {
      bmaker.close();
    }
  }

  public static void testBundleClasspath() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Export-Package", "test.activator;-split-package:=merge-first");
      p.put("Bundle-Activator", "test.activator.Activator");
      p.put("Import-Package", "*");
      p.put("Bundle-ClassPath", ".");
      bmaker.setProperties(p);
      bmaker.setClasspath(new File[] {
          new File("bin"), new File("src")
      });
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      report("testBundleClasspath", bmaker, jar);
      jar.exists("testresources/activator/Activator.class");
      assertEquals(bmaker.getErrors().size(), 0);
      assertEquals(bmaker.getWarnings().size(), 0);
    }
    finally {
      bmaker.close();
    }

  }

  public static void testUnreferredImport() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();

      p.put("-classpath", "jar/mina.jar");
      p.put("Export-Package", "*");
      p.put("Import-Package", "org.apache.commons.collections.map,*");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      report("testUnreferredImport", bmaker, jar);
    }
    finally {
      bmaker.close();
    }
  }

  public static void testUnreferredNegatedImport() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();

      p.put("-classpath", "jar/mina.jar");
      p.put("Export-Package", "*");
      p.put("Import-Package", "!org.apache.commons.collections.map,*");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      report("testUnreferredImport", bmaker, jar);
    }
    finally {
      bmaker.close();
    }

  }

  public static void testIncludeResourceResourcesOnlyJar2() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();

      p.put("-classpath", "jar/ro.jar");
      p.put("Export-Package", "*");
      p.put("Import-Package", "");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      report("testIncludeResourceResourcesOnlyJar2", bmaker, jar);
      assertTrue(bmaker.getExports().getByFQN("ro") != null);
      assertFalse(bmaker.getExports().getByFQN("META-INF") != null);

      assertEquals(3, jar.getResources().size());
    }
    finally {
      bmaker.close();
    }
  }

  public static void testClasspathFileNotExist() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      File cp[] = new File[] {
        IO.getFile("jar/idonotexist.jar")
      };

      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      bmaker.build();
      assertTrue(bmaker.check("The JAR is empty", "Missing file on classpath: .*/jar/idonotexist.jar"));
    }
    finally {
      bmaker.close();
    }

  }

  public static void testExpandWithNegate() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      File cp[] = new File[] {
        IO.getFile("jar/asm.jar")
      };

      p.put("Export-Package", "!org.objectweb.asm,*");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      assertNull(jar.getDirectories().get("org/objectweb/asm"));
      assertNotNull(jar.getDirectories().get("org/objectweb/asm/signature"));
      assertEquals(0, bmaker.getWarnings().size());
      assertEquals(0, bmaker.getErrors().size());
      assertEquals(3, jar.getResources().size());
    }
    finally {
      bmaker.close();
    }
  }

  public static void testIncludeResourceResourcesOnlyJar() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      File cp[] = new File[] {
        IO.getFile("jar/ro.jar")
      };

      p.put("Export-Package", "*");
      p.put("Import-Package", "");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertEquals(0, bmaker.getWarnings().size());
      assertEquals(0, bmaker.getErrors().size());
      assertEquals(3, jar.getResources().size());
    }
    finally {
      bmaker.close();
    }
  }

  public static void testIncludeResourceResourcesOnly() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      File cp[] = new File[] {
        new File("src")
      };

      p.put("Import-Package", "");
      p.put("Private-Package", "test.resourcesonly");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      assertEquals(0, bmaker.getWarnings().size());
      assertEquals(0, bmaker.getErrors().size());
      assertEquals(4, jar.getResources().size());
    }
    finally {
      bmaker.close();
    }

  }

  public static void testIncludeResourceFromZipDefault() throws Exception {
    Builder bmaker = new Builder();
    Properties p = new Properties();
    p.put("Include-Resource", "@jar/easymock.jar");
    bmaker.setProperties(p);
    Jar jar = bmaker.build();
    assertTrue(bmaker.check());
    assertEquals(59, jar.getResources().size());

  }

  public static void testIncludeResourceFromZipDeep() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Include-Resource", "@jar/easymock.jar!/**");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      assertEquals(59, jar.getResources().size());
    }
    finally {
      bmaker.close();
    }
  }

  public static void testIncludeResourceFromZipOneDirectory() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Import-Package", "");
      p.put("Include-Resource", "@jar/easymock.jar!/org/easymock/**");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());

      assertEquals(59, jar.getResources().size());
      assertNotNull(jar.getResource("org/easymock/AbstractMatcher.class"));
    }
    finally {
      bmaker.close();
    }

  }

  public static void testIncludeResourceFromZipOneDirectoryOther() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put(Constants.BUNDLE_CLASSPATH, "OPT-INF/test");
      p.put("Import-Package", "!*");
      p.put("-resourceonly", "true");
      p.put("Include-Resource", "OPT-INF/test=@jar/osgi.jar!/org/osgi/service/event/**");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();

      assertTrue(bmaker.check());

      assertEquals(7, jar.getResources().size());
      assertNotNull(jar.getResource("OPT-INF/test/org/osgi/service/event/EventAdmin.class"));
    }
    finally {
      bmaker.close();
    }

  }

  public static void testIncludeResourceFromZipRecurseDirectory() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Import-Package", "!*");
      p.put("Include-Resource", "@jar/easymock.jar!/org/easymock/**");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      assertEquals(59, jar.getResources().size());
    }
    finally {
      bmaker.close();
    }

  }

  public static void testIncludeLicenseFromZip() throws Exception {
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Import-Package", "");
      p.put("Include-Resource", "@jar/osgi.jar!/LICENSE");
      bmaker.setProperties(p);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      assertEquals(1, jar.getResources().size());
      assertNotNull(jar.getResource("LICENSE"));
    }
    finally {
      bmaker.close();
    }

  }

  public static void testEasymock() throws Exception {
    File cp[] = {
      IO.getFile("jar/easymock.jar")
    };
    Builder bmaker = new Builder();
    try {
      Properties p = new Properties();
      p.put("Import-Package", "*");
      p.put("Export-Package", "*");
      p.put("Bundle-SymbolicName", "easymock");
      p.put("Bundle-Version", "2.2");
      bmaker.setProperties(p);
      bmaker.setClasspath(cp);
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      jar.getManifest().write(System.err);
    }
    finally {
      bmaker.close();
    }

  }

  public static void testSources() throws Exception {
    Builder bmaker = new Builder();
    try {
      bmaker.addClasspath(new File("bin"));
      bmaker.setSourcepath(new File[] {
        new File("src")
      });
      bmaker.setProperty("-sources", "true");
      bmaker.setProperty("Export-Package", "test.activator");
      Jar jar = bmaker.build();
      assertTrue(bmaker.check());
      assertEquals(
          "[test/activator/AbstractActivator.class, test/activator/Activator.class, test/activator/Activator11.class, test/activator/Activator2.class, test/activator/Activator3.class, test/activator/ActivatorPackage.class, test/activator/ActivatorPrivate.class, test/activator/DefaultVisibilityActivator.class, test/activator/IActivator.class, test/activator/MissingNoArgsConstructorActivator.class, test/activator/NotAnActivator.class]",
          new SortedList<String>(jar.getDirectories().get("test/activator").keySet()).toString());
    }
    finally {
      bmaker.close();
    }

  }

  public void testVerify() throws Exception {
    System.err.println("Erroneous bundle: tb1.jar");
    Jar jar = new Jar("test", getClass().getResourceAsStream("tb1.jar"));
    Verifier verifier = new Verifier(jar);
    verifier.verify();
    assertTrue(verifier.check());
    jar.close();
    verifier.close();
  }

  public static void report(String title, Analyzer builder, Jar jar) {
    System.err.println("Directories " + jar.getDirectories().keySet());
    System.err.println("Warnings    " + builder.getWarnings());
    System.err.println("Errors      " + builder.getErrors());
    System.err.println("Exports     " + builder.getExports());
    System.err.println("Imports     " + builder.getImports());
  }

}
TOP

Related Classes of test.BuilderTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.