blob: 696ed77b5cac2dd8addaab663474b55f3833d103 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.junit;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import junit.framework.Assert;
import junit.framework.AssertionFailedError;
import junit.framework.Protectable;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestFailure;
import junit.framework.TestResult;
import org.netbeans.junit.internal.NbModuleLogHandler;
/**
* Wraps a test class with proper NetBeans Runtime Container environment.
* This allows to execute tests in a very similar environment to the
* actual invocation in the NetBeans IDE. To use write your test as
* you are used to and add suite static method:
* <pre>
* public class YourTest extends NbTestCase {
* public YourTest(String s) { super(s); }
*
* public static Test suite() {
* return NbModuleSuite.create(YourTest.class);
* }
*
* public void testXYZ() { ... }
* public void testABC() { ... }
* }
* </pre>
* For more advanced configuration see {@link #emptyConfiguration()} and {@link Configuration}.
*
* @since 1.46
* @author Jaroslav Tulach <jaroslav.tulach@netbeans.org>
*/
public class NbModuleSuite {
private static final Logger LOG;
static {
System.setProperty("org.netbeans.MainImpl.154417", "true");
LOG = Logger.getLogger(NbModuleSuite.class.getName());
}
private NbModuleSuite() {}
/** Settings object that allows one to configure execution of
* whole {@link NbModuleSuite}. Chain the method invocations
* (each method returns new instance of {@link Configuration})
* and call {@link #suite()} at the end to generate the final
* JUnit test class.
*
* @since 1.48
*/
public static final class Configuration extends Object {
final List<Item> tests;
final Class<? extends TestCase> latestTestCaseClass;
final List<String> clusterRegExp;
/** each odd is cluster reg exp, each even is module reg exp */
final List<String> moduleRegExp;
final List<String> startupArgs;
final ClassLoader parentClassLoader;
final boolean reuseUserDir;
final boolean gui;
final boolean enableClasspathModules;
final boolean honorAutoEager;
final boolean hideExtraModules;
final Level failOnMessage;
final Level failOnException;
private Configuration(
List<String> clusterRegExp,
List<String> moduleRegExp,
List<String> startupArgs,
ClassLoader parent,
List<Item> testItems,
Class<? extends TestCase> latestTestCase,
boolean reuseUserDir,
boolean gui,
boolean enableCPModules,
boolean honorAutoEager,
Level failOnMessage,
Level failOnException,
boolean hideExtraModules
) {
this.clusterRegExp = clusterRegExp;
this.moduleRegExp = moduleRegExp;
this.startupArgs = startupArgs;
this.parentClassLoader = parent;
this.tests = testItems;
this.reuseUserDir = reuseUserDir;
this.latestTestCaseClass = latestTestCase;
this.gui = gui;
this.enableClasspathModules = enableCPModules;
this.honorAutoEager = honorAutoEager;
this.failOnException = failOnException;
this.failOnMessage = failOnMessage;
this.hideExtraModules = hideExtraModules;
}
static Configuration create(Class<? extends TestCase> clazz) {
return new Configuration(
null, null, null, ClassLoader.getSystemClassLoader().getParent(),
Collections.<Item>emptyList(), clazz, false, true, true, false
, null, null, false);
}
/** Regular expression to match clusters that shall be enabled.
* To enable all cluster, one can use <code>".*"</code>. To enable
* ide and java clusters, it is handy to pass in <code>"ide|java"</code>.
* There is no need to request presence of <code>platform</code> cluster,
* as that is available all the time by default.
* <p>
* Since version 1.55 this method can be called multiple times.
*
* @param regExp regular expression to match cluster names
* @return clone of this configuration with cluster set to regExp value
*/
public Configuration clusters(String regExp) {
ArrayList<String> list = new ArrayList<String>();
if (clusterRegExp != null) {
list.addAll(clusterRegExp);
}
if (regExp != null) {
list.add(regExp);
}
if (list.isEmpty()) {
list = null;
}
return new Configuration(
list, moduleRegExp, startupArgs, parentClassLoader, tests,
latestTestCaseClass, reuseUserDir, gui, enableClasspathModules,
honorAutoEager
, failOnMessage, failOnException, hideExtraModules);
}
/** By default only modules on classpath of the test are enabled,
* the rest are just autoloads. If you need to enable more, you can
* specify that with this method. To enable all available modules
* in all clusters pass in <code>".*"</code>. Since 1.55 this method
* is cummulative.
*
* @param regExp regular expression to match code name base of modules
* @return clone of this configuration with enable modules set to regExp value
*/
public Configuration enableModules(String regExp) {
if (regExp == null) {
return this;
}
return enableModules(".*", regExp);
}
/** By default only modules on classpath of the test are enabled,
* the rest are just autoloads. If you need to enable more, you can
* specify that with this method. To enable all available modules in
* one cluster, use this method and pass <code>".*"</code> as list of
* modules. This method is cumulative.
*
* @param clusterRegExp regular expression to match clusters
* @param moduleRegExp regular expression to match code name base of modules
* @return clone of this configuration with enable modules set to regExp value
* @since 1.55
*/
public Configuration enableModules(String clusterRegExp, String moduleRegExp) {
List<String> arr = new ArrayList<String>();
if (this.moduleRegExp != null) {
arr.addAll(this.moduleRegExp);
}
arr.add(clusterRegExp);
arr.add(moduleRegExp);
return new Configuration(
this.clusterRegExp, arr, startupArgs, parentClassLoader,
tests, latestTestCaseClass, reuseUserDir, gui,
enableClasspathModules, honorAutoEager, failOnMessage,
failOnException, hideExtraModules);
}
/**
* Appends one or more command line arguments which will be used to
* start the application. Arguments which take a parameter should
* usually be specified as two separate strings. Also note that this
* method cannot handle arguments which must be passed directly to the
* JVM (such as memory settings or system properties), those should be
* instead specified in the <code>test.run.args</code> property (e.g.
* in the module's <code>project.properties</code> file).
*
* @param arguments command line arguments to append; each value
* specified here will be passed a separate argument when starting
* the application under test.
* @return clone of this configuration object with the specified
* command line arguments appended to any which may have already
* been present
* @since 1.67
*/
public Configuration addStartupArgument(String... arguments) {
if (arguments == null || arguments.length < 1){
throw new IllegalStateException("Must specify at least one startup argument");
}
List<String> newArgs = new ArrayList<String>();
if (startupArgs != null) {
newArgs.addAll(startupArgs);
}
newArgs.addAll(Arrays.asList(arguments));
return new Configuration(
clusterRegExp, moduleRegExp, newArgs, parentClassLoader,
tests, latestTestCaseClass, reuseUserDir, gui,
enableClasspathModules, honorAutoEager, failOnMessage,
failOnException, hideExtraModules);
}
Configuration classLoader(ClassLoader parent) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parent, tests,
latestTestCaseClass, reuseUserDir, gui, enableClasspathModules,
honorAutoEager
, failOnMessage, failOnException, hideExtraModules);
}
/** Adds new test name, or array of names into the configuration. By
* default the suite executes all <code>testXYZ</code>
* methods present in the test class
* (the one passed into {@link Configuration#create(java.lang.Class)}
* method). However if there is a need to execute just some of them,
* one can use this method to explicitly enumerate them by subsequent
* calls to <code>addTest</code> method.
* @param testNames list names to add to the test execution
* @return clone of this configuration with testNames test added to the
* list of executed tests
*/
public Configuration addTest(String... testNames) {
if (latestTestCaseClass == null){
throw new IllegalStateException();
}
List<Item> newTests = new ArrayList<Item>(tests);
newTests.add(new Item(true, latestTestCaseClass, testNames));
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
newTests, latestTestCaseClass, reuseUserDir, gui,
enableClasspathModules, honorAutoEager, failOnMessage,
failOnException, hideExtraModules);
}
/** Adds new test class to run, together with a list of its methods
* that shall be executed. The list can be empty and if so, the
* the suite executes all <code>testXYZ</code>
* methods present in the test class.
*
* @param test the class to also execute in this suite
* @param testNames list names to add to the test execution
* @return clone of this configuration with testNames test added to the
* list of executed tests
* @since 1.50
*/
public Configuration addTest(Class<? extends TestCase> test, String... testNames) {
if (test.equals(latestTestCaseClass)){
return addTest(testNames);
}
List<Item> newTests = new ArrayList<Item>(tests);
addLatest(newTests);
if ((testNames != null) && (testNames.length != 0)){
newTests.add(new Item(true, test, testNames));
}
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
newTests, test, reuseUserDir, gui, enableClasspathModules,
honorAutoEager
, failOnMessage, failOnException, hideExtraModules);
}
/**
* Add new {@link junit.framework.Test} to run. The implementation must
* have no parameter constructor. TastCase can be also passed as an argument
* of this method than it's delegated to
* {@link Configuration#addTest(java.lang.Class, java.lang.String[]) }
*
* @param test Test implementation to add
* @return clone of this configuration with new Test added to the list
* of executed tests
* @since 1.50
*/
public Configuration addTest(Class<? extends Test> test) {
if (TestCase.class.isAssignableFrom(test)){
Class<? extends TestCase> tc = test.asSubclass(TestCase.class);
return addTest(tc, new String[0]);
}
List<Item> newTests = new ArrayList<Item>(tests);
newTests.add(new Item(false, test, null));
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
newTests, latestTestCaseClass, reuseUserDir,
gui, enableClasspathModules, honorAutoEager
, failOnMessage, failOnException, hideExtraModules);
}
/** By default all modules on classpath are enabled (so you can link
* with modules that you compile against), this method allows you to
* disable this feature, which is useful if the test is known to not
* link against any of classpath classes.
*
* @param enable pass false to ignore modules on classpath
* @return new configuration clone
* @since 1.56
*/
public Configuration enableClasspathModules(boolean enable) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
tests, latestTestCaseClass, reuseUserDir,
gui, enable, honorAutoEager, failOnMessage, failOnException, hideExtraModules);
}
/** By default the {@link #enableModules(java.lang.String)} method
* converts all autoloads into regular modules and enables them. This
* is maybe useful in certain situations, but does not really mimic the
* real behaviour of the system when it is executed. Those who need
* to as closely as possible simulate the real run, can use
* <code>honorAutoloadEager(true)</code>.
*
* @param honor true in case autoloads shall remain autoloads and eager modules eager
* @return new configuration filled with this data
* @since 1.57
*/
public Configuration honorAutoloadEager(boolean honor) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
tests, latestTestCaseClass, reuseUserDir,
gui, enableClasspathModules, honor
, failOnMessage, failOnException, hideExtraModules);
}
/** Allows to limit what modules get enabled in the system.
* The original purpose of {@link NbModuleSuite} was to enable
* as much of modules as possible. This was believed to
* resemble the real situation in the running application the best.
* However it turned out there
* are situations when too much modules can break the system
* and it is necessary to prevent loading some of them.
* This method can achieve that.
* <p>
* The primary usage is for <em>Ant</em> based harness. It usually
* contains full installation of various clusters and the application
* picks just certain modules from that configuration.
* <code>hideExtraModules(true)</code> allows exclusion of these
* modules as well.
* <p>
* The usefulness of this method in <em>Maven</em> based environment
* is not that big. Usually the nbm plugin makes only necessary
* JARs available. In combination with {@link #enableClasspathModules(boolean)
* enableClasspathModules(false)}, it may give you a subset of
* the Platform loaded in a test. In a
* Maven-based app declaring a dependency on the whole
* org.netbeans.cluster:platform use the following suite expression:
* <pre>
* NbModuleSuite.createConfiguration(ApplicationTest.class).
* gui(true).
* hideExtraModules(true).
* enableModules("(?!org.netbeans.modules.autoupdate|org.netbeans.modules.core.kit|org.netbeans.modules.favorites).*").
* enableClasspathModules(false).
* suite();
* </pre>
*
* @param hide true if all enabled not explicitly requested modules should
* be hidden
* @return new configuration with holds the provided parameter
* @since 1.72
*/
public Configuration hideExtraModules(boolean hide) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
tests, latestTestCaseClass, reuseUserDir,
gui, enableClasspathModules, honorAutoEager, failOnMessage,
failOnException, hide);
}
/** Fails if there is a message sent to {@link Logger} with appropriate
* level or higher during the test run execution.
*
* @param level the minimal level of the message
* @return new configuration filled with this data
* @since 1.58
*/
public Configuration failOnMessage(Level level) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
tests, latestTestCaseClass, reuseUserDir,
gui, enableClasspathModules, honorAutoEager
, level, failOnException, hideExtraModules);
}
/** Fails if there is an exception reported to {@link Logger} with appropriate
* level or higher during the test run execution.
*
* @param level the minimal level of the message
* @return new configuration filled with this data
* @since 1.58
*/
public Configuration failOnException(Level level) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
tests, latestTestCaseClass, reuseUserDir,
gui, enableClasspathModules, honorAutoEager
, failOnMessage, level, hideExtraModules);
}
private void addLatest(List<Item> newTests) {
if (latestTestCaseClass == null){
return;
}
for (Item item : newTests) {
if (item.clazz.equals(latestTestCaseClass)){
return;
}
}
newTests.add(new Item(true, latestTestCaseClass, null));
}
private Configuration getReady() {
List<Item> newTests = new ArrayList<Item>(tests);
addLatest(newTests);
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
newTests, latestTestCaseClass, reuseUserDir, gui,
enableClasspathModules
,honorAutoEager, failOnMessage, failOnException, hideExtraModules);
}
/** Should the system run with GUI or without? The default behaviour
* does not prevent any module to show UI. If <code>false</code> is
* used, then the whole system is instructed with <code>--nogui</code>
* option that it shall run as much as possible in invisible mode. As
* a result, the main window is not shown after the start, for example.
*
* @param gui true or false
* @return clone of this configuration with gui mode associated
*/
public Configuration gui(boolean gui) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader,
tests, latestTestCaseClass, reuseUserDir, gui,
enableClasspathModules
,honorAutoEager, failOnMessage, failOnException, hideExtraModules);
}
/**
* Enables or disables userdir reuse. By default it is disabled.
* @param reuse true or false
* @return clone of this configuration with userdir reuse mode associated
* @since 1.52
*/
public Configuration reuseUserDir(boolean reuse) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentClassLoader, tests,
latestTestCaseClass, reuse, gui, enableClasspathModules
,honorAutoEager, failOnMessage, failOnException, hideExtraModules);
}
/**
* Sets the parent ClassLoader on which the NB platform should start.
* @param parentCL the parent ClassLoader
* @return clone of this configuration with the parent ClassLoader set
* @since 1.91
*/
public Configuration parentClassLoader(ClassLoader parentCL) {
return new Configuration(
clusterRegExp, moduleRegExp, startupArgs, parentCL, tests,
latestTestCaseClass, reuseUserDir, gui, enableClasspathModules
,honorAutoEager, failOnMessage, failOnException, hideExtraModules);
}
/**
* Creates a test suite from this configuration.
* Same as {@link #create(org.netbeans.junit.NbModuleSuite.Configuration)} but more fluid.
* @return a suite ready for returning from a {@code public static Test suite()} method
* @since org.netbeans.modules.junit/1 1.70
*/
public Test suite() {
return new S(this);
}
}
/** Factory method to create wrapper test that knows how to setup proper
* NetBeans Runtime Container environment.
* Wraps the provided class into a test that set ups properly the
* testing environment. The set of enabled modules is going to be
* determined from the actual classpath of a module, which is common
* when in all NetBeans tests. All other modules are kept disabled.
* In addition,it allows one limit the clusters that shall be made available.
* For example <code>ide|java</code> will start the container just
* with platform, ide and java clusters.
*
*
* @param clazz the class with bunch of testXYZ methods
* @param clustersRegExp regexp to apply to name of cluster to find out if it is supposed to be included
* in the runtime container setup or not
* @param moduleRegExp by default all modules on classpath are turned on,
* however this regular expression can specify additional ones. If not
* null, the specified cluster will be searched for modules with such
* codenamebase and those will be turned on
* @return runtime container ready test
*/
public static Test create(Class<? extends TestCase> clazz, String clustersRegExp, String moduleRegExp) {
return Configuration.create(clazz).clusters(clustersRegExp).enableModules(moduleRegExp).suite();
}
/** Factory method to create wrapper test that knows how to setup proper
* NetBeans Runtime Container environment.
* Wraps the provided class into a test that set ups properly the
* testing environment. The set of enabled modules is going to be
* determined from the actual classpath of a module, which is common
* when in all NetBeans tests. All other modules are kept disabled.
* In addition,it allows one limit the clusters that shall be made available.
* For example <code>ide|java</code> will start the container just
* with platform, ide and java clusters.
*
*
* @param clazz the class with bunch of testXYZ methods
* @param clustersRegExp regexp to apply to name of cluster to find out if it is supposed to be included
* in the runtime container setup or not
* @param moduleRegExp by default all modules on classpath are turned on,
* however this regular expression can specify additional ones. If not
* null, the specified cluster will be searched for modules with such
* codenamebase and those will be turned on
* @param tests names of test methods to execute from the <code>clazz</code>, if
* no test methods are specified, all tests in the class are executed
* @return runtime container ready test
* @since 1.49
*/
public static Test create(Class<? extends TestCase> clazz, String clustersRegExp, String moduleRegExp, String... tests) {
Configuration conf = Configuration.create(clazz).clusters(clustersRegExp).enableModules(moduleRegExp);
if (tests.length > 0) {
conf = conf.addTest(tests);
}
return conf.suite();
}
/** Factory method to create wrapper test that knows how to setup proper
* NetBeans Runtime Container environment.
* Wraps the provided class into a test that set ups properly the
* testing environment. All modules, in all clusters,
* in the tested applicationwill be included in the test.
*
* @param clazz the class with bunch of testXYZ methods
* @param tests names of test methods to execute from the <code>clazz</code>, if
* no test methods are specified, all tests in the class are executed
* @return runtime container ready test
* @since 1.49
*/
public static Test allModules(Class<? extends TestCase> clazz, String... tests) {
return create(clazz, ".*", ".*", tests);
}
/** Creates default configuration wrapping a class that can be executed
* with the {@link NbModuleSuite} support.
*
* @param clazz the class to test, the actual instances will be created
* for the class of the same name, but loaded by different classloader
* @return config object prefilled with default values; the defaults may
* be altered with its addition instance methods
* @since 1.48
*/
public static Configuration createConfiguration(Class<? extends TestCase> clazz) {
return Configuration.create(clazz);
}
/** Creates empty configuration without any class assiciated. You need
* to call {@link Configuration#addTest(java.lang.Class, java.lang.String[])}
* then to register proper test classes.
*
* @return config object prefilled with default values; the defaults may
* be altered with its addition instance methods
* @since 1.50
*/
public static Configuration emptyConfiguration() {
return Configuration.create(null);
}
/** Factory method to create wrapper test that knows how to setup proper
* NetBeans Runtime Container environment. This method allows better
* customization and control over the executed set of tests.
* Wraps the provided class into a test that set ups properly the
* testing environment, read more in {@link Configuration}.
*
*
* @param config the configuration for the test
* @return runtime container ready test
* @since 1.48
* @see Configuration#suite
*/
public static Test create(Configuration config) {
return config.suite();
}
private static final class Item {
boolean isTestCase;
Class<?> clazz;
String[] fileNames;
public Item(boolean isTestCase, Class<?> clazz, String[] fileNames) {
this.isTestCase = isTestCase;
this.clazz = clazz;
this.fileNames = fileNames;
}
}
static final class S extends NbTestSuite {
final Configuration config;
private static int invocations;
private static File lastUserDir;
private int testCount = 0;
public S(Configuration config) {
this.config = config.getReady();
}
@Override
public int countTestCases() {
return testCount;
}
@Override
public void run(final TestResult result) {
result.runProtected(this, new Protectable() {
public @Override void protect() throws Throwable {
ClassLoader before = Thread.currentThread().getContextClassLoader();
try {
runInRuntimeContainer(result);
} finally {
Thread.currentThread().setContextClassLoader(before);
}
}
});
}
private static String[] tokenizePath(String path) {
List<String> l = new ArrayList<String>();
StringTokenizer tok = new StringTokenizer(path, ":;", true); // NOI18N
char dosHack = '\0';
char lastDelim = '\0';
int delimCount = 0;
while (tok.hasMoreTokens()) {
String s = tok.nextToken();
if (s.length() == 0) {
// Strip empty components.
continue;
}
if (s.length() == 1) {
char c = s.charAt(0);
if (c == ':' || c == ';') {
// Just a delimiter.
lastDelim = c;
delimCount++;
continue;
}
}
if (dosHack != '\0') {
// #50679 - "C:/something" is also accepted as DOS path
if (lastDelim == ':' && delimCount == 1 && (s.charAt(0) == '\\' || s.charAt(0) == '/')) {
// We had a single letter followed by ':' now followed by \something or /something
s = "" + dosHack + ':' + s;
// and use the new token with the drive prefix...
} else {
// Something else, leave alone.
l.add(Character.toString(dosHack));
// and continue with this token too...
}
dosHack = '\0';
}
// Reset count of # of delimiters in a row.
delimCount = 0;
if (s.length() == 1) {
char c = s.charAt(0);
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
// Probably a DOS drive letter. Leave it with the next component.
dosHack = c;
continue;
}
}
l.add(s);
}
if (dosHack != '\0') {
//the dosHack was the last letter in the input string (not followed by the ':')
//so obviously not a drive letter.
//Fix for issue #57304
l.add(Character.toString(dosHack));
}
return l.toArray(new String[l.size()]);
}
static void findClusters(Collection<File> clusters, List<String> regExps) throws IOException {
File plat = findPlatform().getCanonicalFile();
String selectiveClusters = System.getProperty("cluster.path.final"); // NOI18N
Set<File> path;
if (selectiveClusters != null) {
path = new TreeSet<File>();
for (String p : tokenizePath(selectiveClusters)) {
File f = new File(p);
path.add(f.getCanonicalFile());
}
} else {
File parent;
String allClusters = System.getProperty("all.clusters"); // #194794
if (allClusters != null) {
parent = new File(allClusters);
} else {
parent = plat.getParentFile();
}
path = new TreeSet<File>(Arrays.asList(parent.listFiles()));
}
for (String c : regExps) {
for (File f : path) {
if (f.equals(plat)) {
continue;
}
if (!f.getName().matches(c)) {
continue;
}
File m = new File(new File(f, "config"), "Modules");
if (m.exists()) {
clusters.add(f);
}
}
}
}
private void runInRuntimeContainer(TestResult result) throws Exception {
System.getProperties().remove("netbeans.dirs");
File platform = findPlatform();
List<URL> bootCP = new ArrayList<URL>();
List<File> dirs = new ArrayList<File>();
dirs.add(new File(platform, "lib"));
File jdkHome = new File(System.getProperty("java.home"));
if (new File(jdkHome.getParentFile(), "lib").exists()) {
jdkHome = jdkHome.getParentFile();
}
dirs.add(new File(jdkHome, "lib"));
//in case we're running code coverage, load the coverage libraries
if (System.getProperty("code.coverage.classpath") != null) {
dirs.add(new File(System.getProperty("code.coverage.classpath")));
}
for (File dir: dirs) {
File[] jars = dir.listFiles();
if (jars != null) {
for (File jar : jars) {
if (jar.getName().endsWith(".jar")) {
bootCP.add(toURI(jar).toURL());
}
}
}
}
// loader that does not see our current classloader
JUnitLoader junit = new JUnitLoader(config.parentClassLoader, NbModuleSuite.class.getClassLoader());
URLClassLoader loader = new URLClassLoader(bootCP.toArray(new URL[0]), junit);
Class<?> main = loader.loadClass("org.netbeans.Main"); // NOI18N
Assert.assertEquals("Loaded by our classloader", loader, main.getClassLoader());
Method m = main.getDeclaredMethod("main", String[].class); // NOI18N
System.setProperty("java.util.logging.config", "-");
System.setProperty("netbeans.logger.console", "true");
if (System.getProperty("netbeans.logger.noSystem") == null) {
System.setProperty("netbeans.logger.noSystem", "true");
}
System.setProperty("netbeans.home", platform.getPath());
System.setProperty("netbeans.full.hack", "true");
String branding = System.getProperty("branding.token"); // NOI18N
if (branding != null) {
try {
Method setBranding = loader.loadClass("org.openide.util.NbBundle").getMethod("setBranding", String.class); // NOI18N
setBranding.invoke(null, branding);
} catch (Throwable ex) {
if (ex instanceof InvocationTargetException) {
ex = ((InvocationTargetException)ex).getTargetException();
}
LOG.log(Level.WARNING, "Cannot set branding to " + branding, ex); // NOI18N
}
}
File ud = new File(new File(Manager.getWorkDirPath()), "userdir" + invocations++);
if (config.reuseUserDir) {
ud = lastUserDir != null ? lastUserDir : ud;
} else {
NbTestCase.deleteSubFiles(ud);
}
lastUserDir = ud;
ud.mkdirs();
System.setProperty("netbeans.user", ud.getPath());
TreeSet<String> modules = new TreeSet<String>();
if (config.enableClasspathModules) {
modules.addAll(findEnabledModules(NbTestSuite.class.getClassLoader()));
}
modules.add("org.openide.filesystems");
modules.add("org.openide.modules");
modules.add("org.openide.util");
modules.add("org.openide.util.ui");
modules.remove("org.netbeans.insane");
modules.add("org.netbeans.core.startup");
modules.add("org.netbeans.core.startup.base");
modules.add("org.netbeans.bootstrap");
turnModules(ud, !config.honorAutoEager, modules, config.moduleRegExp, platform);
if (config.enableClasspathModules) {
turnClassPathModules(ud, NbTestSuite.class.getClassLoader());
}
StringBuilder sb = new StringBuilder();
String sep = "";
for (File f : findClusters()) {
turnModules(ud, !config.honorAutoEager, modules, config.moduleRegExp, f);
sb.append(sep);
sb.append(f.getPath());
sep = File.pathSeparator;
}
System.setProperty("netbeans.dirs", sb.toString());
if (config.hideExtraModules) {
Collection<File> clusters = new LinkedHashSet<File>();
if (config.clusterRegExp != null) {
findClusters(clusters, config.clusterRegExp);
}
clusters.add(findPlatform());
for (File f : clusters) {
disableModules(ud, f);
}
}
System.setProperty("netbeans.security.nocheck", "true");
List<Class<?>> allClasses = new ArrayList<Class<?>>(config.tests.size());
for (Item item : config.tests) {
allClasses.add(item.clazz);
}
preparePatches(System.getProperty("java.class.path"), System.getProperties(), allClasses.toArray(new Class<?>[0]));
List<String> args = new ArrayList<String>();
args.add("--nosplash");
if (!config.gui) {
args.add("--nogui");
}
if (config.startupArgs != null) {
args.addAll(config.startupArgs);
}
Test handler = NbModuleLogHandler.registerBuffer(config.failOnMessage, config.failOnException);
m.invoke(null, (Object)args.toArray(new String[0]));
ClassLoader global = Thread.currentThread().getContextClassLoader();
Assert.assertNotNull("Global classloader is initialized", global);
ClassLoader testLoader = global;
try {
testLoader.loadClass("junit.framework.Test");
testLoader.loadClass("org.netbeans.junit.NbTestSuite");
NbTestSuite toRun = new NbTestSuite();
for (Item item : config.tests) {
if (item.isTestCase){
Class<? extends TestCase> sndClazz =
testLoader.loadClass(item.clazz.getName()).asSubclass(TestCase.class);
if (item.fileNames == null) {
MethodOrder.orderMethods(sndClazz, null);
toRun.addTest(new NbTestSuiteLogCheck(sndClazz));
} else {
NbTestSuite t = new NbTestSuiteLogCheck();
t.addTests(sndClazz, item.fileNames);
toRun.addTest(t);
}
}else{
Class<? extends Test> sndClazz =
testLoader.loadClass(item.clazz.getName()).asSubclass(Test.class);
toRun.addTest(sndClazz.newInstance());
}
}
if (handler != null) {
toRun.addTest(handler);
}
testCount = toRun.countTestCases();
toRun.run(result);
} catch (ClassNotFoundException ex) {
result.addError(this, ex);
} catch (NoClassDefFoundError ex) {
result.addError(this, ex);
}
if (handler != null) {
NbModuleLogHandler.finish();
}
String n;
if (config.latestTestCaseClass != null) {
n = config.latestTestCaseClass.getName();
} else {
n = "exit"; // NOI18N
}
TestResult shutdownResult = new Shutdown(global, n).run();
if (shutdownResult.failureCount() > 0) {
final TestFailure tf = shutdownResult.failures().nextElement();
result.addFailure(tf.failedTest(), (AssertionFailedError)tf.thrownException());
}
if (shutdownResult.errorCount() > 0) {
final TestFailure tf = shutdownResult.errors().nextElement();
result.addError(tf.failedTest(), tf.thrownException());
}
}
static File findPlatform() {
String clusterPath = System.getProperty("cluster.path.final"); // NOI18N
if (clusterPath != null) {
for (String piece : tokenizePath(clusterPath)) {
File d = new File(piece);
if (d.getName().matches("platform\\d*")) {
return d;
}
}
}
String allClusters = System.getProperty("all.clusters"); // #194794
if (allClusters != null) {
File d = new File(allClusters, "platform"); // do not bother with old numbered variants
if (d.isDirectory()) {
return d;
}
}
try {
Class<?> lookup = Class.forName("org.openide.util.Lookup"); // NOI18N
File util = toFile(lookup.getProtectionDomain().getCodeSource().getLocation().toURI());
Assert.assertTrue("Util exists: " + util, util.exists());
return util.getParentFile().getParentFile();
} catch (Exception ex) {
try {
File nbjunit = toFile(NbModuleSuite.class.getProtectionDomain().getCodeSource().getLocation().toURI());
File harness = nbjunit.getParentFile().getParentFile();
Assert.assertEquals(nbjunit + " is in a folder named 'harness'", "harness", harness.getName());
TreeSet<File> sorted = new TreeSet<File>();
for (File p : harness.getParentFile().listFiles()) {
if (p.getName().startsWith("platform")) {
sorted.add(p);
}
}
Assert.assertFalse("Platform shall be found in " + harness.getParent(), sorted.isEmpty());
return sorted.last();
} catch (Exception ex2) {
Assert.fail("Cannot find utilities JAR: " + ex + " and: " + ex2);
}
return null;
}
}
private File[] findClusters() throws IOException {
Collection<File> clusters = new LinkedHashSet<File>();
if (config.clusterRegExp != null) {
findClusters(clusters, config.clusterRegExp);
}
if (config.enableClasspathModules) {
// find "cluster" from
// k/o.n.m.a.p.N/csam/testModule/build/cluster/modules/org-example-testModule.jar
// tested in apisupport.project
for (String s : tokenizePath(System.getProperty("java.class.path"))) {
File module = new File(s);
File cluster = module.getParentFile().getParentFile();
File m = new File(new File(cluster, "config"), "Modules");
if (m.exists() || cluster.getName().equals("cluster")) {
clusters.add(cluster);
}
}
}
return clusters.toArray(new File[0]);
}
private static String cnb(Manifest m) {
String cn = m.getMainAttributes().getValue("OpenIDE-Module");
return cn != null ? cn.replaceFirst("/\\d+", "") : null;
}
/** Looks for all modules on classpath of given loader and builds
* their list from them.
*/
static Set<String> findEnabledModules(ClassLoader loader) throws IOException {
Set<String> cnbs = new TreeSet<String>();
Enumeration<URL> en = loader.getResources("META-INF/MANIFEST.MF");
while (en.hasMoreElements()) {
URL url = en.nextElement();
InputStream is = url.openStream();
try {
String cnb = cnb(new Manifest(is));
if (cnb != null) {
cnbs.add(cnb);
}
} finally {
is.close();
}
}
return cnbs;
}
private static final Set<String> pseudoModules = new HashSet<String>(Arrays.asList(
"org.openide.util",
"org.openide.util.ui",
"org.openide.util.lookup",
"org.openide.modules",
"org.netbeans.bootstrap",
"org.openide.filesystems",
"org.openide.filesystems.compat8",
"org.netbeans.core.startup",
"org.netbeans.core.startup.base",
"org.netbeans.libs.asm"));
static void turnClassPathModules(File ud, ClassLoader loader) throws IOException {
Enumeration<URL> en = loader.getResources("META-INF/MANIFEST.MF");
while (en.hasMoreElements()) {
URL url = en.nextElement();
Manifest m;
InputStream is = url.openStream();
try {
m = new Manifest(is);
} catch (IOException x) {
throw new IOException("parsing " + url + ": " + x, x);
} finally {
is.close();
}
String cnb = cnb(m);
if (cnb != null) {
File jar = jarFromURL(url);
if (jar == null) {
continue;
}
if (pseudoModules.contains(cnb)) {
// Otherwise will get DuplicateException.
continue;
}
String mavenCP = m.getMainAttributes().getValue("Maven-Class-Path");
if (mavenCP != null) {
// Do not use ((URLClassLoader) loader).getURLs() as this does not work for Surefire Booter.
jar = rewrite(jar, mavenCP.split(" "), System.getProperty("java.class.path"));
}
String xml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE module PUBLIC \"-//NetBeans//DTD Module Status 1.0//EN\"\n" +
" \"http://www.netbeans.org/dtds/module-status-1_0.dtd\">\n" +
"<module name=\"" + cnb + "\">\n" +
" <param name=\"autoload\">false</param>\n" +
" <param name=\"eager\">false</param>\n" +
" <param name=\"enabled\">true</param>\n" +
" <param name=\"jar\">" + jar + "</param>\n" +
" <param name=\"reloadable\">false</param>\n" +
"</module>\n";
File conf = new File(new File(ud, "config"), "Modules");
conf.mkdirs();
File f = new File(conf, cnb.replace('.', '-') + ".xml");
writeModule(f, xml);
}
}
}
private static File rewrite(File jar, String[] mavenCP, String classpath) throws IOException { // #190992
String[] classpathEntries = tokenizePath(classpath);
StringBuilder classPathHeader = new StringBuilder();
for (String artifact : mavenCP) {
String[] grpArtVers = artifact.split(":");
String partOfPath = File.separatorChar + grpArtVers[0].replace('.', File.separatorChar) + File.separatorChar + grpArtVers[1] + File.separatorChar + grpArtVers[2] + File.separatorChar + grpArtVers[1] + '-' + grpArtVers[2];
File dep = null;
for (String classpathEntry : classpathEntries) {
if (classpathEntry.endsWith(".jar") && classpathEntry.contains(partOfPath)) {
dep = new File(classpathEntry);
break;
}
}
if (dep == null) {
throw new IOException("no match for " + artifact + " found in " + classpath);
}
File depCopy = File.createTempFile(artifact.replace(':', '-') + '-', ".jar");
depCopy.deleteOnExit();
NbTestCase.copytree(dep, depCopy);
if (classPathHeader.length() > 0) {
classPathHeader.append(' ');
}
classPathHeader.append(depCopy.getName());
}
String n = jar.getName();
int dot = n.lastIndexOf('.');
File jarCopy = File.createTempFile(n.substring(0, dot) + '-', n.substring(dot));
jarCopy.deleteOnExit();
InputStream is = new FileInputStream(jar);
try {
OutputStream os = new FileOutputStream(jarCopy);
try {
JarInputStream jis = new JarInputStream(is);
Manifest mani = new Manifest(jis.getManifest());
mani.getMainAttributes().putValue("Class-Path", classPathHeader.toString());
JarOutputStream jos = new JarOutputStream(os, mani);
JarEntry entry;
while ((entry = jis.getNextJarEntry()) != null) {
if (entry.getName().matches("META-INF/.+[.]SF")) {
throw new IOException("cannot handle signed JARs");
}
jos.putNextEntry(entry);
byte[] buf = new byte[4092];
for (;;) {
int more = jis.read(buf, 0, buf.length);
if (more == -1) {
break;
}
jos.write(buf, 0, more);
}
}
jis.close();
jos.close();
} finally {
os.close();
}
} finally {
is.close();
}
return jarCopy;
}
private static Pattern MANIFEST = Pattern.compile("jar:(file:.*)!/META-INF/MANIFEST.MF", Pattern.MULTILINE);
private static File jarFromURL(URL u) {
Matcher m = MANIFEST.matcher(u.toExternalForm());
if (m.matches()) {
return toFile(URI.create(m.group(1)));
} else {
if (!u.getProtocol().equals("file")) {
throw new IllegalStateException(u.toExternalForm());
} else {
return null;
}
}
}
/**
* JDK 7
*/
private static Method fileToPath, pathToUri, pathsGet, pathToFile;
static {
try {
fileToPath = File.class.getMethod("toPath");
} catch (NoSuchMethodException x) {
// fine, JDK 6
}
if (fileToPath != null) {
try {
Class<?> path = Class.forName("java.nio.file.Path");
pathToUri = path.getMethod("toUri");
pathsGet = Class.forName("java.nio.file.Paths").getMethod("get", URI.class);
pathToFile = path.getMethod("toFile");
} catch (Exception x) {
throw new ExceptionInInitializerError(x);
}
}
}
private static File toFile(URI u) throws IllegalArgumentException {
if (pathsGet != null) {
try {
return (File) pathToFile.invoke(pathsGet.invoke(null, u));
} catch (Exception x) {
LOG.log(Level.FINE, "could not convert " + u + " to File", x);
}
}
String host = u.getHost();
if (host != null && !host.isEmpty() && "file".equals(u.getScheme())) {
return new File("\\\\" + host + u.getPath().replace('/', '\\'));
}
return new File(u);
}
private static URI toURI(File f) {
if (fileToPath != null) {
try {
URI u = (URI) pathToUri.invoke(fileToPath.invoke(f));
if (u.toString().startsWith("file:///")) { // #214131 workaround
u = new URI(/* "file" */u.getScheme(), /* null */u.getUserInfo(), /* null (!) */u.getHost(), /* -1 */u.getPort(), /* "/..." */u.getPath(), /* null */u.getQuery(), /* null */u.getFragment());
}
return u;
} catch (Exception x) {
LOG.log(Level.FINE, "could not convert " + f + " to URI", x);
}
}
String path = f.getAbsolutePath();
if (path.startsWith("\\\\")) { // UNC
if (!path.endsWith("\\") && f.isDirectory()) {
path += "\\";
}
try {
return new URI("file", null, path.replace('\\', '/'), null);
} catch (URISyntaxException x) {
LOG.log(Level.FINE, "could not convert " + f + " to URI", x);
}
}
return f.toURI();
}
static void preparePatches(String path, Properties prop, Class<?>... classes) throws URISyntaxException {
Pattern tests = Pattern.compile(".*\\" + File.separator + "([^\\" + File.separator + "]+)\\" + File.separator + "tests\\.jar");
StringBuilder sb = new StringBuilder();
String sep = "";
for (String jar : tokenizePath(path)) {
Matcher m = tests.matcher(jar);
if (m.matches()) {
// in case we need it one day, let's add a switch to Configuration
// and choose the following line instead of netbeans.systemclassloader.patches
// prop.setProperty("netbeans.patches." + m.group(1).replace('-', '.'), jar);
sb.append(sep).append(jar);
sep = File.pathSeparator;
}
}
Set<URL> uniqueURLs = new HashSet<URL>();
for (Class<?> c : classes) {
URL test = c.getProtectionDomain().getCodeSource().getLocation();
Assert.assertNotNull("URL found for " + c, test);
if (uniqueURLs.add(test)) {
sb.append(sep).append(toFile(test.toURI()).getPath());
sep = File.pathSeparator;
}
}
prop.setProperty("netbeans.systemclassloader.patches", sb.toString());
}
private static String asString(InputStream is, boolean close) throws IOException {
StringBuilder builder = new StringBuilder();
byte[] bytes = new byte[4096];
try {
for (int i; (i = is.read(bytes)) != -1;) {
builder.append(new String(bytes, 0, i, "UTF-8"));
}
} finally {
if (close) {
is.close();
}
}
for (;;) {
int index = builder.indexOf("\r\n");
if (index == -1) {
break;
}
builder.deleteCharAt(index);
}
return builder.toString();
}
private void disableModules(File ud, File cluster) throws IOException {
File confDir = new File(new File(cluster, "config"), "Modules");
for (File c : confDir.listFiles()) {
if (!isModuleEnabled(c)) {
continue;
}
File udC = new File(new File(new File(ud, "config"), "Modules"), c.getName());
if (!udC.exists()) {
File hidden = new File(udC.getParentFile(), c.getName() + "_hidden");
hidden.createNewFile();
}
}
}
private static boolean isModuleEnabled(File config) throws IOException {
String xml = asString(new FileInputStream(config), true);
Matcher matcherEnabled = ENABLED.matcher(xml);
if (matcherEnabled.find()) {
return "true".equals(matcherEnabled.group(1));
}
return false;
}
private static class Shutdown extends NbTestCase {
Shutdown(ClassLoader global, String testClass) throws Exception {
super("shuttingDown[" + testClass + "]");
this.global = global;
}
@Override
protected int timeOut() {
return 180000; // 3 minutes for a shutdown
}
@Override
protected Level logLevel() {
return Level.FINE;
}
@Override
protected String logRoot() {
return "org.netbeans.core.NbLifecycleManager"; // NOI18N
}
private static void waitForAWT() throws InvocationTargetException, InterruptedException {
final CountDownLatch cdl = new CountDownLatch(1);
SwingUtilities.invokeLater(new Runnable() {
public @Override void run() {
cdl.countDown();
}
});
cdl.await(10, TimeUnit.SECONDS);
}
private final ClassLoader global;
@Override
protected void runTest() throws Throwable {
JFrame shutDown;
try {
shutDown = new JFrame("Shutting down NetBeans...");
shutDown.setBounds(new Rectangle(-100, -100, 50, 50));
shutDown.setVisible(true);
} catch (HeadlessException ex) {
shutDown = null;
}
Class<?> lifeClazz = global.loadClass("org.openide.LifecycleManager"); // NOI18N
Method getDefault = lifeClazz.getMethod("getDefault"); // NOI18N
Method exit = lifeClazz.getMethod("exit");
LOG.log(Level.FINE, "Closing via LifecycleManager loaded by {0}", lifeClazz.getClassLoader());
Object life = getDefault.invoke(null);
if (!life.getClass().getName().startsWith("org.openide.LifecycleManager")) { // NOI18N
System.setProperty("netbeans.close.no.exit", "true"); // NOI18N
System.setProperty("netbeans.close", "true"); // NOI18N
exit.invoke(life);
waitForAWT();
System.getProperties().remove("netbeans.close"); // NOI18N
System.getProperties().remove("netbeans.close.no.exit"); // NOI18N
}
if (shutDown != null) {
shutDown.setVisible(false);
}
}
}
private static final class JUnitLoader extends ClassLoader {
private final ClassLoader junit;
public JUnitLoader(ClassLoader parent, ClassLoader junit) {
super(parent);
this.junit = junit;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (isUnit(name)) {
return junit.loadClass(name);
}
return super.findClass(name);
}
@Override
public URL findResource(String name) {
if (isUnit(name)) {
return junit.getResource(name);
}
if (name.equals("META-INF/services/java.util.logging.Handler")) { // NOI18N
return junit.getResource("org/netbeans/junit/internal/FakeMetaInf.txt"); // NOI18N
}
return super.findResource(name);
}
@Override
public Enumeration<URL> findResources(String name) throws IOException {
if (isUnit(name)) {
return junit.getResources(name);
}
if (name.equals("META-INF/services/java.util.logging.Handler")) { // NOI18N
return junit.getResources("org/netbeans/junit/internal/FakeMetaInf.txt"); // NOI18N
}
return super.findResources(name);
}
private boolean isUnit(String res) {
if (res.startsWith("junit")) {
return true;
}
if (res.startsWith("org.junit") || res.startsWith("org/junit")) {
return true;
}
if (res.startsWith("org.netbeans.junit") || res.startsWith("org/netbeans/junit")) {
if (res.startsWith("org.netbeans.junit.ide") || res.startsWith("org/netbeans/junit/ide")) {
return false;
}
return true;
}
return false;
}
}
private static Pattern ENABLED = Pattern.compile("<param name=[\"']enabled[\"']>([^<]*)</param>", Pattern.MULTILINE);
private static Pattern AUTO = Pattern.compile("<param name=[\"']autoload[\"']>([^<]*)</param>", Pattern.MULTILINE);
private static Pattern EAGER = Pattern.compile("<param name=[\"']eager[\"']>([^<]*)</param>", Pattern.MULTILINE);
private static void turnModules(File ud, boolean autoloads, TreeSet<String> modules, List<String> regExp, File... clusterDirs) throws IOException {
if (regExp == null) {
return;
}
File config = new File(new File(ud, "config"), "Modules");
config.mkdirs();
Iterator<String> it = regExp.iterator();
for (;;) {
if (!it.hasNext()) {
break;
}
String clusterReg = it.next();
String moduleReg = it.next();
Pattern modPattern = Pattern.compile(moduleReg);
for (File c : clusterDirs) {
if (!c.getName().matches(clusterReg)) {
continue;
}
File modulesDir = new File(new File(c, "config"), "Modules");
File[] allModules = modulesDir.listFiles();
if (allModules == null) {
continue;
}
for (File m : allModules) {
String n = m.getName();
if (n.endsWith(".xml")) {
n = n.substring(0, n.length() - 4);
}
n = n.replace('-', '.');
String xml = asString(new FileInputStream(m), true);
boolean contains = modules.contains(n);
if (!contains && modPattern != null) {
contains = modPattern.matcher(n).matches();
}
if (!contains) {
continue;
}
enableModule(xml, autoloads, contains, new File(config, m.getName()));
}
}
}
}
private static void enableModule(String xml, boolean autoloads, boolean enable, File target) throws IOException {
boolean toEnable = false;
{
Matcher matcherEnabled = ENABLED.matcher(xml);
if (matcherEnabled.find()) {
toEnable = "false".equals(matcherEnabled.group(1));
}
Matcher matcherEager = EAGER.matcher(xml);
if (matcherEager.find()) {
if ("true".equals(matcherEager.group(1))) {
return;
}
}
if (!autoloads) {
Matcher matcherAuto = AUTO.matcher(xml);
if (matcherAuto.find()) {
if ("true".equals(matcherAuto.group(1))) {
return;
}
}
}
if (toEnable) {
assert matcherEnabled.groupCount() == 1 : "Groups: " + matcherEnabled.groupCount() + " for:\n" + xml;
try {
String out = xml.substring(0, matcherEnabled.start(1)) + (enable ? "true" : "false") + xml.substring(matcherEnabled.end(1));
writeModule(target, out);
} catch (IllegalStateException ex) {
throw new IOException("Unparsable:\n" + xml, ex);
}
}
}
{
Matcher matcherEager = AUTO.matcher(xml);
if (matcherEager.find()) {
int begin = xml.indexOf("<param name=\"autoload");
int end = xml.indexOf("<param name=\"jar");
String middle = "<param name=\"autoload\">false</param>\n" + " <param name=\"eager\">false</param>\n" + " <param name=\"enabled\">true</param>\n" + " ";
String out = xml.substring(0, begin) + middle + xml.substring(end);
try {
writeModule(target, out);
} catch (IllegalStateException ex) {
throw new IOException("Unparsable:\n" + xml, ex);
}
}
}
}
private static void writeModule(File file, String xml) throws IOException {
String previous;
if (file.exists()) {
previous = asString(new FileInputStream(file), true);
if (previous.equals(xml)) {
return;
}
if (LOG.isLoggable(Level.FINE)) {
LOG.log(Level.FINE, "rewrite module file: {0}", file);
charDump(Level.FINEST, previous);
LOG.finest("new----");
charDump(Level.FINEST, xml);
LOG.finest("end----");
}
}
FileOutputStream os = new FileOutputStream(file);
os.write(xml.getBytes("UTF-8"));
os.close();
}
private static void charDump(Level logLevel, String text) {
StringBuilder sb = new StringBuilder(5 * text.length());
for (int i = 0; i < text.length(); i++) {
if (i % 8 == 0) {
if (i > 0) {
sb.append('\n');
}
} else {
sb.append(' ');
}
int ch = text.charAt(i);
if (' ' <= ch && ch <= 'z') {
sb.append('\'').append((char)ch).append('\'');
} else {
sb.append('x').append(two(Integer.toHexString(ch).toUpperCase()));
}
}
sb.append('\n');
LOG.log(logLevel, sb.toString());
}
private static String two(String s) {
int len = s.length();
switch (len) {
case 0: return "00";
case 1: return "0" + s;
case 2: return s;
default: return s.substring(len - 2);
}
}
} // end of S
private static class NbTestSuiteLogCheck extends NbTestSuite {
public NbTestSuiteLogCheck() {
}
public NbTestSuiteLogCheck(Class<? extends TestCase> clazz) {
super(clazz);
}
@Override
public void runTest(Test test, TestResult result) {
int e = result.errorCount();
int f = result.failureCount();
LOG.log(Level.FINE, "Running test {0}", test);
super.runTest(test, result);
LOG.log(Level.FINE, "Finished: {0}", test);
if (e == result.errorCount() && f == result.failureCount()) {
NbModuleLogHandler.checkFailures((TestCase) test, result, test instanceof NbTestCase ? ((NbTestCase) test).getWorkDirPath() : Manager.getWorkDirPath());
}
}
}
}