1/*
2 * Copyright (C) 2016 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 */
16
17package android.icu.junit;
18
19import android.icu.dev.test.TestFmwk;
20import java.io.PrintWriter;
21import java.io.StringWriter;
22import java.util.regex.Matcher;
23import java.util.regex.Pattern;
24import junit.framework.AssertionFailedError;
25import org.junit.runner.Description;
26
27/**
28 * Represents a test within a {@link TestFmwk} class.
29 */
30final class IcuFrameworkTest implements Comparable<IcuFrameworkTest> {
31
32    private static final String[] EMPTY_ARGS = new String[0];
33
34    private static final Pattern EXTRACT_ERROR_INFO = Pattern.compile(
35            "^[A-Za-z0-9_]+ \\{(\n.*)\n\\}.*", Pattern.DOTALL);
36
37    /**
38     * The {@link TestFmwk} instance on which the tests will be run.
39     */
40    private final TestFmwk testFmwk;
41
42    private final TestFmwk.Target target;
43
44    /**
45     * The name of the individual target to run.
46     */
47    private final String methodName;
48
49    IcuFrameworkTest(TestFmwk testFmwk, TestFmwk.Target target, String methodName) {
50        this.testFmwk = testFmwk;
51        this.target = target;
52        this.methodName = methodName;
53    }
54
55    public String getMethodName() {
56        return methodName;
57    }
58
59    /**
60     * Runs the target.
61     */
62    public void run() {
63        test_for_TestFmwk_Run();
64    }
65
66    /**
67     * A special method to avoid the TestFmwk from throwing an InternalError when an error occurs
68     * during execution of the test but outside the actual test method, e.g. in a
69     * {@link TestFmwk#validate()} method. See http://bugs.icu-project.org/trac/ticket/12183
70     *
71     * <p>DO NOT CHANGE THE NAME
72     */
73    private void test_for_TestFmwk_Run() {
74        StringWriter stringWriter = new StringWriter();
75        PrintWriter log = new PrintWriter(stringWriter);
76
77        TestFmwk.TestParams localParams = TestFmwk.TestParams.create(EMPTY_ARGS, log);
78        if (localParams == null) {
79            throw new IllegalStateException("Could not create params");
80        }
81
82        // We don't want an error summary as we are only running one test.
83        localParams.errorSummary = null;
84
85        try {
86            // Make sure that the TestFmwk is initialized with the correct parameters. This method
87            // is being called solely for its side effect of updating the TestFmwk.params field.
88            testFmwk.resolveTarget(localParams);
89
90            // Run the target.
91            target.run();
92        } catch (Exception e) {
93            // Output the exception to the log and make sure it is treated as an error.
94            e.printStackTrace(log);
95            localParams.errorCount++;
96        }
97
98        // Treat warnings as errors.
99        int errorCount = localParams.errorCount + localParams.warnCount;
100
101        // Ensure that all data is written to the StringWriter.
102        log.flush();
103
104        // Treat warnings as errors.
105        String information = stringWriter.toString();
106        if (errorCount != 0) {
107            // Remove unnecessary formatting.
108            Matcher matcher = EXTRACT_ERROR_INFO.matcher(information);
109            if (matcher.matches()) {
110                information = matcher.group(1)/*.replace("\n    ", "\n")*/;
111            }
112
113            // Also append the logs to the console output.
114            String output = "Failure: " + getDescription() + ", due to "
115                    + errorCount + " error(s)\n" + information;
116
117            throw new AssertionFailedError(output);
118        }
119    }
120
121    /**
122     * Get the JUnit {@link Description}
123     */
124    public Description getDescription() {
125        // Get a description for the specific method within the class.
126        return Description.createTestDescription(testFmwk.getClass(), methodName);
127    }
128
129    @Override
130    public int compareTo(IcuFrameworkTest o) {
131        return methodName.compareTo(o.methodName);
132    }
133}
134