blob: 1fe5af53012ad4c0a9564cd04bf727a986821e5c [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
<<<<<<< Updated upstream
*
* 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
=======
*
* https://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
>>>>>>> Stashed changes
* limitations under the License.
*/
package org.apache.jdo.tck.util;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import javax.jdo.JDOFatalException;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import junit.textui.ResultPrinter;
import junit.textui.TestRunner;
import org.apache.jdo.tck.JDO_Test;
/**
* TestRunner class for running a single test or a test suite in batch mode. The format of the test
* output is specified by the result printer class. The main method sets an exit code according to
* the test result:
*
* <ul>
* <li><code>0</code>: success
* <li><code>1</code>: failure, the test shows an unexpected behavior
* <li><code>2</code>: exception, the test throws an unhandled exception
* </ul>
*
* @author Michael Bouschen
*/
public class BatchTestRunner extends TestRunner {
/** Name of the system property to specify the result printer class. */
public static final String RESULTPRINTER_PROPERTY = "ResultPrinterClass";
/** Default of the system property ResultPrinterClass. */
public static final String RESULTPRINTER_DEFAULT = BatchResultPrinter.class.getName();
/** */
public static final String LOG_DIRECTORY;
static {
String directory = System.getProperty("jdo.tck.log.directory");
if (directory != null && !directory.endsWith(File.separator)) {
directory += File.separator;
}
LOG_DIRECTORY = directory;
}
/**
* Constructor. It creates a result printer instance based on the system property and delegates to
* the constructor taking a result printer argument.
*/
public BatchTestRunner() {
super();
setPrinter(getResultPrinter());
}
/**
* Constructor. Uses the specified resultPrinter to format the test result.
*
* @param resultPrinter the result printer
*/
public BatchTestRunner(ResultPrinter resultPrinter) {
super(resultPrinter);
}
/**
* Runs all test methods from the specified class.
*
* @param clazz class object
*/
public static void run(Class<? extends TestCase> clazz) {
run(new TestSuite(clazz));
}
/**
* Runs the specified test or test suite
*
* @param test test or test suite
* @return the test result
*/
public static TestResult run(Test test) {
return new BatchTestRunner().doRun(test);
}
/**
* Runs the specified test and waits until the user types RETURN.
*
* @param suite suite
*/
public static void runAndWait(Test suite) {
new BatchTestRunner().doRun(suite, true);
}
/**
* Runs the specified test or test suite and closes the pmf.
*
* @param test test or test suite
* @return the test result
*/
@Override
public TestResult doRun(Test test) {
TestResult result = null;
try {
result = doRun(test, false);
JDO_Test.dumpSupportedOptions(LOG_DIRECTORY + "configuration");
} finally {
JDO_Test.closePMF();
}
return result;
}
/**
* Runs in batch mode and sets an exit code. If the specified String array includes a single fully
* qualified class name, this test class is executed.
*
* @param args command line arguments
*/
public static void main(String[] args) {
try {
TestResult r = new BatchTestRunner().start(args);
if (!r.wasSuccessful()) System.exit(FAILURE_EXIT);
System.exit(SUCCESS_EXIT);
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(EXCEPTION_EXIT);
}
}
/**
* Starts the test
*
* @param args arguments
* @return the test result
*/
@Override
public TestResult start(String[] args) {
Test suite = null;
if ((args == null) || args.length == 0) {
String conf = System.getProperty("jdo.tck.cfg");
throw new JDOFatalException(
"Missing JDO TCK test classes for configuration '"
+ conf
+ "'. Please check the property 'jdo.tck.classes'.");
} else if (args.length == 1) {
suite = getTest(args[0]);
} else {
suite = getTestSuite(args);
}
return doRun(suite);
}
/**
* Returns a JUnit TestSuite instance for the classes of the specified list of class names.
*
* @param classNames class names
* @return the test suite
*/
@SuppressWarnings("unchecked")
protected TestSuite getTestSuite(String[] classNames) {
TestSuite testSuite = new TestSuite();
for (String className : classNames) {
try {
Class<? extends TestCase> clazz = (Class<? extends TestCase>) Class.forName(className);
testSuite.addTestSuite(clazz);
} catch (ClassNotFoundException ex) {
System.out.println("Cannot find test class '" + className + "'.");
}
}
return testSuite;
}
/**
* Returns a result printer instance. The system property ResultPrinterClass specifies the class
* of the returned instance. The class must extend junit.textui.ResultPrinter.
*
* @return the result printer
*/
protected ResultPrinter getResultPrinter() {
String className = System.getProperty(RESULTPRINTER_PROPERTY);
if (className != null) {
className = className.trim();
if (className.length() != 0) {
String msg = null;
try {
// get class instance
Class<?> clazz = Class.forName(className);
Constructor<?> ctor = null;
OutputStream stream = null;
// choose constructor taking ConsoleFileOutput arg
if (!Boolean.getBoolean("no.log.file")) {
try {
ctor = clazz.getConstructor(ConsoleFileOutput.class);
stream = new ConsoleFileOutput();
} catch (NoSuchMethodException ex) {
ctor = null;
}
}
// choose constructor taking PrintStream arg
if (ctor == null) {
ctor = clazz.getConstructor(PrintStream.class);
stream = System.out;
}
return (ResultPrinter) ctor.newInstance(new Object[] {stream});
} catch (ClassNotFoundException ex) {
// specified ResultPrinter class not
msg = "Cannot find specified result printer class " + className + ".";
} catch (NoSuchMethodException ex) {
msg = "Class " + className + " does not provide constructor taking a PrintStream.";
} catch (InstantiationException ex) {
msg = "Class " + className + " is abstract.";
} catch (IllegalAccessException ex) {
msg = "Constructor taking a PrintStream of class " + className + " is not accessible.";
} catch (InvocationTargetException ex) {
msg = "Constructor call results in exception " + ex + ".";
}
// ResultPrinter class specified, but not available
System.out.println(msg);
ResultPrinter printer = getDefaultResultPrinter();
System.out.println("Using default result printer of class " + printer.getClass().getName());
}
}
// ResultPrinter class not specified => use default
return getDefaultResultPrinter();
}
/**
* Returns an instance of the default result printer class BatchResultPrinter.
*
* @return the default result printer
*/
protected ResultPrinter getDefaultResultPrinter() {
return new BatchResultPrinter(System.out);
}
/**
* Returns a file name which is determined by method {@link
* BatchTestRunner#changeFileName(String)}. The file name has suffix <code>.txt</code>.
*
* @return the file name
*/
public static String getFileName() {
return changeFileName("junit.txt");
}
/**
* Returns a file name which is constructed by values of some system properties appended by the
* given file name. The system properties evaluated are:
*
* <ul>
* <li>jdo.tck.log.directory: Specifies the directory for the file.
* <li>jdo.tck.database, jdo.tck.cfg: The values of these properties prepend the given file
* name.
* <li>jdo.tck.identitytype: The value of this property is replaced by <code>"app"</code> if it
* equals <code>"applicationidentity"</code>, else it is replaced by <code>"dsid"</code>.
* </ul>
*
* The returned file name is constructed as follows:<br>
* ${jdo.tck.log.directory}/${jdo.tck.database}-${jdo.tck.identitytype}-${jdo.tck.cfg}${given file
* name} Values of properties which do not exist default to <code>""</code>.
*
* @param fileName the file name
* @return the changed file name
*/
public static String changeFileName(String fileName) {
String directory = LOG_DIRECTORY;
String db = System.getProperty("jdo.tck.database");
String identityType = System.getProperty("jdo.tck.identitytype");
if (identityType != null) {
if (identityType.equals("applicationidentity")) {
identityType = "app";
} else {
identityType = "dsid";
}
}
String configuration = System.getProperty("jdo.tck.cfg");
if (configuration != null) {
int index = configuration.indexOf('.');
if (index != -1) {
configuration = configuration.substring(0, index);
}
}
directory = fixPartialFileName(directory);
db = fixPartialFileName(db, '-', new String[] {identityType, configuration, fileName});
identityType = fixPartialFileName(identityType, '-', new String[] {configuration, fileName});
configuration = fixPartialFileName(configuration, '-', new String[] {fileName});
return directory + db + identityType + configuration + fileName;
}
private static String fixPartialFileName(String str) {
if (str == null) {
str = "";
}
return str;
}
private static String fixPartialFileName(String str, char c, String[] values) {
str = fixPartialFileName(str);
if (!str.equals("")) {
for (String value : values) {
if (value != null && !value.equals("") && !value.startsWith(".")) {
str += c;
break;
}
}
}
return str;
}
}