blob: ec99089a5d06f8c99fdf39d0db52d3dbf5b099f2 [file] [log] [blame]
/**
* Copyright (C) 2009 Google Inc.
*
* Licensed 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 com.googlecode.guice;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collections;
import java.util.Enumeration;
import junit.extensions.TestDecorator;
import junit.framework.Test;
import junit.framework.TestResult;
import junit.framework.TestSuite;
/**
* Builds a test suite whose tests are loaded in a private classloader and run them with a security
* manager.
*
* @author jessewilson@google.com (Jesse Wilson)
*/
public class StrictContainerTestSuiteBuilder {
private final ClassLoader classLoader = new NonSystemClassLoader();
private final SecurityManager securityManager;
private final TestSuite testSuite = new TestSuite("StrictContainer");
public StrictContainerTestSuiteBuilder(SecurityManager securityManager) {
this.securityManager = securityManager;
}
public void add(String testClassName) {
try {
Class<?> testClass = classLoader.loadClass(testClassName);
testSuite.addTest(securityManaged(new TestSuite(testClass)));
} catch (Exception e) {
testSuite.addTest(new SuiteConstructionError(testClassName, e));
}
}
public void addSuite(String suiteClassname) {
try {
Class<?> suiteClass = classLoader.loadClass(suiteClassname);
Test testSuite = (Test) suiteClass.getMethod("suite").invoke(null);
this.testSuite.addTest(securityManaged(testSuite));
} catch (Exception e) {
testSuite.addTest(new SuiteConstructionError(suiteClassname, e));
}
}
public TestSuite build() {
return testSuite;
}
/**
* A classloader that reloads everything outside of the JDK.
*/
static class NonSystemClassLoader extends URLClassLoader {
public NonSystemClassLoader() {
super(new URL[0]);
for (final String element : System.getProperty("java.class.path").split(File.pathSeparator)) {
try {
// is it a remote/local URL?
addURL(new URL(element));
} catch (MalformedURLException e1) {
// nope - perhaps it's a filename?
try {
addURL(new File(element).toURI().toURL());
} catch (MalformedURLException e2) {
throw new RuntimeException(e1);
}
}
}
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// check our local cache to avoid duplicates
synchronized (this) {
Class<?> clazz = findLoadedClass(name);
if (clazz != null) {
return clazz;
}
}
if (name.startsWith("java.")
|| name.startsWith("javax.")
|| name.startsWith("junit.")
|| name.startsWith("sun.")
|| name.startsWith("com.sun.")) {
return super.loadClass(name, resolve);
}
Class<?> clazz = findClass(name);
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
}
/**
* Returns a test that sets up and tears down a security manager while it's run.
*/
public Test securityManaged(Test test) {
if (test instanceof TestSuite) {
TestSuite suite = (TestSuite) test;
TestSuite result = new TestSuite(suite.getName());
@SuppressWarnings("unchecked") // a test suite's elements are tests
Enumeration<Test> children = (Enumeration<Test>) suite.tests();
for (Test child : Collections.list(children)) {
result.addTest(securityManaged(child));
}
return result;
} else {
return new TestDecorator(test) {
public void run(TestResult testResult) {
SecurityManager originalSecurityManager = System.getSecurityManager();
System.setSecurityManager(securityManager);
try {
basicRun(testResult);
} finally {
testResult.endTest(this);
System.setSecurityManager(originalSecurityManager);
}
}
};
}
}
/**
* A simple test that always fails with an exception.
*/
private static class SuiteConstructionError implements Test {
private String className;
private final Exception cause;
public SuiteConstructionError(String className, Exception cause) {
this.className = className;
this.cause = cause;
}
public void run(TestResult testResult) {
testResult.addError(this, cause);
}
public int countTestCases() {
return 1;
}
@Override public String toString() {
return className;
}
}
}