1/* 2 * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23/* 24 * 25 * 26 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 27 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 28 * 29 * Portions copyright (c) 2007 Sun Microsystems, Inc. 30 * All Rights Reserved. 31 * 32 * The original version of this source code and documentation 33 * is copyrighted and owned by Taligent, Inc., a wholly-owned 34 * subsidiary of IBM. These materials are provided under terms 35 * of a License Agreement between Taligent and Sun. This technology 36 * is protected by multiple US and International patents. 37 * 38 * This notice and attribution to Taligent may not be removed. 39 * Taligent is a registered trademark of Taligent, Inc. 40 * 41 * Permission to use, copy, modify, and distribute this software 42 * and its documentation for NON-COMMERCIAL purposes and without 43 * fee is hereby granted provided that this copyright notice 44 * appears in all copies. Please refer to the file "copyright.html" 45 * for further important copyright and licensing information. 46 * 47 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF 48 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 49 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 50 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR 51 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR 52 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. 53 * 54 */ 55 56import java.lang.reflect.*; 57import java.util.Hashtable; 58import java.util.Enumeration; 59import java.util.Vector; 60import java.io.*; 61import java.text.*; 62 63/** 64 * RBTestFmwk is a base class for tests that can be run conveniently from 65 * the command line as well as under the Java test harness. 66 * <p> 67 * Sub-classes implement a set of methods named Test<something>. Each 68 * of these methods performs some test. Test methods should indicate 69 * errors by calling either err or errln. This will increment the 70 * errorCount field and may optionally print a message to the log. 71 * Debugging information may also be added to the log via the log 72 * and logln methods. These methods will add their arguments to the 73 * log only if the test is being run in verbose mode. 74 */ 75public class RBTestFmwk { 76 //------------------------------------------------------------------------ 77 // Everything below here is boilerplate code that makes it possible 78 // to add a new test by simply adding a function to an existing class 79 //------------------------------------------------------------------------ 80 81 protected RBTestFmwk() { 82 // Create a hashtable containing all the test methods. 83 testMethods = new Hashtable(); 84 Method[] methods = getClass().getDeclaredMethods(); 85 for( int i=0; i<methods.length; i++ ) { 86 if( methods[i].getName().startsWith("Test") 87 || methods[i].getName().startsWith("test") ) { 88 testMethods.put( methods[i].getName(), methods[i] ); 89 } 90 } 91 } 92 93 protected void run(String[] args) throws Exception 94 { 95 System.out.println(getClass().getName() + " {"); 96 indentLevel++; 97 98 // Set up the log and reference streams. We use PrintWriters in order to 99 // take advantage of character conversion. The JavaEsc converter will 100 // convert Unicode outside the ASCII range to Java's \\uxxxx notation. 101 log = new PrintWriter(System.out,true); 102 103 // Parse the test arguments. They can be either the flag 104 // "-verbose" or names of test methods. Create a list of 105 // tests to be run. 106 Vector testsToRun = new Vector( args.length ); 107 for( int i=0; i<args.length; i++ ) { 108 if( args[i].equals("-verbose") ) { 109 verbose = true; 110 } 111 else if( args[i].equals("-prompt") ) { 112 prompt = true; 113 } else if (args[i].equals("-nothrow")) { 114 nothrow = true; 115 } else { 116 Object m = testMethods.get( args[i] ); 117 if( m != null ) { 118 testsToRun.addElement( m ); 119 } 120 else { 121 usage(); 122 return; 123 } 124 } 125 } 126 127 // If no test method names were given explicitly, run them all. 128 if( testsToRun.size() == 0 ) { 129 Enumeration methodNames = testMethods.elements(); 130 while( methodNames.hasMoreElements() ) { 131 testsToRun.addElement( methodNames.nextElement() ); 132 } 133 } 134 135 // Run the list of tests given in the test arguments 136 for( int i=0; i<testsToRun.size(); i++ ) { 137 int oldCount = errorCount; 138 139 Method testMethod = (Method)testsToRun.elementAt(i); 140 writeTestName(testMethod.getName()); 141 142 try { 143 testMethod.invoke(this, new Object[0]); 144 } 145 catch( IllegalAccessException e ) { 146 errln("Can't acces test method " + testMethod.getName()); 147 } 148 catch( InvocationTargetException e ) { 149 errorCount++; 150 log.println("\nUncaught throwable thrown in test method " 151 + testMethod.getName()); 152 e.getTargetException().printStackTrace(this.log); 153 if (!nothrow) { 154 throw new RuntimeException("Exiting..."); 155 } 156 } 157 writeTestResult(errorCount - oldCount); 158 } 159 indentLevel--; 160 writeTestResult(errorCount); 161 if (prompt) { 162 System.out.println("Hit RETURN to exit..."); 163 try { 164 System.in.read(); 165 } 166 catch (IOException e) { 167 System.out.println("Exception: " + e.toString() + e.getMessage()); 168 } 169 } 170 if (nothrow) { 171 System.exit(errorCount); 172 } 173 } 174 175 /** 176 * Adds given string to the log if we are in verbose mode. 177 */ 178 protected void log( String message ) { 179 if( verbose ) { 180 indent(indentLevel + 1); 181 log.print( message ); 182 log.flush(); 183 } 184 } 185 186 protected void logln( String message ) { 187 log(message + System.getProperty("line.separator")); 188 } 189 190 /** 191 * Report an error 192 */ 193 protected void err( String message ) { 194 errorCount++; 195 indent(indentLevel + 1); 196 log.print( message ); 197 log.flush(); 198 199 if (!nothrow) { 200 throw new RuntimeException(message); 201 } 202 } 203 204 protected void errln( String message ) { 205 err(message + System.getProperty("line.separator")); 206 } 207 208 209 protected void writeTestName(String testName) { 210 indent(indentLevel); 211 log.print(testName); 212 log.flush(); 213 needLineFeed = true; 214 } 215 216 protected void writeTestResult(int count) { 217 if (!needLineFeed) { 218 indent(indentLevel); 219 log.print("}"); 220 } 221 needLineFeed = false; 222 223 if (count != 0) 224 log.println(" FAILED"); 225 else 226 log.println(" Passed"); 227 } 228 229 private final void indent(int distance) { 230 if (needLineFeed) { 231 log.println(" {"); 232 needLineFeed = false; 233 } 234 log.print(spaces.substring(0, distance * 2)); 235 } 236 237 /** 238 * Print a usage message for this test class. 239 */ 240 void usage() { 241 System.out.println(getClass().getName() + 242 ": [-verbose] [-nothrow] [-prompt] [test names]"); 243 244 System.out.println("test names:"); 245 Enumeration methodNames = testMethods.keys(); 246 while( methodNames.hasMoreElements() ) { 247 System.out.println("\t" + methodNames.nextElement() ); 248 } 249 } 250 251 private boolean prompt = false; 252 private boolean nothrow = false; 253 protected boolean verbose = false; 254 255 private PrintWriter log; 256 private int indentLevel = 0; 257 private boolean needLineFeed = false; 258 private int errorCount = 0; 259 260 private Hashtable testMethods; 261 private final String spaces = " "; 262} 263