CoreTestResult.java revision a7a1b49769a5619178aa782966da3d8384c7cc10
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.google.coretests;
17
18import java.lang.reflect.Method;
19
20import junit.framework.Protectable;
21import junit.framework.Test;
22import junit.framework.TestCase;
23import junit.framework.TestResult;
24import dalvik.annotation.KnownFailure;
25import dalvik.annotation.SideEffect;
26
27/**
28 * A special TestResult implementation that is able to filter out annotated
29 * tests and handles our known failures properly (expects them to fail).
30 * Handy when running the Core Libraries tests on Android, the bare-metal
31 * Dalvik VM, or the RI.
32 */
33public class CoreTestResult extends TestResult {
34
35    /**
36     * The flags the user specified for this test run.
37     */
38    protected int fFlags;
39
40    /**
41     * The timeout the user specified for this test run.
42     */
43    protected int fTimeout;
44
45    /**
46     * The total number of tests in the original suite.
47     */
48    protected int fTotalTestCount;
49
50    /**
51     * The number of Android-only tests in the original suite.
52     */
53    protected int fAndroidOnlyCount;
54
55    /**
56     * The number of broken tests in the original suite.
57     */
58    protected int fBrokenTestCount;
59
60    /**
61     * The number of known failures in the original suite.
62     */
63    protected int fKnownFailureCount;
64
65    /**
66     * The number of side-effective tests in the original suite.
67     */
68    protected int fSideEffectCount;
69
70    /**
71     * The number of normal (non-annotated) tests in the original suite.
72     */
73    protected int fNormalTestCount;
74
75    /**
76     * The number of ignored tests, that is, the number of tests that were
77     * excluded from this suite due to their annotations.
78     */
79    protected int fIgnoredCount;
80
81    /**
82     * Creates a new CoreTestResult with the given flags and timeout.
83     */
84    public CoreTestResult(int flags, int timeout) {
85        super();
86
87        fFlags = flags;
88        fTimeout = timeout;
89    }
90
91    /**
92     * Checks whether the given TestCase method has the given annotation.
93     */
94    @SuppressWarnings("unchecked")
95    boolean hasAnnotation(TestCase test, Class clazz) {
96        try {
97            Method method = test.getClass().getMethod(test.getName());
98            return method.getAnnotation(clazz) != null;
99        } catch (Exception e) {
100            // Ignore
101        }
102
103        return false;
104    }
105
106    @Override
107    @SuppressWarnings("deprecation")
108    public void runProtected(final Test test, Protectable p) {
109        if ((fFlags & CoreTestSuite.DRY_RUN) == 0) {
110            if (test instanceof TestCase) {
111                TestCase testCase = (TestCase)test;
112
113                // Check whether we need to invert the test result (known failures)
114                boolean invert = hasAnnotation(testCase, KnownFailure.class) &&
115                        (fFlags & CoreTestSuite.INVERT_KNOWN_FAILURES) != 0;
116
117                // Check whether we need to isolate the test (side effects)
118                boolean isolate = hasAnnotation(testCase, SideEffect.class) &&
119                        (fFlags & CoreTestSuite.ISOLATE_NONE) == 0 ||
120                        (fFlags & CoreTestSuite.ISOLATE_ALL) != 0;
121
122                CoreTestRunnable runnable = new CoreTestRunnable(
123                        testCase, this, p, invert, isolate);
124
125                if (fTimeout > 0) {
126                    Thread thread = new Thread(runnable);
127                    thread.start();
128                    try {
129                        thread.join(fTimeout * 1000);
130                    } catch (InterruptedException ex) {
131                        // Ignored
132                    }
133                    if (thread.isAlive()) {
134                        StackTraceElement[] trace = thread.getStackTrace();
135                        runnable.stop();
136                        thread.stop();
137                        try {
138                            thread.join(fTimeout * 1000);
139                        } catch (InterruptedException ex) {
140                            // Ignored
141                        }
142
143                        CoreTestTimeout timeout = new CoreTestTimeout("Test timed out");
144                        timeout.setStackTrace(trace);
145                        addError(test, timeout);
146                    }
147                } else {
148                    runnable.run();
149                }
150            }
151        }
152    }
153
154    /**
155     * Updates the statistics in this TestResult. Called from the TestSuite,
156     * since, once the original suite has been filtered, we don't actually see
157     * these tests here anymore.
158     */
159    void updateStats(int total, int androidOnly, int broken, int knownFailure,
160            int normal, int ignored, int sideEffect) {
161
162        this.fTotalTestCount += total;
163        this.fAndroidOnlyCount += androidOnly;
164        this.fBrokenTestCount += broken;
165        this.fKnownFailureCount += knownFailure;
166        this.fNormalTestCount += normal;
167        this.fIgnoredCount += ignored;
168        this.fSideEffectCount += sideEffect;
169    }
170}
171