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
24import java.lang.reflect.*;
25import java.util.Hashtable;
26import java.util.Enumeration;
27import java.util.Vector;
28import java.io.*;
29import java.text.*;
30
31/**
32 * IntlTest is a base class for tests that can be run conveniently from
33 * the command line as well as under the Java test harness.
34 * <p>
35 * Sub-classes implement a set of methods named Test<something>. Each
36 * of these methods performs some test. Test methods should indicate
37 * errors by calling either err or errln.  This will increment the
38 * errorCount field and may optionally print a message to the log.
39 * Debugging information may also be added to the log via the log
40 * and logln methods.  These methods will add their arguments to the
41 * log only if the test is being run in verbose mode.
42 */
43public class IntlTest {
44
45    //------------------------------------------------------------------------
46    // Everything below here is boilerplate code that makes it possible
47    // to add a new test by simply adding a function to an existing class
48    //------------------------------------------------------------------------
49
50    protected IntlTest() {
51        // Create a hashtable containing all the test methods.
52        testMethods = new Hashtable();
53        Method[] methods = getClass().getDeclaredMethods();
54        for( int i=0; i<methods.length; i++ ) {
55            if( methods[i].getName().startsWith("Test") ) {
56                testMethods.put( methods[i].getName(), methods[i] );
57            }
58        }
59    }
60
61    protected void run(String[] args) throws Exception
62    {
63        System.out.println(getClass().getName() + " {");
64        indentLevel++;
65
66        // Set up the log and reference streams.  We use PrintWriters in order to
67        // take advantage of character conversion.  The JavaEsc converter will
68        // convert Unicode outside the ASCII range to Java's \\uxxxx notation.
69        log = new PrintWriter(System.out,true);
70
71        // Parse the test arguments.  They can be either the flag
72        // "-verbose" or names of test methods. Create a list of
73        // tests to be run.
74        Vector testsToRun = new Vector( args.length );
75        for( int i=0; i<args.length; i++ ) {
76            if( args[i].equals("-verbose") ) {
77                verbose = true;
78            }
79            else if( args[i].equals("-prompt") ) {
80                prompt = true;
81            } else if (args[i].equals("-nothrow")) {
82                nothrow = true;
83            } else {
84                Object m = testMethods.get( args[i] );
85                if( m != null ) {
86                    testsToRun.addElement( m );
87                }
88                else {
89                    usage();
90                    return;
91                }
92            }
93        }
94
95        // If no test method names were given explicitly, run them all.
96        if( testsToRun.size() == 0 ) {
97            Enumeration methodNames = testMethods.elements();
98            while( methodNames.hasMoreElements() ) {
99                testsToRun.addElement( methodNames.nextElement() );
100            }
101        }
102
103        // Run the list of tests given in the test arguments
104        for( int i=0; i<testsToRun.size(); i++ ) {
105            int oldCount = errorCount;
106
107            Method testMethod = (Method)testsToRun.elementAt(i);
108            writeTestName(testMethod.getName());
109
110            try {
111                testMethod.invoke(this, new Object[0]);
112            }
113            catch( IllegalAccessException e ) {
114                errln("Can't acces test method " + testMethod.getName());
115            }
116            catch( InvocationTargetException e ) {
117                errln("Uncaught exception thrown in test method "
118                               + testMethod.getName());
119                e.getTargetException().printStackTrace(this.log);
120            }
121            writeTestResult(errorCount - oldCount);
122        }
123        indentLevel--;
124        writeTestResult(errorCount);
125
126        if (prompt) {
127            System.out.println("Hit RETURN to exit...");
128            try {
129                System.in.read();
130            }
131            catch (IOException e) {
132                System.out.println("Exception: " + e.toString() + e.getMessage());
133            }
134        }
135        if (nothrow) {
136            System.exit(errorCount);
137        }
138    }
139
140    /**
141     * Adds given string to the log if we are in verbose mode.
142     */
143    protected void log( String message ) {
144        if( verbose ) {
145            indent(indentLevel + 1);
146            log.print( message );
147        }
148    }
149
150    protected void logln( String message ) {
151        log(message + System.getProperty("line.separator"));
152    }
153
154    /**
155     * Report an error
156     */
157    protected void err( String message ) {
158        errorCount++;
159        indent(indentLevel + 1);
160        log.print( message );
161        log.flush();
162
163        if (!nothrow) {
164            throw new RuntimeException(message);
165        }
166    }
167
168    protected void errln( String message ) {
169        err(message + System.getProperty("line.separator"));
170    }
171
172
173    protected void writeTestName(String testName) {
174        indent(indentLevel);
175        log.print(testName);
176        log.flush();
177        needLineFeed = true;
178    }
179
180    protected void writeTestResult(int count) {
181        if (!needLineFeed) {
182            indent(indentLevel);
183            log.print("}");
184        }
185        needLineFeed = false;
186
187        if (count != 0)
188            log.println(" FAILED");
189        else
190            log.println(" Passed");
191    }
192
193    private final void indent(int distance) {
194        if (needLineFeed) {
195            log.println(" {");
196            needLineFeed = false;
197        }
198        log.print(spaces.substring(0, distance * 2));
199    }
200
201    /**
202     * Print a usage message for this test class.
203     */
204    void usage() {
205        System.out.println(getClass().getName() +
206                            ": [-verbose] [-nothrow] [-prompt] [test names]");
207
208        System.out.println("test names:");
209        Enumeration methodNames = testMethods.keys();
210        while( methodNames.hasMoreElements() ) {
211            System.out.println("\t" + methodNames.nextElement() );
212        }
213    }
214
215    private boolean     prompt = false;
216    private boolean     nothrow = false;
217    protected boolean   verbose = false;
218
219    private PrintWriter log;
220    private int         indentLevel = 0;
221    private boolean     needLineFeed = false;
222    private int         errorCount = 0;
223
224    private Hashtable testMethods;
225    private final String spaces = "                                          ";
226}
227
228//eof
229