org.thingml.testing.reportbuilder.ReportBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.thingml.testing.reportbuilder.ReportBuilder.java

Source

/**
 * 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.
 *
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 */
package org.thingml.testing.reportbuilder;

import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.shade.org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.HTMLWriter;
import org.dom4j.io.OutputFormat;
import org.thingml.testing.reportbuilder.parser.Suite;
import org.thingml.testing.reportbuilder.parser.Test;

public class ReportBuilder {
    private List<Suite> results;
    private ConsoleLogger log;

    public ReportBuilder(List<Suite> parsed, ConsoleLogger logger) {
        results = parsed;
        log = logger;
    }

    public void saveToHTML(String path) throws IOException {
        Document document = DocumentHelper.createDocument();
        document.addDocType("html", null, null);
        Element html = document.addElement("html");
        Element head = html.addElement("head");
        Element body = html.addElement("body");

        buildHead(html, head);
        buildDocument(head, body);
        addModal(body);

        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setExpandEmptyElements(true);

        FileWriter file = new FileWriter(path);
        HTMLWriter writer = new HTMLWriter(file, format);
        writer.write(document);
        writer.close();
    }

    public void buildHead(Element html, Element head) {
        // Add Bootstrap
        html.addAttribute("lang", "en");
        head.addElement("meta").addAttribute("charset", "utf-8");
        head.addElement("meta").addAttribute("http-equiv", "X-UA-Compatible").addAttribute("content", "IE=edge");
        head.addElement("meta").addAttribute("name", "viewport").addAttribute("content",
                "width=device-width, initial-scale=1");
        head.addElement("link").addAttribute("rel", "stylesheet").addAttribute("href",
                "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css");

        // Add ChartJS
        head.addElement("script").addAttribute("src",
                "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js");

        // Add jQuery
        head.addElement("script").addAttribute("src", "https://code.jquery.com/jquery-3.2.1.min.js");
        head.addElement("script").addAttribute("src",
                "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js");

        // Import custom scripts
        addJavaScipt(head, "createCharts.js");
        addJavaScipt(head, "showModal.js");
        addJavaScipt(head, "filtering.js");

        // Import custom styles
        addStylesheet(head, "header.css");
        addStylesheet(head, "table.css");
    }

    private void buildDocument(Element head, Element body) {
        // Set title
        head.addElement("title").addText("ThingML :: Testing :: Report");

        // Add containers
        Element top = body.addElement("div").addAttribute("class", "jumbotron");
        Element main = body.addElement("div").addAttribute("class", "container-fluid");

        buildTestsSummary(top);
        buildSuites(main, results);
    }

    private void buildTestsSummary(Element parent) {
        Element container = parent.addElement("div").addAttribute("class", "container-fluid");

        Element topRow = container.addElement("div").addAttribute("class", "row");
        topRow.addElement("div").addAttribute("class", "col-sm-6").addElement("h1").addText("Summary");
        topRow.addElement("div").addAttribute("class", "col-sm-6 text-right").addElement("h3")
                .addText(Suite.countTests(results) + " tests in total");

        Element summaryRow = container.addElement("div").addAttribute("class", "row");
        // Add suite summaries
        for (Suite suite : results) {
            addSummaryChart(summaryRow.addElement("div").addAttribute("class", "col-sm-1"), suite.getName(),
                    suite.getSuiteSummary().simplify());
        }
        // Add compiler summaries
        for (Entry<String, Summary> compilerSummary : Suite.getCompilerSummaries(results).entrySet()) {
            addSummaryChart(summaryRow.addElement("div").addAttribute("class", "col-sm-1"),
                    compilerSummary.getKey(), compilerSummary.getValue().simplify());
        }

        // Add filterings
        Element filterRow = container.addElement("div").addAttribute("class", "row");
        filterRow.addElement("div").addAttribute("class", "col-sm-10");

        filterRow.addElement("div").addAttribute("class", "col-sm-2").addElement("button")
                .addAttribute("id", "thingml-only-failures").addAttribute("type", "button")
                .addAttribute("class", "btn btn-default").addText("Show only failures");
    }

