TestRunner.java revision 3573:c4a18ee691c4
11541Srgrimes/*
21541Srgrimes * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41541Srgrimes *
51541Srgrimes * This code is free software; you can redistribute it and/or modify it
61541Srgrimes * under the terms of the GNU General Public License version 2 only, as
71541Srgrimes * published by the Free Software Foundation.
81541Srgrimes *
91541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT
101541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
111541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
121541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that
131541Srgrimes * accompanied this code).
141541Srgrimes *
151541Srgrimes * You should have received a copy of the GNU General Public License version
161541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation,
171541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
181541Srgrimes *
191541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
201541Srgrimes * or visit www.oracle.com if you need additional information or have any
211541Srgrimes * questions.
221541Srgrimes */
231541Srgrimes
241541Srgrimespackage toolbox;
251541Srgrimes
261541Srgrimesimport java.io.PrintStream;
271541Srgrimesimport java.lang.annotation.Annotation;
281541Srgrimesimport java.lang.annotation.Retention;
291541Srgrimesimport java.lang.annotation.RetentionPolicy;
301541Srgrimesimport java.lang.reflect.InvocationTargetException;
311541Srgrimesimport java.lang.reflect.Method;
321541Srgrimesimport java.util.function.Function;
331541Srgrimes
341541Srgrimes/**
351541Srgrimes * Utility class to manage and execute sub-tests within a test.
361541Srgrimes *
371541Srgrimes * This class does the following:
3814476Shsu * <ul>
3950477Speter * <li>  invokes those test methods annotated with @Test
401541Srgrimes * <li>  keeps track of successful and failed tests
411541Srgrimes * <li>  throws an Exception if any test fails.
4260041Sphk * <li>  provides a test summary at the end of the run.
4360041Sphk * </ul>
4415493Sbde
451541Srgrimes * Tests must extend this class, annotate the test methods
461541Srgrimes * with @Test and call one of the runTests method.
4759840Sphk */
486549Sbdepublic abstract class TestRunner {
496549Sbde   /** Marker annotation for test cases. */
506549Sbde    @Retention(RetentionPolicy.RUNTIME)
516549Sbde    public @interface Test { }
5259840Sphk
536549Sbde    int testCount = 0;
546549Sbde    int errorCount = 0;
556549Sbde
566549Sbde    public String testName = null;
576549Sbde
586549Sbde    protected PrintStream out;
596549Sbde
601541Srgrimes    /**
6158934Sphk     * Constructs the Object.
6258926Sphk     * @param out the PrintStream to print output to.
6358926Sphk     */
6458934Sphk    public TestRunner(PrintStream out) {
6558934Sphk        this.out = out;
6658926Sphk    }
6758942Sphk
6858942Sphk    /**
6958942Sphk     * Invoke all methods annotated with @Test.
7058934Sphk     * @throws java.lang.Exception if any errors occur
7158934Sphk     */
7258934Sphk    protected void runTests() throws Exception {
7358934Sphk        runTests(f -> new Object[0]);
7459840Sphk    }
7558934Sphk
7658934Sphk    /**
7758934Sphk     * Invoke all methods annotated with @Test.
7858934Sphk     * @param f a lambda expression to specify arguments for the test method
7960938Sjake     * @throws java.lang.Exception if any errors occur
8058934Sphk     */
8158934Sphk    protected void runTests(Function<Method, Object[]> f) throws Exception {
8258934Sphk        for (Method m : getClass().getDeclaredMethods()) {
8358934Sphk            Annotation a = m.getAnnotation(Test.class);
8458926Sphk            if (a != null) {
8558926Sphk                testName = m.getName();
8658345Sphk                try {
8758345Sphk                    testCount++;
8858345Sphk                    out.println("test: " + testName);
8958942Sphk                    m.invoke(this, f.apply(m));
9058345Sphk                } catch (InvocationTargetException e) {
9160041Sphk                    errorCount++;
9260041Sphk                    Throwable cause = e.getCause();
9360041Sphk                    out.println("Exception: " + e.getCause());
9459915Sphk                    cause.printStackTrace(out);
9559915Sphk                }
9658934Sphk                out.println();
9755205Speter            }
9848225Smckusick        }
9960041Sphk
10060041Sphk        if (testCount == 0) {
10148225Smckusick            throw new Error("no tests found");
10260041Sphk        }
10360041Sphk
10448225Smckusick        StringBuilder summary = new StringBuilder();
10548273Speter        if (testCount != 1) {
10658942Sphk            summary.append(testCount).append(" tests");
10760938Sjake        }
10858942Sphk        if (errorCount > 0) {
10958942Sphk            if (summary.length() > 0) {
11058942Sphk                summary.append(", ");
11158942Sphk            }
11258942Sphk            summary.append(errorCount).append(" errors");
11358942Sphk        }
11458942Sphk        out.println(summary);
11558942Sphk        if (errorCount > 0) {
11658942Sphk            throw new Exception(errorCount + " errors found");
11758942Sphk        }
11858942Sphk    }
11939238Sgibbs
12029683Sgibbs    protected void error(String message) {
12158942Sphk        out.println("Error: " + message);
12258942Sphk        errorCount++;
12358942Sphk    }
12458942Sphk}
12558942Sphk