/*******************************************************************************
 * Copyright (c) 2007, 2017 IBM Corporation and others.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which accompanies this distribution,
 * and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 * 
 * Contributors: IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.pde.build.internal.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.filters.StringInputStream;
import org.apache.tools.ant.taskdefs.Ant;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.equinox.p2.publisher.eclipse.FeatureEntry;
import org.eclipse.pde.build.internal.tests.ant.AntUtils;
import org.eclipse.pde.build.tests.BuildConfiguration;
import org.eclipse.pde.build.tests.PDETestCase;
import org.eclipse.pde.internal.build.site.BuildTimeFeature;
import org.eclipse.pde.internal.build.site.BuildTimeFeatureFactory;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.osgi.framework.FrameworkUtil;

@RunWith(BlockJUnit4ClassRunner.class)
public class SourceTests extends PDETestCase {
	@Test
	public void testBug206679_247198() throws Exception {
		IFolder buildFolder = newTest("206679");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		// generate an SDK feature
		Utils.generateFeature(buildFolder, "sdk",
				new String[] { "org.eclipse.jdt", "jdt.source", "org.eclipse.platform" }, null);
		Properties properties = new Properties();
		properties.put("generate.feature@jdt.source", "org.eclipse.jdt");
		Utils.storeBuildProperties(sdk, properties);

		Properties props = BuildConfiguration.getScriptGenerationProperties(buildFolder, "feature", "sdk");
		// tests bug 247198
		props.put("filteredDependencyCheck", "false");
		generateScripts(buildFolder, props);

		IFolder jdtSource = buildFolder.getFolder("features").getFolder("jdt.source");
		IFile featureXML = jdtSource.getFile("feature.xml");
		BuildTimeFeatureFactory factory = new BuildTimeFeatureFactory();
		BuildTimeFeature feature = factory.parseBuildFeature(featureXML.getLocation().toPath());
		assertTrue(feature.getDescription() != null);
	}

	@Test
	public void testBug114150() throws Exception {
		IFolder buildFolder = newTest("114150");

		Properties buildProperties = BuildConfiguration.getBuilderProperties(buildFolder);
		Utils.storeBuildProperties(buildFolder, buildProperties);

		runBuild(buildFolder);

		Set<String> entries = new HashSet<>();
		entries.add("eclipse/features/a.feature.sdk_1.0.0/feature.xml");
		entries.add("eclipse/features/a.feature.source_1.0.0/feature.xml");
		entries.add("eclipse/plugins/a.feature.source_1.0.0.jar:src/a.plugin_1.0.0/src.zip");
		entries.add("eclipse/plugins/a.feature.source_1.0.0.jar:src/a.plugin_1.0.0/about.html"); // tests bug 209092
		assertZipContents(buildFolder, "I.TestBuild/a.feature.sdk.zip", entries);
		entries = new HashSet<>();
		entries.add("eclipse/features/a.feature_1.0.0/feature.xml");
		entries.add("eclipse/plugins/a.plugin_1.0.0.jar");
		assertZipContents(buildFolder, "I.TestBuild/a.feature.zip", entries);
	}

	// test that generated source fragments have a proper platform filter
	@SuppressWarnings("unchecked")
	@Test
	public void testBug184517() throws Exception {
		IFolder buildFolder = newTest("184517");
		IFolder features = Utils.createFolder(buildFolder, "features");

		// generate an SDK feature
		Utils.generateFeature(buildFolder, "sdk", new String[] { "rcp", "rcp.source" }, null);
		Properties properties = new Properties();
		properties.put("generate.feature@rcp.source", "rcp");
		IFolder sdk = features.getFolder("sdk");
		Utils.storeBuildProperties(sdk, properties);

		String os = Platform.getOS();
		String ws = Platform.getWS();
		String arch = Platform.getOSArch();

		// Create the rcp feature
		Utils.generateFeature(buildFolder, "rcp", null,
				new String[] { "fragment;os=\"" + os + "\";ws=\"" + ws + "\";arch=\"" + arch + "\"" });

		// Create a fragment with a platform filter
		IFolder fragment = Utils.createFolder(buildFolder, "plugins/fragment");
		Utils.generatePluginBuildProperties(fragment, null);
		Attributes manifestAdditions = new Attributes();
		manifestAdditions.put(new Attributes.Name("Eclipse-PlatformFilter"),
				"(& (osgi.ws=" + ws + ") (osgi.os=" + os + ") (osgi.arch=" + arch + "))");
		Utils.generateBundleManifest(fragment, "fragment", "1.0.0", manifestAdditions);

		// getScriptGenerationProperties sets buildDirectory to buildFolder by default
		properties = BuildConfiguration.getScriptGenerationProperties(buildFolder, "feature", "sdk");
		properties.put("configs", os + "," + ws + "," + arch);
		generateScripts(buildFolder, properties);

		String fragmentName = "rcp.source." + os + "." + ws + "." + arch + "_1.0.0";
		IFolder sourceFragment = buildFolder.getFolder("plugins/" + fragmentName);

		// check the manifest for a correct platform filter
		assertResourceFile(sourceFragment, "META-INF/MANIFEST.MF");
		try (InputStream stream = new BufferedInputStream(
				sourceFragment.getFile("META-INF/MANIFEST.MF").getLocationURI().toURL().openStream())) {
			Manifest manifest = new Manifest(stream);
			String filter = manifest.getMainAttributes().getValue("Eclipse-PlatformFilter");
			assertTrue(filter.length() > 0);
			properties = new Properties();
			properties.put("osgi.os", os);
			properties.put("osgi.ws", ws);
			properties.put("osgi.arch", arch);
			// In 1.6 VMs properties is not casted correctly to dictionary causing a
			// compilation error (Bug 390267)
			@SuppressWarnings("rawtypes")
			Dictionary dictionary = properties;
			assertTrue(FrameworkUtil.createFilter(filter).match(dictionary));
		}

	}

	// test that '<' and '>' are properly escaped in generated source feature
	// Also tests bug 191756: features with empty <license> entries
	@Test
	public void testbug184920() throws Exception {
		// the provided resource features/a.feature/feature.xml contains &lt;foo!&gt;
		// which must be handled properly
		IFolder buildFolder = newTest("184920");

		Properties properties = BuildConfiguration.getScriptGenerationProperties(buildFolder, "feature",
				"a.feature.sdk");
		// 191756: This will NPE if empty license entry is a problem
		generateScripts(buildFolder, properties);

		assertResourceFile(buildFolder, "features/a.feature.source/feature.xml");
		IFile feature = buildFolder.getFile("features/a.feature.source/feature.xml");

		BuildTimeFeatureFactory factory = new BuildTimeFeatureFactory();
		factory.parseBuildFeature(feature.getLocation().toPath());
	}

	// test that source can come before the feature it is based on
	@Test
	public void testBug179616A() throws Exception {
		IFolder buildFolder = newTest("179616A");
		IFolder bundleFolder = Utils.createFolder(buildFolder, "plugins/a.bundle");
		IFolder sdkFolder = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateBundle(bundleFolder, "a.bundle");
		// add some source to a.bundle
		File src = new File(bundleFolder.getLocation().toFile(), "src/a.java");
		src.getParentFile().mkdir();
		try (FileOutputStream stream = new FileOutputStream(src)) {
			stream.write("//L33T CODEZ\n".getBytes());
		}

		Utils.generateFeature(buildFolder, "rcp", null, new String[] { "a.bundle" });

		Utils.generateFeature(buildFolder, "sdk", new String[] { "rcp.source", "rcp" }, null);
		Properties properties = new Properties();
		properties.put("generate.feature@rcp.source", "rcp");
		Utils.storeBuildProperties(sdkFolder, properties);

		Utils.generateAllElements(buildFolder, "sdk");
		Utils.storeBuildProperties(buildFolder, BuildConfiguration.getBuilderProperties(buildFolder));
		runBuild(buildFolder);

		Set<String> entries = new HashSet<>();
		entries.add("eclipse/plugins/rcp.source_1.0.0.jar:src/a.bundle_1.0.0/src.zip");
		assertZipContents(buildFolder, "I.TestBuild/eclipse.zip", entries);
	}

	@Test
	public void testBug179616B() throws Exception {
		IFolder buildFolder = newTest("179616B");
		IFolder bundleFolder = Utils.createFolder(buildFolder, "plugins/a.bundle");
		IFolder singleFolder = Utils.createFolder(buildFolder, "features/single");

		Utils.generateBundle(bundleFolder, "a.bundle");
		File src = new File(bundleFolder.getLocation().toFile(), "src/a.java");
		src.getParentFile().mkdir();
		try (FileOutputStream stream = new FileOutputStream(src)) {
			stream.write("//L33T CODEZ\n".getBytes());
		}

		Utils.generateFeature(buildFolder, "single", null, new String[] { "single.source", "a.bundle" });
		Properties properties = new Properties();
		properties.put("generate.plugin@single.source", "single");
		Utils.storeBuildProperties(singleFolder, properties);

		Utils.generateAllElements(buildFolder, "single");
		Utils.storeBuildProperties(buildFolder, BuildConfiguration.getBuilderProperties(buildFolder));
		runBuild(buildFolder);

		Set<String> entries = new HashSet<>();
		entries.add("eclipse/plugins/single.source_1.0.0.jar:src/a.bundle_1.0.0/src.zip");
		assertZipContents(buildFolder, "I.TestBuild/eclipse.zip", entries);
	}

	// Test the use of plugin@foo;unpack="false" in the generate.feature property
	// Test Source generation when source feature is name different from originating
	// feature
	@Test
	public void testBug107372_208617() throws Exception {
		IFolder buildFolder = newTest("107372");
		IFolder bundleA = Utils.createFolder(buildFolder, "plugins/bundleA");
		IFolder bundleDoc = Utils.createFolder(buildFolder, "plugins/bundleDoc");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateBundle(bundleA, "bundleA");
		File src = new File(bundleA.getLocation().toFile(), "src/a.java");
		src.getParentFile().mkdir();
		try (FileOutputStream outputStream = new FileOutputStream(src)) {
			outputStream.write("//L33T CODEZ\n".getBytes());
		}

		Utils.generateBundle(bundleDoc, "bundleDoc");
		src = new File(bundleDoc.getLocation().toFile(), "src/a.java");
		src.getParentFile().mkdir();
		try (FileOutputStream outputStream = new FileOutputStream(src)) {
			outputStream.write("//L33T CODEZ\n".getBytes());
		}

		// generate an SDK feature
		// test bug 208617 by naming the source feature something other than just
		// originating feature + .source
		Utils.generateFeature(buildFolder, "sdk", new String[] { "rcp", "source" }, null);
		Properties properties = new Properties();
		properties.put("generate.feature@source", "rcp,plugin@bundleDoc;unpack=\"false\"");
		Utils.storeBuildProperties(sdk, properties);

		// RCP Feature
		Utils.generateFeature(buildFolder, "rcp", null, new String[] { "bundleA" });

		Utils.generateAllElements(buildFolder, "sdk");
		Utils.storeBuildProperties(buildFolder, BuildConfiguration.getBuilderProperties(buildFolder));
		runBuild(buildFolder);

		// bundleDoc only gets in the build by being added to the generated source
		// feature,
		// check that it is there in the result and is in jar form.
		Set<String> entries = new HashSet<>();
		entries.add("eclipse/plugins/bundleDoc_1.0.0.jar");
		entries.add("eclipse/plugins/source_1.0.0.jar:src/bundleA_1.0.0/src.zip");
		assertZipContents(buildFolder, "I.TestBuild/eclipse.zip", entries);
	}

	// test use of feature@foo;optional="true"
	@Test
	public void testBug228537() throws Exception {
		IFolder buildFolder = newTest("228537");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateFeature(buildFolder, "sdk", new String[] { "source" }, null);
		Properties properties = new Properties();
		properties.put("generate.feature@source", "sdk,feature@org.eclipse.rcp;optional=\"true\";os=\"win32\"");
		Utils.storeBuildProperties(sdk, properties);

		Properties buildProperties = BuildConfiguration.getScriptGenerationProperties(buildFolder, "feature", "sdk");
		generateScripts(buildFolder, buildProperties);

		assertResourceFile(buildFolder, "features/source/feature.xml");
		IFile featureFile = buildFolder.getFile("features/source/feature.xml");

		BuildTimeFeatureFactory factory = new BuildTimeFeatureFactory();
		BuildTimeFeature feature = factory.parseBuildFeature(featureFile.getLocation().toPath());
		FeatureEntry[] entries = feature.getRawIncludedFeatureReferences();
		assertTrue(entries.length == 1);
		assertEquals(entries[0].getId(), "org.eclipse.rcp");
		assertTrue(entries[0].isOptional());
		assertEquals(entries[0].getOS(), "win32");
	}

	@Test
	public void testIndividualSourceBundles() throws Exception {
		IFolder buildFolder = newTest("individualSourceBundles");

		IFolder bundleA = Utils.createFolder(buildFolder, "plugins/bundleA");
		IFolder bundleB = Utils.createFolder(buildFolder, "plugins/bundleB");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateBundleManifest(bundleA, "bundleA", "1.0.0", null);
		Properties buildProperties = new Properties();
		buildProperties.put("src.includes", "about.html");
		Utils.generatePluginBuildProperties(bundleA, buildProperties);
		File src = new File(bundleA.getLocation().toFile(), "src/a.java");
		src.getParentFile().mkdir();
		try (FileOutputStream outputStream = new FileOutputStream(src)) {
			outputStream.write("//L33T CODEZ\n".getBytes());
		}
		File about = new File(bundleA.getLocation().toFile(), "about.html");
		try (FileOutputStream outputStream = new FileOutputStream(about)) {
			outputStream.write("about\n".getBytes());
		}

		Utils.generateBundle(bundleB, "bundleB");
		src = new File(bundleB.getLocation().toFile(), "src/b.java");
		src.getParentFile().mkdir();
		try (FileOutputStream outputStream = new FileOutputStream(src)) {
			outputStream.write("//L33T CODEZ\n".getBytes());
		}

		// generate an SDK feature
		Utils.generateFeature(buildFolder, "sdk", new String[] { "rcp", "rcp.source" }, null);
		Properties properties = new Properties();
		properties.put("generate.feature@rcp.source", "rcp");
		Utils.storeBuildProperties(sdk, properties);

		// RCP Feature
		Utils.generateFeature(buildFolder, "rcp", null, new String[] { "bundleA", "bundleB" });

		Utils.generateAllElements(buildFolder, "sdk");
		buildProperties = BuildConfiguration.getBuilderProperties(buildFolder);
		buildProperties.put("individualSourceBundles", "true");
		Utils.storeBuildProperties(buildFolder, buildProperties);
		runBuild(buildFolder);

		Set<String> entries = new HashSet<>();
		entries.add("eclipse/plugins/bundleA.source_1.0.0.jar");
		entries.add("eclipse/plugins/bundleB.source_1.0.0.jar");
		assertZipContents(buildFolder, "I.TestBuild/eclipse.zip", entries);

		try (ZipFile zip = new ZipFile(buildFolder.getFile("I.TestBuild/eclipse.zip").getLocation().toFile())) {
			ZipEntry entry = zip.getEntry("eclipse/plugins/bundleA.source_1.0.0.jar");
			IFile jar = buildFolder.getFile("bundleA.source_1.0.0.jar");
			try (InputStream in = zip.getInputStream(entry)) {
				Files.copy(in, jar.getLocation().toFile().toPath(), StandardCopyOption.REPLACE_EXISTING);
			}
		}

		entries.clear();
		entries.add("about.html");
		entries.add("plugin.properties");
		assertZipContents(buildFolder, "bundleA.source_1.0.0.jar", entries);

		IFile feature = buildFolder.getFile("features/rcp.source/feature.xml");
		BuildTimeFeatureFactory factory = new BuildTimeFeatureFactory();
		BuildTimeFeature model = factory.parseBuildFeature(feature.getLocation().toPath());

		FeatureEntry[] included = model.getPluginEntries();
		assertEquals(included.length, 2);
		assertEquals(included[0].getId(), "bundleA.source");
		assertFalse(included[0].isUnpack());
		assertEquals(included[1].getId(), "bundleB.source");
		assertFalse(included[1].isUnpack());
	}

	@Test
	public void testBug230870() throws Exception {
		IFolder buildFolder = newTest("230870");

		IFolder bundleA = Utils.createFolder(buildFolder, "plugins/bundleA");
		IFolder bundleB = Utils.createFolder(buildFolder, "plugins/bundleB");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateFeature(buildFolder, "sdk", new String[] { "rcp", "rcp.source" },
				new String[] { "bundleB", "bundleB.source;unpack=false" });
		Properties properties = new Properties();
		properties.put("generate.feature@rcp.source", "rcp");
		properties.put("generate.plugin@bundleB.source", "bundleB");
		properties.put("individualSourceBundles", "true");
		Utils.storeBuildProperties(sdk, properties);

		Utils.generateFeature(buildFolder, "rcp", null, new String[] { "bundleA" });

		Utils.generateBundleManifest(bundleA, "bundleA", "1.0.0", null);
		Properties buildProperties = new Properties();
		buildProperties.put("src.includes", "about.html");
		Utils.generatePluginBuildProperties(bundleA, buildProperties);
		Utils.writeBuffer(bundleA.getFile("src/A.java"), new StringBuffer("class A {\n}\n"));
		Utils.writeBuffer(bundleA.getFile("about.html"), new StringBuffer("about\n"));

		Utils.generateBundleManifest(bundleB, "bundleB", "1.0.0", null);
		buildProperties = new Properties();
		buildProperties.put("src.includes", "about.html");
		Utils.generatePluginBuildProperties(bundleB, buildProperties);
		Utils.writeBuffer(bundleB.getFile("src/B.java"), new StringBuffer("class B {\n}\n"));
		Utils.writeBuffer(bundleB.getFile("about.html"), new StringBuffer("about\n"));

		properties = BuildConfiguration.getBuilderProperties(buildFolder);
		properties.put("topLevelElementId", "sdk");
		properties.put("baseLocation", "");
		properties.put("archivesFormat", "*,*,*-folder");
		Utils.storeBuildProperties(buildFolder, properties);
		runBuild(buildFolder);

		Set<String> entries = new HashSet<>();
		entries.clear();
		entries.add("A.java");
		entries.add("about.html");
		assertZipContents(buildFolder, "tmp/eclipse/plugins/bundleA.source_1.0.0.jar", entries);

		entries.clear();
		entries.add("B.java");
		entries.add("about.html");
		assertZipContents(buildFolder, "tmp/eclipse/plugins/bundleB.source_1.0.0.jar", entries);
	}

	@Test
	public void testIndividualSourceBundles_2() throws Exception {
		IFolder buildFolder = newTest("individualSourceBundles2");

		IFolder bundleA = Utils.createFolder(buildFolder, "plugins/bundleA");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateBundle(bundleA, "bundleA");
		File src = new File(bundleA.getLocation().toFile(), "src/A.java");
		src.getParentFile().mkdir();
		try (FileOutputStream outputStream = new FileOutputStream(src)) {
			outputStream.write("class A {\n}\n".getBytes());
		}

		// generate an SDK feature
		Utils.generateFeature(buildFolder, "sdk", null, new String[] { "bundleA", "bundleA.source" });
		Properties properties = new Properties();
		properties.put("generate.plugin@bundleA.source", "bundleA");
		Utils.storeBuildProperties(sdk, properties);

		Utils.generateAllElements(buildFolder, "sdk");
		Properties buildProperties = BuildConfiguration.getBuilderProperties(buildFolder);
		buildProperties.put("individualSourceBundles", "true");
		buildProperties.put("archivesFormat", "*,*,*-folder");
		Utils.storeBuildProperties(buildFolder, buildProperties);
		runBuild(buildFolder);

		IFolder plugins = buildFolder.getFolder("tmp/eclipse/plugins");
		IFile binaryA = plugins.getFile("bundleA_1.0.0.jar");
		IFile binaryASource = plugins.getFile("bundleA.source_1.0.0.jar");
		assertZipContents(binaryA, "A.class");
		assertZipContents(binaryASource, "A.java");

		String manifestFile = readEntryFromZip(binaryASource, "META-INF/MANIFEST.MF");
		try (InputStream contents = new StringInputStream(manifestFile)) {
			Manifest manifest = new Manifest(contents);
			Attributes attr = manifest.getMainAttributes();
			assertEquals(attr.getValue("Bundle-Version"), "1.0.0");
			assertEquals(attr.getValue("Bundle-SymbolicName"), "bundleA.source");
			assertTrue(attr.getValue("Eclipse-SourceBundle").startsWith("bundleA;version=\"1.0.0\""));
		}
	}

	@Test
	public void test243475_243227() throws Exception {
		IFolder buildFolder = newTest("243475");
		IFolder bundleFolder = Utils.createFolder(buildFolder, "plugins/a.bundle");
		IFolder sdkFolder = Utils.createFolder(buildFolder, "features/sdk");
		Utils.generateBundleManifest(bundleFolder, "a.bundle", "1.0.0", null);
		Properties props = new Properties();
		props.put("src.includes", "about.html");
		Utils.generatePluginBuildProperties(bundleFolder, props);
		// add some source to a.bundle
		File src = new File(bundleFolder.getLocation().toFile(), "src/a.java");
		src.getParentFile().mkdir();
		try (FileOutputStream stream = new FileOutputStream(src)) {
			stream.write("//L33T CODEZ\n".getBytes());
		}
		// add the about.html
		File about = new File(bundleFolder.getLocation().toFile(), "about.html");
		try (FileOutputStream stream = new FileOutputStream(about)) {
			stream.write("about\n".getBytes());
		}

		Utils.generateFeature(buildFolder, "rcp", null, new String[] { "a.bundle" }, "1.0.0.qualifier");

		Utils.generateFeature(buildFolder, "sdk", new String[] { "rcp", "rcp.source" }, null);
		Properties properties = new Properties();
		properties.put("generate.feature@rcp.source", "rcp");
		Utils.storeBuildProperties(sdkFolder, properties);

		Utils.generateAllElements(buildFolder, "sdk");
		Properties buildProperties = BuildConfiguration.getBuilderProperties(buildFolder);
		buildProperties.put("archivesFormat", "*,*,*-folder");
		buildProperties.put("forceContextQualifier", "123");
		Utils.storeBuildProperties(buildFolder, buildProperties);
		runBuild(buildFolder);

		assertResourceFile(buildFolder, "tmp/eclipse/plugins/rcp.source_1.0.0.123.jar:src/a.bundle_1.0.0/about.html");
		assertResourceFile(buildFolder, "tmp/eclipse/plugins/rcp.source_1.0.0.123.jar:src/a.bundle_1.0.0/src.zip");

		// build again using the binaries output from the first build
		IFolder build2 = Utils.createFolder(buildFolder, "2");

		// top level feature must be in buildDirectory
		Utils.createFolder(build2, "features");
		sdkFolder.move(IPath.fromOSString("../2/features/sdk"), true, null);

		// TODO here the rcp.source_1.0.0.123.jar should be extracted to rcp.source_1.0.0.123 as it was before
		// but I'm too lazy to do that and Java doesn't provide one liner to do that
		
		String oldBuild = buildFolder.getLocation().toOSString();
		Utils.generateAllElements(build2, "sdk");
		buildProperties = BuildConfiguration.getBuilderProperties(build2);
		buildProperties.put("archivesFormat", "*,*,*-folder");
		buildProperties.put("pluginPath", oldBuild + "/tmp/eclipse" + File.pathSeparator + oldBuild + "/features/rcp");
		buildProperties.put("forceContextQualifier", "124");
		Utils.storeBuildProperties(build2, buildProperties);
		runBuild(build2);

		assertResourceFile(build2, "tmp/eclipse/plugins/rcp.source_1.0.0.124.jar");

		// If the TODO above is fixed, the lines here can be uncommented
		// assertResourceFile(build2, "tmp/eclipse/plugins/rcp.source_1.0.0.124.jar:src/a.bundle_1.0.0/about.html");
		// assertResourceFile(build2, "tmp/eclipse/plugins/rcp.source_1.0.0.124.jar:src/a.bundle_1.0.0/src.zip");
	}

	@Ignore
	@Test
	public void testBug247007_247027() throws Exception {
		IFolder buildFolder = newTest("247007");
		IFolder sdkFolder = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateFeature(buildFolder, "sdk", new String[] { "sdk.source" }, new String[] { "org.apache.ant" });
		Properties properties = new Properties();
		properties.put("generate.feature@sdk.source", "sdk,feature@org.eclipse.rcp");
		Utils.storeBuildProperties(sdkFolder, properties);

		properties = BuildConfiguration.getScriptGenerationProperties(buildFolder, "feature", "sdk");
		properties.put("filteredDependencyCheck", "true");
		generateScripts(buildFolder, properties);

		// if we failed to account for the source features, then osgi would not have
		// been in the state and
		// org.apache.ant would have failed to resolve and generateScripts would have
		// thrown an exception
	}

	@Test
	public void testBug257761() throws Exception {
		IFolder buildFolder = newTest("257761");
		IFolder a1 = Utils.createFolder(buildFolder, "plugins/a1");
		IFolder a2 = Utils.createFolder(buildFolder, "plugins/a2");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateFeature(buildFolder, "sdk", new String[] { "sdk.source" },
				new String[] { "a;version=1.0.0", "a;version=2.0.0" });
		Properties properties = new Properties();
		properties.put("generate.feature@sdk.source", "sdk");
		properties.put("individualSourceBundles", "true");
		Utils.storeBuildProperties(sdk, properties);

		Utils.generateBundleManifest(a1, "a", "1.0.0", null);
		Utils.generatePluginBuildProperties(a1, null);
		Utils.writeBuffer(a1.getFile("src/a.java"), new StringBuffer("class a{}"));

		Utils.generateBundleManifest(a2, "a", "2.0.0", null);
		Utils.generatePluginBuildProperties(a2, null);
		Utils.writeBuffer(a2.getFile("src/a.java"), new StringBuffer("class a{}"));

		properties = BuildConfiguration.getBuilderProperties(buildFolder);
		properties.put("topLevelElementId", "sdk");
		properties.put("baseLocation", "");
		properties.put("archivesFormat", "*,*,*-folder");
		Utils.storeBuildProperties(buildFolder, properties);

		runBuild(buildFolder);
		assertResourceFile(buildFolder, "tmp/eclipse/plugins/a.source_1.0.0.jar");
		assertResourceFile(buildFolder, "tmp/eclipse/plugins/a.source_2.0.0.jar");
	}

	@Test
	public void testBug272543() throws Exception {
		IFolder root = newTest("272543");
		IFolder buildFolder = Utils.createFolder(root, "build1");
		IFolder bundleA = Utils.createFolder(buildFolder, "plugins/bundleA");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateFeature(buildFolder, "sdk", null, new String[] { "bundleA", "bundleA.source;unpack=false" });
		Properties properties = new Properties();
		properties.put("generate.plugin@bundleA.source", "bundleA");
		properties.put("individualSourceBundles", "true");
		Utils.storeBuildProperties(sdk, properties);

		Utils.generateBundleManifest(bundleA, "bundleA", "1.0.0", null);
		Properties buildProperties = new Properties();
		buildProperties.put("src.includes", "about.html");
		Utils.generatePluginBuildProperties(bundleA, buildProperties);
		Utils.writeBuffer(bundleA.getFile("src/A.java"), new StringBuffer("class A {\n}\n"));
		Utils.writeBuffer(bundleA.getFile("about.html"), new StringBuffer("about\n"));

		properties = BuildConfiguration.getBuilderProperties(buildFolder);
		properties.put("topLevelElementId", "sdk");
		properties.put("baseLocation", "");
		properties.put("archivesFormat", "*,*,*-folder");
		Utils.storeBuildProperties(buildFolder, properties);
		runBuild(buildFolder);

		IFolder build2 = Utils.createFolder(root, "build2");
		IFolder sdk2 = Utils.createFolder(build2, "features/sdk2");
		Utils.generateFeature(build2, "sdk2", null, new String[] { "bundleA", "bundleA.source;unpack=false" });
		properties = new Properties();
		properties.put("generate.plugin@bundleA.source", "bundleA");
		properties.put("individualSourceBundles", "true");
		Utils.storeBuildProperties(sdk2, properties);

		properties = BuildConfiguration.getBuilderProperties(build2);
		properties.put("topLevelElementId", "sdk2");
		properties.put("baseLocation", buildFolder.getFolder("tmp/eclipse").getLocation().toOSString());
		properties.put("archivesFormat", "*,*,*-folder");
		Utils.storeBuildProperties(build2, properties);
		runBuild(build2);
	}

	@Test
	public void testBug290828() throws Exception {
		IFolder buildFolder = newTest("290828");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateFeature(buildFolder, "f", null, new String[] { "org.eclipse.team.core" });
		Utils.generateFeature(buildFolder, "sdk", new String[] { "f", "f.source" }, null);

		Properties properties = new Properties();
		properties.put("generate.feature@f.source", "f");
		properties.put("individualSourceBundles", "true");
		Utils.storeBuildProperties(sdk, properties);

		properties = BuildConfiguration.getBuilderProperties(buildFolder);
		properties.put("topLevelElementId", "sdk");
		properties.put("archivesFormat", "*,*,*-folder");
		Utils.storeBuildProperties(buildFolder, properties);
		runBuild(buildFolder);

		IFile feature = buildFolder.getFile("tmp/eclipse/features/f.source_1.0.0/feature.xml");
		assertResourceFile(feature);
		BuildTimeFeatureFactory factory = new BuildTimeFeatureFactory();
		BuildTimeFeature model = factory.parseBuildFeature(feature.getLocation().toPath());
		FeatureEntry[] included = model.getPluginEntries();
		assertEquals(1, included.length);
		for (FeatureEntry element : included) {
			assertResourceFile(buildFolder,
					"tmp/eclipse/plugins/" + element.getId() + "_" + element.getVersion() + ".jar");
		}
	}

	@Test
	public void testbug302941() throws Exception {
		IFolder buildFolder = newTest("302941");

		IFolder bundleA = Utils.createFolder(buildFolder, "plugins/bundleA");
		IFolder sdk = Utils.createFolder(buildFolder, "features/sdk");

		Utils.generateFeature(buildFolder, "sdk", null, new String[] { "bundleA", "bundleA.source;unpack=false" });
		Properties properties = new Properties();
		properties.put("generate.plugin@bundleA.source", "bundleA");
		properties.put("individualSourceBundles", "true");
		Utils.storeBuildProperties(sdk, properties);

		Utils.generateBundleManifest(bundleA, "bundleA", "1.0.0", null);
		Properties buildProperties = new Properties();
		buildProperties.put("src.includes", "about.html");
		Utils.generatePluginBuildProperties(bundleA, buildProperties);
		Utils.writeBuffer(bundleA.getFile("src/A.java"), new StringBuffer("class A {\n}\n"));
		Utils.writeBuffer(bundleA.getFile("about.html"), new StringBuffer("about\n"));

		properties = BuildConfiguration.getBuilderProperties(buildFolder);
		properties.put("topLevelElementId", "sdk");
		properties.put("baseLocation", "");
		properties.put("archivesFormat", "*,*,*-folder");
		Utils.storeBuildProperties(buildFolder, properties);

		StringBuffer buildAll = new StringBuffer();
		buildAll.append(
				"<project default=\"main\">                                                                  \n");
		buildAll.append(
				"   <target name=\"main\" >                                                                  \n");
		buildAll.append(
				"      <property name=\"builder\" value=\"${basedir}\" />                                    \n");
		buildAll.append(
				"      <ant antfile=\"build.xml\" dir=\"${eclipse.pdebuild.scripts}\" target=\"generate\" /> \n");
		buildAll.append(
				"      <ant antfile=\"build.xml\" dir=\"${eclipse.pdebuild.scripts}\" target=\"generate\" /> \n");
		buildAll.append(
				"   </target>                                                                                \n");
		buildAll.append(
				"</project>                                                                                  \n");

		IFile buildXml = buildFolder.getFile("buildAll.xml");
		Utils.writeBuffer(buildXml, buildAll);

		runAntScript(buildXml.getLocation().toOSString(), new String[] { "main" },
				buildFolder.getLocation().toOSString(), null);

		IFile buildScript = buildFolder.getFile("plugins/bundleA.source_1.0.0/build.xml");
		Project antProject = assertValidAntScript(buildScript);
		Target publishBinParts = antProject.getTargets().get("publish.bin.parts");
		assertNotNull(publishBinParts);
		Object child = AntUtils.getFirstChildByName(publishBinParts, "ant");
		assertNotNull(child);
		assertTrue(child instanceof Ant);
	}
}
