com.gargoylesoftware.htmlunit.runners.TestCaseCorrector.java Source code

Java tutorial

Introduction

Here is the source code for com.gargoylesoftware.htmlunit.runners.TestCaseCorrector.java

Source

/*
 * Copyright (c) 2002-2016 Gargoyle Software Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gargoylesoftware.htmlunit.runners;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.ComparisonFailure;
import org.junit.runners.model.FrameworkMethod;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.CodeStyleTest;
import com.gargoylesoftware.htmlunit.general.HostExtractor;

/**
 * This is meant to automatically correct the test case to put either the real browser expectations,
 * or the {@link com.gargoylesoftware.htmlunit.BrowserRunner.NotYetImplemented} annotation for HtmlUnit.
 *
 * @author Ahmed Ashour
 */
final class TestCaseCorrector {

    private TestCaseCorrector() {
    }

    static void correct(final FrameworkMethod method, final boolean realBrowser,
            final BrowserVersion browserVersion, final boolean notYetImplemented, final Throwable t)
            throws IOException {
        final String testRoot = "src/test/java/";
        final String browserString = browserVersion.getNickname().toUpperCase(Locale.ROOT);
        final File file = new File(testRoot + method.getDeclaringClass().getName().replace('.', '/') + ".java");
        final List<String> lines = FileUtils.readLines(file);
        final String methodLine = "    public void " + method.getName() + "()";
        if (realBrowser) {
            String defaultExpectation = null;
            for (int i = 0; i < lines.size(); i++) {
                if ("    @Default".equals(lines.get(i))) {
                    defaultExpectation = getDefaultExpectation(lines, i);
                }
                if (lines.get(i).startsWith(methodLine)) {
                    i = addExpectation(lines, i, browserString, (ComparisonFailure) t);
                    break;
                }
                if (i == lines.size() - 2) {
                    addMethodWithExpectation(lines, i, browserString, method.getName(), (ComparisonFailure) t,
                            defaultExpectation);
                    break;
                }
            }
        } else if (!notYetImplemented) {
            String defaultExpectation = null;
            for (int i = 0; i < lines.size(); i++) {
                if ("    @Default".equals(lines.get(i))) {
                    defaultExpectation = getDefaultExpectation(lines, i);
                }
                if (lines.get(i).startsWith(methodLine)) {
                    addNotYetImplemented(lines, i, browserString);
                    break;
                }
                if (i == lines.size() - 2) {
                    addNotYetImplementedMethod(lines, i, browserString, method.getName(), defaultExpectation);
                    break;
                }
            }
        } else {
            for (int i = 0; i < lines.size(); i++) {
                if (lines.get(i).startsWith(methodLine)) {
                    removeNotYetImplemented(lines, i, browserString);
                    break;
                }
            }
        }
        FileUtils.writeLines(file, lines);
    }

    private static String getDefaultExpectation(final List<String> lines, final int defaultIndex) {
        int index = defaultIndex;
        while (index >= 0 && !lines.get(index).contains("Alerts")) {
            index--;
        }
        if (index >= 0) {
            final String line = lines.get(index);
            return line.substring(line.indexOf('"') + 1, line.lastIndexOf('"'));
        }
        return null;
    }

    private static int addExpectation(final List<String> lines, int i, final String browserString,
            final ComparisonFailure comparisonFailure) {
        while (!lines.get(i).startsWith("    @Alerts")) {
            i--;
        }
        final List<String> alerts = CodeStyleTest.alertsToList(lines, i);
        for (final Iterator<String> it = alerts.iterator(); it.hasNext();) {
            if (it.next().startsWith(browserString + " = ")) {
                it.remove();
            }
        }
        alerts.add(browserString + " = " + getActualString(comparisonFailure));
        lines.remove(i);
        while (lines.get(i).startsWith("        ")) {
            lines.remove(i);
        }
        for (int x = 0; x < alerts.size(); x++) {
            String line = alerts.get(x);
            if (x == 0) {
                if (!line.contains(" = ")) {
                    line = "DEFAULT = " + line;
                }
                line = "    @Alerts(" + line;
            } else {
                line = "            " + line;
            }
            if (x < alerts.size() - 1) {
                line += ",";
            } else {
                line += ")";
            }
            lines.add(i++, line);
        }
        return i;
    }

    private static String getActualString(final ComparisonFailure failure) {
        String actual = failure.getActual();
        actual = actual.substring(1, actual.length() - 1).replace("\r", "\\r").replace("\n", "\\n");
        if (actual.length() > 96) {
            final StringBuilder builder = new StringBuilder();
            while (!actual.isEmpty()) {
                int length = actual.lastIndexOf(',', 96) + 1;
                if (length == 0 && !actual.isEmpty()) {
                    length = Math.min(96, actual.length());
                }
                if (builder.length() != 0) {
                    builder.append(System.lineSeparator()).append("                + ");
                }
                builder.append('"').append(actual.substring(0, length)).append('"');
                actual = actual.substring(length);
            }
            return builder.toString();
        }
        return "\"" + actual + "\"";
    }

