1 /* 2 * Copyright (c) 1998, 2016, 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 package test.java.text.testlib; 25 26 import java.io.IOException; 27 import java.io.PrintWriter; 28 import java.lang.reflect.InvocationTargetException; 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import java.util.ArrayList; 32 import java.util.Map; 33 import java.util.LinkedHashMap; 34 import java.util.List; 35 36 /** 37 * IntlTest is a base class for tests that can be run conveniently from 38 * the command line as well as under the Java test harness. 39 * <p> 40 * Sub-classes implement a set of public void methods named "Test*" or 41 * "test*" with no arguments. Each of these methods performs some 42 * test. Test methods should indicate errors by calling either err() or 43 * errln(). This will increment the errorCount field and may optionally 44 * print a message to the log. Debugging information may also be added to 45 * the log via the log and logln methods. These methods will add their 46 * arguments to the log only if the test is being run in verbose mode. 47 */ 48 public abstract class IntlTest { 49 50 //------------------------------------------------------------------------ 51 // Everything below here is boilerplate code that makes it possible 52 // to add a new test by simply adding a method to an existing class. 53 //------------------------------------------------------------------------ 54 IntlTest()55 protected IntlTest() { 56 // Populate testMethods with all the test methods. 57 Method[] methods = getClass().getDeclaredMethods(); 58 for (Method method : methods) { 59 if (Modifier.isPublic(method.getModifiers()) 60 && method.getReturnType() == void.class 61 && method.getParameterCount() == 0) { 62 String name = method.getName(); 63 if (name.length() > 4) { 64 if (name.startsWith("Test") || name.startsWith("test")) { 65 testMethods.put(name, method); 66 } 67 } 68 } 69 } 70 } 71 run(String[] args)72 protected void run(String[] args) throws Exception 73 { 74 // Set up the log and reference streams. We use PrintWriters in order to 75 // take advantage of character conversion. The JavaEsc converter will 76 // convert Unicode outside the ASCII range to Java's \\uxxxx notation. 77 log = new PrintWriter(System.out, true); 78 79 // Parse the test arguments. They can be either the flag 80 // "-verbose" or names of test methods. Create a list of 81 // tests to be run. 82 List<Method> testsToRun = new ArrayList<>(args.length); 83 for (String arg : args) { 84 switch (arg) { 85 case "-verbose": 86 verbose = true; 87 break; 88 case "-prompt": 89 prompt = true; 90 break; 91 case "-nothrow": 92 nothrow = true; 93 break; 94 case "-exitcode": 95 exitCode = true; 96 break; 97 default: 98 Method m = testMethods.get(arg); 99 if (m == null) { 100 System.out.println("Method " + arg + ": not found"); 101 usage(); 102 return; 103 } 104 testsToRun.add(m); 105 break; 106 } 107 } 108 109 // If no test method names were given explicitly, run them all. 110 if (testsToRun.isEmpty()) { 111 testsToRun.addAll(testMethods.values()); 112 } 113 114 System.out.println(getClass().getName() + " {"); 115 indentLevel++; 116 117 // Run the list of tests given in the test arguments 118 for (Method testMethod : testsToRun) { 119 int oldCount = errorCount; 120 121 writeTestName(testMethod.getName()); 122 123 try { 124 testMethod.invoke(this, new Object[0]); 125 } catch (IllegalAccessException e) { 126 errln("Can't acces test method " + testMethod.getName()); 127 } catch (InvocationTargetException e) { 128 errln("Uncaught exception thrown in test method " 129 + testMethod.getName()); 130 e.getTargetException().printStackTrace(this.log); 131 } 132 writeTestResult(errorCount - oldCount); 133 } 134 indentLevel--; 135 writeTestResult(errorCount); 136 137 if (prompt) { 138 System.out.println("Hit RETURN to exit..."); 139 try { 140 System.in.read(); 141 } catch (IOException e) { 142 System.out.println("Exception: " + e.toString() + e.getMessage()); 143 } 144 } 145 if (nothrow) { 146 if (exitCode) { 147 System.exit(errorCount); 148 } 149 if (errorCount > 0) { 150 throw new IllegalArgumentException("encountered " + errorCount + " errors"); 151 } 152 } 153 } 154 155 /** 156 * Adds the given message to the log if we are in verbose mode. 157 */ log(String message)158 protected void log(String message) { 159 logImpl(message, false); 160 } 161 logln(String message)162 protected void logln(String message) { 163 logImpl(message, true); 164 } 165 logln()166 protected void logln() { 167 logImpl(null, true); 168 } 169 logImpl(String message, boolean newline)170 private void logImpl(String message, boolean newline) { 171 if (verbose) { 172 if (message != null) { 173 indent(indentLevel + 1); 174 log.print(message); 175 } 176 if (newline) { 177 log.println(); 178 } 179 } 180 } 181 err(String message)182 protected void err(String message) { 183 errImpl(message, false); 184 } 185 errln(String message)186 protected void errln(String message) { 187 errImpl(message, true); 188 } 189 errImpl(String message, boolean newline)190 private void errImpl(String message, boolean newline) { 191 errorCount++; 192 indent(indentLevel + 1); 193 log.print(message); 194 if (newline) { 195 log.println(); 196 } 197 log.flush(); 198 199 if (!nothrow) { 200 throw new RuntimeException(message); 201 } 202 } 203 getErrorCount()204 protected int getErrorCount() { 205 return errorCount; 206 } 207 writeTestName(String testName)208 protected void writeTestName(String testName) { 209 indent(indentLevel); 210 log.print(testName); 211 log.flush(); 212 needLineFeed = true; 213 } 214 writeTestResult(int count)215 protected void writeTestResult(int count) { 216 if (!needLineFeed) { 217 indent(indentLevel); 218 log.print("}"); 219 } 220 needLineFeed = false; 221 222 if (count != 0) { 223 log.println(" FAILED"); 224 } else { 225 log.println(" Passed"); 226 } 227 } 228 229 /* 230 * Returns a spece-delimited hex String. 231 */ toHexString(String s)232 protected static String toHexString(String s) { 233 StringBuilder sb = new StringBuilder(" "); 234 235 for (int i = 0; i < s.length(); i++) { 236 sb.append(Integer.toHexString(s.charAt(i))); 237 sb.append(' '); 238 } 239 240 return sb.toString(); 241 } 242 indent(int distance)243 private void indent(int distance) { 244 if (needLineFeed) { 245 log.println(" {"); 246 needLineFeed = false; 247 } 248 log.print(SPACES.substring(0, distance * 2)); 249 } 250 251 /** 252 * Print a usage message for this test class. 253 */ usage()254 void usage() { 255 System.out.println(getClass().getName() + 256 ": [-verbose] [-nothrow] [-exitcode] [-prompt] [test names]"); 257 258 System.out.println(" Available test names:"); 259 for (String methodName : testMethods.keySet()) { 260 System.out.println("\t" + methodName); 261 } 262 } 263 264 private boolean prompt; 265 private boolean nothrow; 266 protected boolean verbose; 267 private boolean exitCode; 268 private PrintWriter log; 269 private int indentLevel; 270 private boolean needLineFeed; 271 private int errorCount; 272 273 private final Map<String, Method> testMethods = new LinkedHashMap<>(); 274 275 private static final String SPACES = " "; 276 } 277