    private void buildSuites(Element parent, List<Suite> suites) {
        for (Suite suite : suites) {
            String hasFailure = suite.hasFailure() ? " has-failure" : "";
            Element div = parent.addElement("div").addAttribute("class", "thingml-suite" + hasFailure);

            if (!suite.getTests().isEmpty()) {
                // Add title
                div.addElement("h1").addText(suite.getName()).addAttribute("style", "margin-top: 100px");

                // Add tests
                if (!suite.getTests().isEmpty())
                    buildTests(div, suite.getTests());
            }

            // Add children suits
            buildSuites(parent, suite.getSuites());
        }
    }

    private void buildTests(Element parent, List<Test> tests) {
        Element table = parent.addElement("table").addAttribute("class", "table table-hover");

        // Make colgroup so we can style columns
        Element colgroup = table.addElement("colgroup");
        colgroup.addElement("col");
        colgroup.addElement("col").addAttribute("span", "" + tests.size());

        // Build first row
        Element topRow = table.addElement("thead").addElement("tr");
        topRow.addElement("th"); // empty first cell
        for (Test test : tests) {
            String testHasFailure = test.hasFailure() ? " has-failure" : "";
            topRow.addElement("th").addAttribute("class", "thingml-test" + testHasFailure).addText(test.getName());
        }

        // Get all the compilers
        Set<String> compilers = Test.getCompilers(tests);

        Element tBody = table.addElement("tbody");
        for (String compiler : compilers) {
            Element row = tBody.addElement("tr");
            row.addElement("td").addText(compiler);

            for (Test test : tests) {
                TestCaseResult res = test.getTestCaseFullResult(compiler);
                String testHasFailure = test.hasFailure() ? " has-failure" : "";
                String testCaseHasFailure = res.getResult().simplify() == Result.FAILURE ? " has-failure" : "";

                row.addElement("td").addAttribute("class", "thingml-test" + testHasFailure).addElement("div")
                        .addAttribute("style", "background-color:" + res.getResult().toColor())
                        .addAttribute("title", res.getResult().toString()).addText(res.getResult().toIcon())
                        .addAttribute("class", "thingml-testcase-result" + testCaseHasFailure)
                        .addAttribute("data-result-message", res.getMessage())
                        .addAttribute("data-result-title", res.getTitle())
                        .addAttribute("data-result-error", res.getResult().toString());
            }
        }
    }

    /* --- Helpers --- */
    private void addSummaryChart(Element parent, String name, Summary summary) {
        parent.addElement("canvas").addAttribute("class", "thingml-summary").addAttribute("data-summary",
                "{ \"text\": \"" + name + "\", \"results\": " + summary.toJSON() + "}");
    }

    private void addModal(Element body) {
        Element content = body.addElement("div").addAttribute("class", "modal fade")
                .addAttribute("id", "thingml-message-modal").addAttribute("tabindex", "-1")
                .addAttribute("role", "dialog").addElement("div").addAttribute("class", "modal-dialog modal-lg")
                .addAttribute("role", "document").addElement("div").addAttribute("class", "modal-content");

        Element header = content.addElement("div").addAttribute("class", "modal-header");
        header.addElement("button").addAttribute("type", "button").addAttribute("class", "close")
                .addAttribute("data-dismiss", "modal").addAttribute("aria-label", "Close").addElement("span")
                .addAttribute("aria-hidden", "true").addText("x");
        header.addElement("h4").addAttribute("class", "modal-title").addText("Title");

        content.addElement("div").addAttribute("class", "modal-body").addElement("pre").addAttribute("class",
                "thingml-message panel-danger bg-danger text-danger");
    }

    private void addJavaScipt(Element head, String file) {
        head.addElement("script").addAttribute("type", "text/javascript").addText(readIncludedFile(file, log));
    }

    private void addStylesheet(Element head, String file) {
        head.addElement("style").addText(readIncludedFile(file, log));
    }

    /* --- Static helpers --- */
    private static String readIncludedFile(String file, ConsoleLogger log) {
        try {
            return IOUtils.toString(ReportBuilder.class.getResourceAsStream("/" + file));
        } catch (Exception e) {
            log.error("Couldn't read '" + file + "'", e);
            return "";
        }
    }
}