Path: blob/master/test/functional/cmdline_options_tester/src/TestSuite.java
6004 views
/*******************************************************************************1* Copyright (c) 2004, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122import java.io.*;23import java.text.*;24import java.util.*;25import com.oti.j9.exclude.*;2627/**28* This is the test suite object that keeps track of all the tests and runs them.29*/30public class TestSuite {3132/**33* The user-defined variables in the configuration file. Substitution of these is done34* later, just before the commands are actually executed35*/36private static Hashtable _variables = new Hashtable();37private static final String failedPropertyName = "cmdlinetester.failed_tests";38private ExcludeList _excludes;39private long _defaultTimeout;40private boolean _verbose;41private int _outputLimit;42private static SortedSet _processedVariables;4344private ArrayList _passed;45private ArrayList _failed;4647/* ArrayList to hold environment variables */48private static Hashtable _envVarList = new Hashtable();49/**50* Initializes variables.51*/52TestSuite( ExcludeList excludes, long defaultTimeout, boolean verbose, int outputLimit ) {53_variables = new Hashtable();54_excludes = excludes;55_defaultTimeout = defaultTimeout;56_verbose = verbose;57_passed = new ArrayList();58_failed = new ArrayList();59_outputLimit = outputLimit;60System.setProperty(failedPropertyName, "0");61}6263void setVerbose( boolean verbose ) {64_verbose = verbose;65}6667void setOutputLimit( int limit ) {68_outputLimit = limit;69}7071/**72* Add a new test73*/74void runTest( Test test ) {75try {76if (_excludes != null && !_excludes.shouldRun( test.getId() )) {77System.out.println( "Test excluded: " + test.getId() + '\n' );78return;79}80String testName = test.getId();81System.out.println( "Testing: " + testName );82test.setOutputLimit(_outputLimit);83boolean result = test.run( _defaultTimeout ); // <-- actually run the test84if (result) {85_passed.add( testName );86System.out.println( "Test result: PASSED" );87if (_verbose) {88test.dumpVerboseOutput(result);89}90System.out.print( '\n' );91} else {92_failed.add( testName );93System.out.println( "Test result: FAILED" );94test.dumpVerboseOutput(result); // print verbose output in case of failure95System.out.print( '\n' );9697int failedTests = Integer.parseInt(System.getProperty(failedPropertyName));98failedTests++;99System.setProperty(failedPropertyName, Integer.toString(failedTests));100}101test.destroy();102} catch (Exception e) {103TestSuite.printStackTrace(e);104}105}106107void printResults() {108// print aggregate statistics109System.out.println("\n---TEST RESULTS---");110System.out.println("Number of PASSED tests: " + _passed.size() + " out of " + (_passed.size() + _failed.size()));111System.out.println("Number of FAILED tests: " + _failed.size() + " out of " + (_passed.size() + _failed.size()));112113if (_failed.size() > 0) {114System.out.println("\n---SUMMARY OF FAILED TESTS---");115for (int i = 0; i < _failed.size(); i++) {116System.out.println( (String)_failed.get(i) );117}118System.out.println("-----------------------------\n");119}120}121122int getFailureCount() {123return _failed.size();124}125126public static void putVariable( String key, String value ) {127_variables.put( key, value );128}129130public static String getVariable( String key ) {131//return (String)_variables.get( key );132/* MODIFIED by Oliver Deakin - 20050211 - treat system properties the same as variables - do this under the covers133so that there is no distinction between system properties and variables */134String returnString = (String) (_variables.get(key));135if (returnString == null)136{137// If key is not in the cmdlinetester variables, check system properties138returnString = (String) (TestSuite.getSystemProperty(key));139}140141return returnString;142}143144public static String evaluateVariables( String s ) {145return evaluateVariables(s, null);146}147148/* A new way to implement use of environment variables */149public static void putEnvironmentVariable( String key, String value ) {150_envVarList.put( key, value );151}152153/* This will return a list of the environment variables in a format that Runtime.exec can understand:154"name=value"155*/156public static String[] getEnvironmentVariableList() {157//Create an array string from the current environment variables158String[] envVarArray;159if (_envVarList.size() == 0)160{161return null;162}163164envVarArray = new String[_envVarList.size()];165166// Iterate through the Hashtable turning key/value pairs into the correct format167Object[] keyNames = _envVarList.keySet().toArray();168for (int keyNum = 0; keyNum<_envVarList.size(); keyNum++)169{170String key = (String)keyNames[keyNum];171String value = (String)_envVarList.get(key);172envVarArray[keyNum] = key + "=" + value;173}174175return envVarArray;176}177178public static String getSystemProperty( String key ) {179return (String) (System.getProperties().get( key ));180}181182/**183* Does a variable replacement on s using the variables in <code>_variables</code> and184* System.properties. Also does a replacement of nested variables within variable185* names. For example, if $HI$ = "WORD", $WORD$ = "ING", and $TESTING$ = "SOMETHING",186* then $TEST{$HI$}$ would evaluate as follows:187*188* $TEST{$HI$}$ -> $TEST{WORD}$ -> $TESTING$ -> SOMETHING189*190* Curly brackets have no special meaning if outside of a set of dollar signs. When191* inside a set dollar signs, curly brackets always have special meaning. For192* example, "{}TEST$TEST{{HI}}${HI}" would evaluate as follows (using the same193* variable values as in the previous example):194*195* {}TEST$TEST{{HI}}${HI} -> {}TEST$TEST{WORD}${HI} -> {}TEST$TESTING${HI} ->196* {}TESTSOMETHING{HI}197*198* For each (<code>key</code>, <code>value</code>) pair in <code>_variables</code>199* and System.properties, this method replaces all instances of $<code>key</code>$200* with <code>value</code> (taking into account the nested variable replacement201* described above). All the substitutions from <code>_variables</code> are202* done before any of the substitutions from System.properties.203*204* Note: this method will "expand" the String "$$" to "$" after all other expansions205* have been performed. This is done so that the user can specify a literal "$" if206* desired.207*208* @param s - The source string209* @param variableName - The name of the variable whose value is being evaluated210* if applicable; null if it is not a variable's value that is being evaluated211* @return A copy of s with all the substitutions performed.212*/213public static String evaluateVariables( String s, String variableName ) {214if (s == null || s.equals("$$")) {215return s;216}217218String value = s;219220if (null == variableName) {221_processedVariables = new TreeSet();222} else {223if (_processedVariables.contains(variableName)) {224System.err.println(225"The variable \"" + variableName + "\" with value \"" + value +226"\" cannot be resolved because it refers to itself somewhere " +227"along the variable substitution chain.");228System.exit(1);229} else {230_processedVariables.add(variableName);231}232}233234Stack tokens = new Stack();235int varStartIndex = -1;236237for (int i = 0; i < s.length(); i++)238{239char currChar = s.charAt(i);240switch (currChar)241{242case '$':243if (!tokens.isEmpty() && '$' == ((Character)tokens.peek()).charValue()) {244tokens.pop();245if (tokens.isEmpty())246{247String newString = s.substring(0, varStartIndex - 1) +248expandVariable(s.substring(varStartIndex, i));249int newIndex = newString.length() - 1; // adjust for i++ at end of loop250251if ( (i + 1) < s.length()) {252newString += s.substring(i + 1);253}254255s = newString;256i = newIndex;257varStartIndex = -1;258}259} else {260if (tokens.isEmpty()) {261varStartIndex = i + 1;262}263tokens.push(Character.valueOf('$'));264}265break;266267case '{':268if (!tokens.isEmpty()) {269tokens.push(Character.valueOf('{'));270}271break;272273case '}':274if (!tokens.isEmpty()) {275if ('{' == ((Character)tokens.peek()).charValue()) {276tokens.pop();277} else {278System.err.println(279"The variable \"" + variableName + "\" with value \"" + value +280"\" cannot be resolved because it contains a '}' after " +281"an opening '$'.");282System.exit(1);283}284}285}286}287288if (!tokens.isEmpty())289{290System.err.println(291"The variable \"" + variableName + "\" with value \"" + value +292"\" cannot be resolved because it is missing at least one token " +293"signifying the end of a variable ('$' or '}'); the first " +294"unbalanced start token is a '" +295((Character)tokens.pop()).charValue() + "'");296System.exit(1);297}298299if (null != variableName) {300_processedVariables.remove(variableName);301}302303if (null == variableName)304{305boolean lastWasDollar = false;306for (int i = 0; i < s.length(); i++)307{308char c = s.charAt(i);309if ('$' == c)310{311if (lastWasDollar)312{313s = s.substring(0, i - 1) + s.substring(i);314i--; // we removed a char from the String so adjust i accordingly315316lastWasDollar = false;317} else {318lastWasDollar = true;319}320}321}322}323324return s;325}326327private static String expandVariable(String s)328{329String unexpandedName = s;330Stack tokens = new Stack();331int varStartIndex = -1;332333for (int i = 0; i < s.length(); i++)334{335char currChar = s.charAt(i);336switch (currChar)337{338case '$':339if (!tokens.isEmpty() && '$' == ((Character)tokens.peek()).charValue()) {340tokens.pop();341if (tokens.isEmpty())342{343String newString = s.substring(0, varStartIndex - 1) +344expandVariable(s.substring(varStartIndex, i));345int newIndex = newString.length() - 1; // adjust for i++ at end of loop346347if ( (i + 1) < s.length()) {348newString += s.substring(i + 1);349}350351s = newString;352i = newIndex;353varStartIndex = -1;354}355} else {356if (tokens.isEmpty()) {357varStartIndex = i + 1;358}359tokens.push(Character.valueOf('$'));360}361break;362363case '{':364if (tokens.isEmpty()) {365varStartIndex = i + 1;366}367tokens.push(Character.valueOf('{'));368break;369370case '}':371if (tokens.isEmpty()) {372System.err.println(373"The variable name \"" + unexpandedName + "\" cannot be " +374"resolved because it contains a '}' that does not refer " +375"to a corresponding '{'.");376System.exit(1);377} else {378if ('{' == ((Character)tokens.peek()).charValue()) {379tokens.pop();380if (tokens.isEmpty())381{382String newString = s.substring(0, varStartIndex - 1) +383expandVariable(s.substring(varStartIndex, i));384int newIndex = newString.length() - 1; // adjust for i++ at end of loop385386if ( (i + 1) < s.length()) {387newString += s.substring(i + 1);388}389390s = newString;391i = newIndex;392varStartIndex = -1;393}394} else {395System.err.println(396"The variable name \"" + unexpandedName + "\" cannot " +397"be resolved because it contains a '}' after " +398"an opening '$'.");399System.exit(1);400}401}402}403}404405if (!tokens.isEmpty())406{407System.err.println(408"The variable name \"" + unexpandedName + "\" cannot " +409"be resolved because it is missing at least one token " +410"signifying the end of a variable ('$' or '}'); the first " +411"unbalanced start token is a '" +412((Character)tokens.pop()).charValue() + "'");413System.exit(1);414}415416String varValue = getVariableValue(s);417418if (null == varValue)419{420System.err.println(421"The variable \"" + s + "\" does not exist; original string " +422"used to construct the variable name was \"" + unexpandedName + "\"");423System.exit(1);424}425426return evaluateVariables(varValue, s);427}428429private static String getVariableValue(String variableName)430{431if (variableName.equals("")) {432return "$$";433}434435String value;436437value = getVariable(variableName);438if (null != value)439{440return value;441}442443value = (String)System.getProperties().get(variableName);444return value;445}446447/**448* Basic implementation of the String.replaceAll that's in Java 1.4+449*450* @param s - The source string451* @param find - Substring to find452* @param replace - Substring to replace all instances of <code>find</code> with453* @return A copy of <code>s<code>, with all instances of <code>find</code> replaced with454* <code>replace</code>455*/456public static String doReplaceAll( String s, String find, String replace ) {457int lastIndex = 0;458int index = s.indexOf( find, lastIndex );459while (index >= 0) {460s = s.substring( 0, index ) + replace + s.substring( index + find.length() );461lastIndex = index + replace.length();462index = s.indexOf( find, lastIndex );463}464return s;465}466467public static void printErrorMessage(String message) {468Calendar calendar = Calendar.getInstance();469DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");470System.out.println("***[TEST INFO " + df.format(calendar.getTime()) + "] " + message + "***");471}472473public static void printStackTrace(Throwable e) {474StringWriter sw = new StringWriter();475PrintWriter pw = new PrintWriter(sw);476e.printStackTrace(pw);477478String[] stack = sw.toString().split("\n");479for (int i = 0; i < stack.length; i++) {480String element = stack[i];481printErrorMessage(element);482}483484pw.close();485}486}487488489