    private static void removeNotYetImplemented(final List<String> lines, final int i, final String browserString) {
        final String previous = lines.get(i - 1);
        if (previous.contains("@NotYetImplemented")) {
            if (previous.indexOf('(') != -1) {
                final int p0 = previous.indexOf('(') + 1;
                final int p1 = previous.lastIndexOf(')');
                String browsers = previous.substring(p0, p1);
                if (browsers.indexOf('{') != -1) {
                    browsers = browsers.substring(1, browsers.length() - 1).trim();
                }
                final Set<String> browserSet = new HashSet<>();
                for (final String browser : browsers.split(",")) {
                    browserSet.add(browser.trim());
                }
                browserSet.remove(browserString);
                if (browserSet.size() == 1) {
                    lines.set(i - 1, "    @NotYetImplemented(" + browserSet.iterator().next() + ")");
                } else if (browserSet.size() > 1) {
                    lines.set(i - 1, "    @NotYetImplemented({ " + StringUtils.join(browserSet, ", ") + " })");
                } else {
                    lines.remove(i - 1);
                }
            } else {
                final List<String> allBrowsers = new ArrayList<>(
                        Arrays.asList("CHROME", "IE11", "FF31", "FF38", "EDGE"));
                for (final Iterator<String> it = allBrowsers.iterator(); it.hasNext();) {
                    if (it.next().equals(browserString)) {
                        it.remove();
                    }
                }
                lines.set(i - 1, "    @NotYetImplemented({ " + StringUtils.join(allBrowsers, ", ") + " })");
            }
        }
    }

    private static void addNotYetImplementedMethod(final List<String> lines, int i, final String browserString,
            final String methodName, final String defaultExpectations) {
        String parent = methodName;
        final String child = parent.substring(parent.lastIndexOf('_') + 1);
        parent = parent.substring(1, parent.indexOf('_', 1));

        if (!lines.get(i).isEmpty()) {
            i++;
        }
        lines.add(i++, "");
        lines.add(i++, "    /**");
        lines.add(i++, "     * @throws Exception if the test fails");
        lines.add(i++, "     */");
        lines.add(i++, "    @Test");
        lines.add(i++, "    @Alerts(\"" + defaultExpectations + "\")");
        lines.add(i++, "    @NotYetImplemented(" + browserString + ")");
        lines.add(i++, "    public void _" + parent + "_" + child + "() throws Exception {");
        lines.add(i++, "        test(\"" + parent + "\", \"" + child + "\");");
        lines.add(i++, "    }");
        lines.add(i++, "}");
        while (lines.size() > i) {
            lines.remove(i);
        }
    }

    private static void addNotYetImplemented(final List<String> lines, final int i, final String browserString) {
        final String previous = lines.get(i - 1);
        if (previous.contains("@NotYetImplemented")) {
            if (previous.indexOf('(') != -1 && !previous.contains(browserString)) {
                final int p0 = previous.indexOf('(') + 1;
                final int p1 = previous.lastIndexOf(')');
                String browsers = previous.substring(p0, p1);
                if (browsers.indexOf('{') != -1) {
                    browsers = browsers.substring(1, browsers.length() - 1).trim();
                }
                browsers += ", " + browserString;
                lines.set(i - 1, "    @NotYetImplemented({ " + browsers + " })");
            }
        } else {
            lines.add(i, "    @NotYetImplemented(" + browserString + ")");
        }
    }

    private static void addMethodWithExpectation(final List<String> lines, int i, final String browserString,
            final String methodName, final ComparisonFailure comparisonFailure, final String defaultExpectations) {
        String parent = methodName;
        final String child = parent.substring(parent.lastIndexOf('_') + 1);
        final int index = parent.indexOf('_', 1);
        if (index != -1) {
            parent = parent.substring(1, index);
        } else {
            parent = parent.substring(1);
        }

        if (!lines.get(i).isEmpty()) {
            i++;
        }
        lines.add(i++, "");
        lines.add(i++, "    /**");
        lines.add(i++, "     * @throws Exception if the test fails");
        lines.add(i++, "     */");
        lines.add(i++, "    @Test");
        lines.add(i++, "    @Alerts(DEFAULT = \"" + defaultExpectations + "\",");
        lines.add(i++, "            " + browserString + " = " + getActualString(comparisonFailure) + ")");
        if (index != -1) {
            lines.add(i++, "    public void _" + parent + "_" + child + "() throws Exception {");
            lines.add(i++, "        test(\"" + parent + "\", \"" + child + "\");");
        } else {
            String method = parent;
            for (final String prefix : HostExtractor.PREFIXES_) {
                if (method.startsWith(prefix)) {
                    method = prefix.toLowerCase(Locale.ROOT) + method.substring(prefix.length());
                    break;
                }
            }
            if (Character.isUpperCase(method.charAt(0))) {
                method = Character.toLowerCase(method.charAt(0)) + method.substring(1);
            }
            lines.add(i++, "    public void " + method + "() throws Exception {");
            lines.add(i++, "        test(\"" + parent + "\");");
        }
        lines.add(i++, "    }");
        lines.add(i++, "}");
        while (lines.size() > i) {
            lines.remove(i);
        }
    }
}