Index: src/org/netbeans/modules/apisupport/project/universe/TestModuleDependency.java =================================================================== RCS file: src/org/netbeans/modules/apisupport/project/universe/TestModuleDependency.java diff -N src/org/netbeans/modules/apisupport/project/universe/TestModuleDependency.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/netbeans/modules/apisupport/project/universe/TestModuleDependency.java 20 Jul 2006 09:13:24 -0000 @@ -0,0 +1,84 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.apisupport.project.universe; + +import java.util.Comparator; + +/** + * Test dependedency entry from project.xml + * @author pzajac + */ +public class TestModuleDependency { + public static final String UNIT = "unit"; // NOI18N + public static final String QA_FUNCTIONAL = "qa-functional"; // NOI18N + private final ModuleEntry module; + // dependendends also on tests of modules + private boolean test; + // depends on execution classpath of the modules + private boolean recursive; + // compilation dependency + private boolean compile; + + public static final Comparator CNB_COMPARATOR = new CndsComparator(); + + private static final class CndsComparator implements Comparator { + public int compare(Object tmd1,Object tmd2) { + return ((TestModuleDependency)tmd1).module.getCodeNameBase().compareTo(((TestModuleDependency)tmd2).module.getCodeNameBase()); + } + } + /** + * Creates a new instance of TestModuleDependency + */ + public TestModuleDependency(ModuleEntry me,boolean test,boolean recursive,boolean compile) { + this.module = me; + this.setTest(test); + this.setRecursive(recursive); + this.setCompile(compile); + } + + public ModuleEntry getModule() { + return module; + } + + public boolean isTest() { + return test; + } + + public void setTest(boolean test) { + this.test = test; + } + + public boolean isRecursive() { + return recursive; + } + + public void setRecursive(boolean recursive) { + this.recursive = recursive; + } + + public boolean isCompile() { + return compile; + } + + public void setCompile(boolean compile) { + this.compile = compile; + } + +} Index: test/unit/src/org/netbeans/modules/apisupport/project/queries/ClassPathProviderImplTest.java =================================================================== RCS file: /cvs/apisupport/project/test/unit/src/org/netbeans/modules/apisupport/project/queries/ClassPathProviderImplTest.java,v retrieving revision 1.39 diff -u -r1.39 ClassPathProviderImplTest.java --- test/unit/src/org/netbeans/modules/apisupport/project/queries/ClassPathProviderImplTest.java 30 Jun 2006 18:12:32 -0000 1.39 +++ test/unit/src/org/netbeans/modules/apisupport/project/queries/ClassPathProviderImplTest.java 20 Jul 2006 09:13:26 -0000 @@ -22,6 +22,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; +import java.io.PrintStream; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -108,6 +109,27 @@ "org-netbeans-modules-nbjunit.jar", "org-netbeans-modules-nbjunit-ide.jar", })); + + private void assertSets(String message,Set set1, Set set2 ) { + StringBuffer result = new StringBuffer(); + boolean pass = true; + for (Iterator it = set1.iterator() ; it.hasNext() ; ) { + Object obj = it.next(); + if (!set2.contains(obj)) { + pass = false; + result.append("- " + obj + "\n"); + } + } + for (Iterator it = set2.iterator() ; it.hasNext() ; ) { + Object obj = it.next(); + if (!set1.contains(obj)) { + pass = false; + result.append("+ " + obj + "\n"); + } + } + assertTrue(message + "\n" + result,pass); + } + private Set/**/ urlsOfCp4Tests(ClassPath cp) { Set/**/ s = new TreeSet(); Iterator it = cp.entries().iterator(); @@ -295,13 +317,20 @@ expectedRoots.add("nbjunit.jar"); expectedRoots.add("nbjunit-ide.jar"); expectedRoots.add("insanelib.jar"); - assertEquals("right COMPILE classpath", expectedRoots.toString(), urlsOfCp4Tests(cp).toString()); + // recursive dependencies + expectedRoots.add(urlForJar("nbbuild/netbeans/" + TestBase.CLUSTER_PLATFORM + "/modules/org-netbeans-swing-plaf.jar")); + expectedRoots.add(urlForJar("nbbuild/netbeans/" + TestBase.CLUSTER_PLATFORM + "/modules/org-openide-text.jar")); + +// assertEquals("right COMPILE classpath", expectedRoots.toString(), urlsOfCp4Tests(cp).toString()); + assertSets("right COMPILE classpath", expectedRoots, urlsOfCp4Tests(cp)); + cp = ClassPath.getClassPath(src, ClassPath.EXECUTE); assertNotNull("have an EXECUTE classpath", cp); expectedRoots.add(urlForDir("autoupdate/build/test/unit/classes")); // test.unit.run.cp.extra: expectedRoots.add(urlForJar("nbbuild/netbeans/" + TestBase.CLUSTER_PLATFORM + "/lib/boot.jar")); - assertEquals("right EXECUTE classpath (COMPILE plus classes)", expectedRoots.toString(), urlsOfCp4Tests(cp).toString()); +// assertEquals("right EXECUTE classpath (COMPILE plus classes)", expectedRoots.toString(), urlsOfCp4Tests(cp).toString()); + assertSets("right EXECUTE classpath (COMPILE plus classes)", expectedRoots, urlsOfCp4Tests(cp)); cp = ClassPath.getClassPath(src, ClassPath.SOURCE); assertNotNull("have a SOURCE classpath", cp); assertEquals("right SOURCE classpath", Collections.singleton(src), new HashSet(Arrays.asList(cp.getRoots()))); @@ -424,6 +453,7 @@ assertNull ("ClassPath.SOURCE for build/test must be null",ClassPath.getClassPath(testBuildClasses, ClassPath.SOURCE)); assertNull ("ClassPath.COMPILE for build/test must be null",ClassPath.getClassPath(testBuildClasses, ClassPath.COMPILE)); cp = ClassPath.getClassPath(testBuildClasses, ClassPath.EXECUTE); + String path = ((NbModuleProject)prj).evaluator().getProperty("test.unit.run.cp.extra"); //NOI18N List trExtra = new ArrayList (); if (path != null) { @@ -448,6 +478,7 @@ ClassPathSupport.createClassPath(new FileObject[] {testBuildClasses}), tccp, ClassPathSupport.createClassPath(trExtra), + ClassPathSupport.createClassPath(new URL[] {new URL(urlForJar("nbbuild/netbeans/" + TestBase.CLUSTER_PLATFORM + "/modules/org-netbeans-modules-masterfs.jar"))}) }); assertClassPathsHaveTheSameResources(cp, expectedCp); @@ -594,7 +625,8 @@ } private void assertClassPathsHaveTheSameResources(ClassPath actual, ClassPath expected) { - assertEquals(urlsOfCp(expected).toString(), urlsOfCp(actual).toString()); +// assertEquals(urlsOfCp(expected).toString(), urlsOfCp(actual).toString()); + assertSets("cls: ",urlsOfCp(expected), urlsOfCp(actual)); } public void testTransitiveExecuteClasspath() throws Exception { // #70206 Index: src/org/netbeans/modules/apisupport/project/Evaluator.java =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/Evaluator.java,v retrieving revision 1.8 diff -u -r1.8 Evaluator.java --- src/org/netbeans/modules/apisupport/project/Evaluator.java 30 Jun 2006 18:12:11 -0000 1.8 +++ src/org/netbeans/modules/apisupport/project/Evaluator.java 20 Jul 2006 09:13:30 -0000 @@ -45,6 +45,7 @@ import org.netbeans.api.java.platform.JavaPlatform; import org.netbeans.api.java.platform.JavaPlatformManager; import org.netbeans.api.project.ProjectManager; +import org.netbeans.modules.apisupport.project.universe.TestModuleDependency; import org.netbeans.modules.apisupport.project.universe.ModuleEntry; import org.netbeans.modules.apisupport.project.universe.ModuleList; import org.netbeans.spi.project.support.ant.AntProjectEvent; @@ -81,6 +82,32 @@ /** See issue #69440 for more details. */ private boolean runInAtomicAction; + static class TestClasspath { + String compile; + String runtime; + String testCompile; + String testRuntime; + public TestClasspath() { + compile = ""; + runtime = ""; + testCompile = ""; + testRuntime = ""; + } + public String getCompileClasspath() { + return compile + ":" + testCompile; + } + public String getRuntimeClasspath() { + return runtime + ":" + testRuntime; + } + + private static TestClasspath getOrEmpty(Map testsCPs, String testtype) { + TestClasspath tcp = (TestClasspath) testsCPs.get(testtype); + if (tcp == null ) { + tcp = new TestClasspath(); + } + return tcp; + } + } public Evaluator(NbModuleProject project, NbModuleTypeProvider typeProvider) { this.project = project; this.typeProvider = typeProvider; @@ -303,6 +330,7 @@ buildDefaults.put("cp.extra", ""); // NOI18N buildDefaults.put("cp", "${module.classpath}:${cp.extra}"); // NOI18N buildDefaults.put("run.cp", computeRuntimeModuleClasspath(ml) + ":${cp.extra}:${build.classes.dir}"); // NOI18N + baseEval = PropertyUtils.sequentialPropertyEvaluator(predefs, (PropertyProvider[]) providers.toArray(new PropertyProvider[providers.size()])); buildDefaults.put("test.unit.cp.extra", ""); // NOI18N String testJars; // #68685 - follow Ant script @@ -339,9 +367,12 @@ "${netbeans.user}/modules/org-netbeans-modules-nbjunit.jar:" + // NOI18N, new for 6.0 "${netbeans.user}/modules/org-netbeans-modules-nbjunit-ide.jar"; // NOI18N, new for 6.0 } - buildDefaults.put("test.unit.cp", "${cp}:${cluster}/${module.jar}:" + testJars + ":${test.unit.cp.extra}"); // NOI18N + Map/**/ testsCPs = computeTestingClassPaths(ml,baseEval); + TestClasspath tcp = TestClasspath.getOrEmpty(testsCPs,"unit"); + + buildDefaults.put("test.unit.cp", "${cp}:${cluster}/${module.jar}:" + testJars + ":${test.unit.cp.extra}:" + tcp.getCompileClasspath()); // NOI18N buildDefaults.put("test.unit.run.cp.extra", ""); // NOI18N - buildDefaults.put("test.unit.run.cp", "${test.unit.cp}:${build.test.unit.classes.dir}:${test.unit.run.cp.extra}"); // NOI18N + buildDefaults.put("test.unit.run.cp", "${test.unit.cp}:${build.test.unit.classes.dir}:${test.unit.run.cp.extra}:"+ tcp.getRuntimeClasspath()); // NOI18N // #61085: need to treat qa-functional tests the same way... buildDefaults.put("test.qa-functional.cp.extra", ""); // NOI18N // No idea how XTest finds these, some weird magic, so no Ant script to match up to: @@ -353,14 +384,16 @@ if (jelly2NbJar != null) { buildDefaults.put("jelly2-nb.jar", jelly2NbJar); // NOI18N } + tcp = TestClasspath.getOrEmpty(testsCPs,"qa-functional"); buildDefaults.put("test.qa-functional.cp", testJars + // NOI18N ":${netbeans.home}/../testtools/modules/ext/nbjunit-ide.jar" + // NOI18N ":${netbeans.user}/testtools/modules/ext/nbjunit.jar" + // NOI18N ":${jemmy.jar}" + // NOI18N ":${jelly2-nb.jar}" + // NOI18N - ":${test.qa-functional.cp.extra}"); // NOI18N + ":${test.qa-functional.cp.extra}:" + + tcp.compile + ":" + tcp.testCompile); // NOI18N buildDefaults.put("build.test.qa-functional.classes.dir", "build/test/qa-functional/classes"); // NOI18N - buildDefaults.put("test.qa-functional.run.cp", "${test.qa-functional.cp}:${build.test.qa-functional.classes.dir}"); // NOI18N + buildDefaults.put("test.qa-functional.run.cp", "${test.qa-functional.cp}:${build.test.qa-functional.classes.dir}" + ":" + tcp.runtime + ":" + tcp.testRuntime); // NOI18N providers.add(PropertyUtils.fixedPropertyProvider(buildDefaults)); } // skip a bunch of properties irrelevant here - NBM stuff, etc. @@ -618,5 +651,183 @@ } return cp.toString(); } + + // + /** parse classpath for tests from project.xml + * @retun Map String testtype -> TestClasspath + */ + private Map computeTestingClassPaths(ModuleList ml,PropertyEvaluator evaluator) { + + + Map /**/ classpaths = new HashMap(); + Map /*>*/ testTypes = getTestDependencies(ml); + + String testDistDir = evaluator.getProperty("test.dist.dir"); // NOI18N + if (testDistDir == null) { + NbModuleTypeProvider.NbModuleType type = typeProvider.getModuleType(); + if (type == NbModuleTypeProvider.NETBEANS_ORG) { + // test.dist.dir = ${nb_all}/nbbuild/build/testdist + String nball = evaluator.getProperty("nb_all"); // NOI18N + testDistDir = nball + File.separatorChar + "nbbuild" + File.separatorChar + "build" + File.separatorChar + "testdist"; // NOI18N + } else if ( type == NbModuleTypeProvider.SUITE_COMPONENT) { + // test.dist.dir = ${suite.dir}/build/testdist + String suiteDir = evaluator.getProperty("suite.dir"); // NOI18N + testDistDir = suiteDir + File.separatorChar + "build" + File.separatorChar + "testdist"; // NOI18N + } else { + // standalone module + // test.dist.dir = ${module.dir}/build/testdist + String moduleDir = evaluator.getProperty("module.dir"); // NOI18N + testDistDir = moduleDir + File.separatorChar + "build" + File.separatorChar + "testdist"; + } + } + for (Iterator ttIt = testTypes.entrySet().iterator() ; ttIt.hasNext() ; ) { + Map.Entry entry = (Map.Entry) ttIt.next(); + String ttName = (String)entry.getKey(); + Set ttModules = (Set)entry.getValue(); + computeTestType(ttName,new File(testDistDir),ttModules,classpaths,ml); + } + return classpaths; + } + private Map /*>*/getTestDependencies(ModuleList ml) { + Element data = project.getHelper().getPrimaryConfigurationData(true); + Element pp = Util.findElement(data, + "test-dependencies", NbModuleProjectType.NAMESPACE_SHARED); // NOI18N + + Map/*>*/ testDeps = new HashMap(); + + if (pp != null) { + for (Iterator depssIt = Util.findSubElements(pp).iterator(); depssIt.hasNext();) { + Element depssEl = (Element) depssIt.next(); + Element testTypeEl = Util.findElement(depssEl,"name",NbModuleProjectType.NAMESPACE_SHARED); + String testType = null; + if (testTypeEl != null) { + testType = Util.findText(testTypeEl); + } + if (testType == null) { + testType = TestModuleDependency.UNIT; // default variant + } + Set/**/ directTestDeps = new HashSet(); + + testDeps.put(testType,directTestDeps); + for (Iterator depsIt = Util.findSubElements(depssEl).iterator() ; depsIt.hasNext();) { + Element el = (Element) depsIt.next(); + if (el.getTagName().equals("test-dependency")) { + // parse test dep + boolean test = Util.findElement(el,"test",NbModuleProjectType.NAMESPACE_SHARED) != null; + Element cnbEl = Util.findElement(el,"code-name-base",NbModuleProjectType.NAMESPACE_SHARED); + + String cnb = null; + if (cnbEl != null) { + cnb = Util.findText(cnbEl); + } + boolean recursive = Util.findElement(el,"recursive",NbModuleProjectType.NAMESPACE_SHARED) != null; + boolean compile = Util.findElement(el,"compile-dependency",NbModuleProjectType.NAMESPACE_SHARED) != null; + if (cnb != null) { + ModuleEntry me = ml.getEntry(cnb); + // [TOOD] show error module is + if (me != null) { + directTestDeps.add(new TestModuleDependency(me,test,recursive,compile)); + } + } + } + } + } + } + return testDeps; + } + + + private void computeTestType(String ttName,File testDistDir, Set ttModules, Map/**/ classpaths,ModuleList ml) { + + Set compileCnds = new HashSet(); + Set runtimeCnds = new HashSet(); + Set testCompileCnds = new HashSet(); + Set testRuntimeCnds = new HashSet(); + + Set processedRecursive = new HashSet(); + for (Iterator it = ttModules.iterator() ; it.hasNext();) { + TestModuleDependency td = (TestModuleDependency) it.next(); + String cnd = td.getModule().getCodeNameBase(); + if (td.isTest()) { + if (td.isCompile()) { + testCompileCnds.add(cnd); + } + testRuntimeCnds.add(cnd); + } + if (td.isRecursive()) { + // scan cp recursively + processTestEntryRecursive(td,compileCnds,runtimeCnds,processedRecursive,ml); + } else { + runtimeCnds.add(cnd); + if (td.isCompile()) { + compileCnds.add(cnd); + } + } + } + TestClasspath testClasspath = new TestClasspath(); + testClasspath.compile = mergePaths(compileCnds,false,ttName,testDistDir, ml); + testClasspath.runtime = mergePaths(runtimeCnds,false,ttName,testDistDir,ml); + testClasspath.testCompile = mergePaths(testCompileCnds,true,ttName,testDistDir,ml); + testClasspath.testRuntime = mergePaths(testRuntimeCnds,true,ttName,testDistDir,ml); + + classpaths.put(ttName,testClasspath); + } + + private void processTestEntryRecursive(TestModuleDependency td, + Set compileCnds, + Set runtimeCnds, + Set processedRecursive, + ModuleList ml) { + Set/**/ unprocessed = new HashSet(); + + unprocessed.add(td.getModule().getCodeNameBase()); + while (!unprocessed.isEmpty()) { // crude breadth-first search + Iterator it = unprocessed.iterator(); + String cnb = (String) it.next(); + it.remove(); + if (processedRecursive.add(cnb)) { + ModuleEntry module = ml.getEntry(cnb); + if (module == null) { + Util.err.log(ErrorManager.WARNING, "Warning - could not find dependent module " + cnb + " for " + FileUtil.getFileDisplayName(project.getProjectDirectory())); + continue; + } + if (!cnb.equals(project.getCodeNameBase())) { // build/classes for this is special + runtimeCnds.add(cnb); + if (td.isCompile()) { + compileCnds.add(cnb); + } + } + String[] newDeps = module.getRunDependencies(); + unprocessed.addAll(Arrays.asList(newDeps)); + } + } + } + + private String mergePaths(Set cnbs, boolean test,String testtype,File testDistDir,ModuleList ml) { + StringBuffer cps = new StringBuffer(); + for (Iterator it = cnbs.iterator() ; it.hasNext();) { + String cnb = (String)it.next(); + ModuleEntry module = (ModuleEntry)ml.getEntry(cnb); + if (cps.length() > 0) { + cps.append(":"); + } + if (test) { + // we need to get cluster name + File clusterDir = module.getClusterDirectory(); + if (clusterDir != null) { + String clusterName = clusterDir.getName(); + char s = File.separatorChar; + File jarFile = new File( + testDistDir, testtype + s + clusterName + s + cnb.replace('.','-') + s + "tests.jar"); + cps.append(jarFile.getPath()); + } + + } else { + cps.append(module.getJarLocation().getPath()); + } + } + return cps.toString(); + } + }