Make the Gradle plugin compatible with 1.5
Xavier Ducrohet [Fri, 22 Mar 2013 23:52:35 +0000 (16:52 -0700)]
Change-Id: I6f71d0b9dc8a31b5858a5ef63588356266c4611f

gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/ClassPageRenderer.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/OverviewPageRenderer.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/PackagePageRenderer.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/PageRenderer.java

index f553389..223ca76 100644 (file)
@@ -19,11 +19,12 @@ package com.android.build.gradle.internal.test.report;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
-import org.gradle.api.Action;
+import org.gradle.api.internal.ErroringAction;
+import org.gradle.api.internal.html.SimpleHtmlWriter;
 import org.gradle.api.internal.tasks.testing.junit.report.TestFailure;
 import org.gradle.reporting.CodePanelRenderer;
-import org.w3c.dom.Element;
 
+import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -46,21 +47,21 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
         return getModel().getTitle();
     }
 
-    @Override protected void renderBreadcrumbs(Element parent) {
-        Element div = append(parent, "div");
-        div.setAttribute("class", "breadcrumbs");
-        appendLink(div, "index.html", "all");
-        appendText(div, " > ");
-        appendLink(div,
-                String.format("%s.html", getResults().getPackageResults().getFilename(reportType)),
-                getResults().getPackageResults().getName());
-        appendText(div, String.format(" > %s", getResults().getSimpleName()));
+    @Override
+    protected void renderBreadcrumbs(SimpleHtmlWriter htmlWriter) throws IOException {
+        htmlWriter.startElement("div").attribute("class", "breadcrumbs")
+                .startElement("a").attribute("href", "index.html").characters("all").endElement()
+                .characters(" > ")
+                .startElement("a").attribute("href", String.format("%s.html", getResults().getPackageResults().getFilename(reportType))).characters(getResults().getPackageResults().getName()).endElement()
+                .characters(String.format(" > %s", getResults().getSimpleName()))
+        .endElement();
     }
 
-    private void renderTests(Element parent) {
-        Element table = append(parent, "table");
-        Element thead = append(table, "thead");
-        Element tr = append(thead, "tr");
+    private void renderTests(SimpleHtmlWriter htmlWriter) throws IOException {
+        htmlWriter.startElement("table")
+                .startElement("thead")
+                .startElement("tr")
+                .startElement("th").characters("Test").endElement();
 
         // get all the results per device and per test name
         Map<String, Map<String, TestResult>> results = getResults().getTestResultsMap();
@@ -69,10 +70,10 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
         List<String> devices = Lists.newArrayList(results.keySet());
         Collections.sort(devices);
 
-        appendWithText(tr, "th", "Test");
         for (String device : devices) {
-            appendWithText(tr, "th", device);
+            htmlWriter.startElement("th").characters(device).endElement();
         }
+        htmlWriter.endElement().endElement(); // tr/thead
 
         // gather all tests
         Set<String> tests = Sets.newHashSet();
@@ -83,8 +84,7 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
         Collections.sort(sortedTests);
 
         for (String testName : sortedTests) {
-            tr = append(table, "tr");
-            Element td = appendWithText(tr, "td", testName);
+            htmlWriter.startElement("tr").startElement("td").characters(testName).endElement();
 
             ResultType currentType = ResultType.SKIPPED;
 
@@ -93,17 +93,20 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
                 Map<String, TestResult> deviceMap = results.get(device);
                 TestResult test = deviceMap.get(testName);
 
-                Element deviceTd = appendWithText(tr, "td",
-                        String.format("%s (%s)",
-                                test.getFormattedResultType(), test.getFormattedDuration()));
-                deviceTd.setAttribute("class", test.getStatusClass());
+                htmlWriter.startElement("td").attribute("class", test.getStatusClass())
+                        .characters(String.format("%s (%s)",
+                            test.getFormattedResultType(), test.getFormattedDuration()))
+                .endElement();
 
                 currentType = combineResultType(currentType, test.getResultType());
             }
 
             // finally based on whether if a single test failed, set the class on the test name.
-            td.setAttribute("class", getStatusClass(currentType));
+//todo            td.setAttribute("class", getStatusClass(currentType));
+
+            htmlWriter.endElement(); //tr
         }
+        htmlWriter.endElement(); // table
     }
 
     public static ResultType combineResultType(ResultType currentType, ResultType newType) {
@@ -153,7 +156,7 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
     }
 
     @Override
-    protected void renderFailures(Element parent) {
+    protected void renderFailures(SimpleHtmlWriter htmlWriter) throws IOException {
         // get all the results per device and per test name
         Map<String, Map<String, TestResult>> results = getResults().getTestResultsMap();
 
@@ -189,10 +192,6 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
                 testPassPercent.put(testName, percent);
             }
 
-            Element div = append(parent, "div");
-            div.setAttribute("class", "test");
-            append(div, "a").setAttribute("name", test.getId().toString());
-
             String name;
             if (percent.total == 1) {
                 name = testName;
@@ -203,45 +202,25 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
                         percent.failed, percent.total);
             }
 
-            appendWithText(div, "h3", name).setAttribute("class", test.getStatusClass());
+            htmlWriter.startElement("div").attribute("class", "test")
+                .startElement("a").attribute("name", test.getId().toString()).characters("").endElement() //browsers dont understand <a name="..."/>
+                    .startElement("h3").attribute("class", test.getStatusClass()).characters(name).endElement();
             for (TestFailure failure : test.getFailures()) {
-                codePanelRenderer.render(failure.getStackTrace(), div);
+                codePanelRenderer.render(failure.getStackTrace(), htmlWriter);
             }
+            htmlWriter.endElement();
         }
     }
 
-    private void renderStdOut(Element parent) {
-        codePanelRenderer.render(getResults().getStandardOutput().toString(), parent);
-    }
-
-    private void renderStdErr(Element parent) {
-        codePanelRenderer.render(getResults().getStandardError().toString(), parent);
-    }
-
-    @Override protected void registerTabs() {
+    @Override
+    protected void registerTabs() {
         addFailuresTab();
-        addTab("Tests", new Action<Element>() {
+        addTab("Tests", new ErroringAction<SimpleHtmlWriter>() {
             @Override
-            public void execute(Element element) {
-                renderTests(element);
+            public void doExecute(SimpleHtmlWriter writer) throws IOException {
+                renderTests(writer);
             }
         });
-        if (getResults().getStandardOutput().length() > 0) {
-            addTab("Standard output", new Action<Element>() {
-                @Override
-                public void execute(Element element) {
-                    renderStdOut(element);
-                }
-            });
-        }
-        if (getResults().getStandardError().length() > 0) {
-            addTab("Standard error", new Action<Element>() {
-                @Override
-                public void execute(Element element) {
-                    renderStdErr(element);
-                }
-            });
-        }
         addDeviceAndVariantTabs();
     }
 }
index 450eb55..f289179 100644 (file)
  */
 package com.android.build.gradle.internal.test.report;
 
+import org.gradle.api.internal.ErroringAction;
+import org.gradle.api.internal.html.SimpleHtmlWriter;
 
-import org.gradle.api.Action;
-import org.w3c.dom.Element;
+import java.io.IOException;
 
 /**
  * Custom OverviewPageRenderer based on Gradle's OverviewPageRenderer
@@ -28,78 +29,82 @@ class OverviewPageRenderer extends PageRenderer<AllTestResults> {
         super(reportType);
     }
 
-    @Override protected void registerTabs() {
+    @Override
+    protected void registerTabs() {
         addFailuresTab();
         if (!getResults().getPackages().isEmpty()) {
-            addTab("Packages", new Action<Element>() {
+            addTab("Packages", new ErroringAction<SimpleHtmlWriter>() {
                 @Override
-                public void execute(Element element) {
-                    renderPackages(element);
+                protected void doExecute(SimpleHtmlWriter writer) throws IOException {
+                    renderPackages(writer);
                 }
             });
         }
-        addTab("Classes", new Action<Element>() {
+        addTab("Classes", new ErroringAction<SimpleHtmlWriter>() {
             @Override
-            public void execute(Element element) {
-                renderClasses(element);
+            public void doExecute(SimpleHtmlWriter htmlWriter) throws IOException {
+                renderClasses(htmlWriter);
             }
         });
-        addDeviceAndVariantTabs();
     }
 
-    @Override protected void renderBreadcrumbs(Element element) {
+    @Override
+    protected void renderBreadcrumbs(SimpleHtmlWriter htmlWriter) {
     }
 
-    private void renderPackages(Element parent) {
-        Element table = append(parent, "table");
-        Element thead = append(table, "thead");
-        Element tr = append(thead, "tr");
-        appendWithText(tr, "th", "Package");
-        appendWithText(tr, "th", "Tests");
-        appendWithText(tr, "th", "Failures");
-        appendWithText(tr, "th", "Duration");
-        appendWithText(tr, "th", "Success rate");
+    private void renderPackages(SimpleHtmlWriter htmlWriter) throws IOException {
+        htmlWriter.startElement("table");
+        htmlWriter.startElement("thead");
+        htmlWriter.startElement("tr");
+        htmlWriter.startElement("th").characters("Package").endElement();
+        htmlWriter.startElement("th").characters("Tests").endElement();
+        htmlWriter.startElement("th").characters("Failures").endElement();
+        htmlWriter.startElement("th").characters("Duration").endElement();
+        htmlWriter.startElement("th").characters("Success rate").endElement();
+        htmlWriter.endElement();
+        htmlWriter.endElement();
+        htmlWriter.startElement("tbody");
         for (PackageTestResults testPackage : getResults().getPackages()) {
-            tr = append(table, "tr");
-            Element td;
-            td = append(tr, "td");
-            td.setAttribute("class", testPackage.getStatusClass());
-            appendLink(td,
-                    String.format("%s.html", testPackage.getFilename(reportType)),
-                    testPackage.getName());
-            appendWithText(tr, "td", testPackage.getTestCount());
-            appendWithText(tr, "td", testPackage.getFailureCount());
-            appendWithText(tr, "td", testPackage.getFormattedDuration());
-            td = appendWithText(tr, "td", testPackage.getFormattedSuccessRate());
-            td.setAttribute("class", testPackage.getStatusClass());
+            htmlWriter.startElement("tr");
+            htmlWriter.startElement("td").attribute("class", testPackage.getStatusClass());
+            htmlWriter.startElement("a").attribute("href", String.format("%s.html", testPackage.getFilename(reportType))).characters(testPackage.getName()).endElement();
+            htmlWriter.endElement();
+            htmlWriter.startElement("td").characters(Integer.toString(testPackage.getTestCount())).endElement();
+            htmlWriter.startElement("td").characters(Integer.toString(testPackage.getFailureCount())).endElement();
+            htmlWriter.startElement("td").characters(testPackage.getFormattedDuration()).endElement();
+            htmlWriter.startElement("td").attribute("class", testPackage.getStatusClass()).characters(testPackage.getFormattedSuccessRate()).endElement();
+            htmlWriter.endElement();
         }
+        htmlWriter.endElement();
+        htmlWriter.endElement();
     }
 
-    private void renderClasses(Element parent) {
-        Element table = append(parent, "table");
-        Element thead = append(table, "thead");
-        Element tr = append(thead, "tr");
-        appendWithText(tr, "th", "Class");
-        appendWithText(tr, "th", "Tests");
-        appendWithText(tr, "th", "Failures");
-        appendWithText(tr, "th", "Duration");
-        appendWithText(tr, "th", "Success rate");
+    private void renderClasses(SimpleHtmlWriter htmlWriter) throws IOException {
+        htmlWriter.startElement("table");
+        htmlWriter.startElement("thead");
+        htmlWriter.startElement("tr");
+        htmlWriter.startElement("th").characters("Class").endElement();
+        htmlWriter.startElement("th").characters("Tests").endElement();
+        htmlWriter.startElement("th").characters("Failures").endElement();
+        htmlWriter.startElement("th").characters("Duration").endElement();
+        htmlWriter.startElement("th").characters("Success rate").endElement();
+        htmlWriter.endElement();
+        htmlWriter.endElement();
+        htmlWriter.startElement("tbody");
+
         for (PackageTestResults testPackage : getResults().getPackages()) {
             for (ClassTestResults testClass : testPackage.getClasses()) {
-                tr = append(table, "tr");
-                Element td;
-
-                td = append(tr, "td");
-                td.setAttribute("class", testClass.getStatusClass());
-                appendLink(td,
-                        String.format("%s.html", testClass.getFilename(reportType)),
-                        testClass.getName());
-                appendWithText(tr, "td", testClass.getTestCount());
-                appendWithText(tr, "td", testClass.getFailureCount());
-                appendWithText(tr, "td", testClass.getFormattedDuration());
-                td = appendWithText(tr, "td", testClass.getFormattedSuccessRate());
-                td.setAttribute("class", testClass.getStatusClass());
+                htmlWriter.startElement("tr");
+                htmlWriter.startElement("td").attribute("class", testClass.getStatusClass()).endElement();
+                htmlWriter.startElement("a").attribute("href", String.format("%s.html", testClass.getFilename(reportType))).characters(testClass.getName()).endElement();
+                htmlWriter.startElement("td").characters(Integer.toString(testClass.getTestCount())).endElement();
+                htmlWriter.startElement("td").characters(Integer.toString(testClass.getFailureCount())).endElement();
+                htmlWriter.startElement("td").characters(testClass.getFormattedDuration()).endElement();
+                htmlWriter.startElement("td").attribute("class", testClass.getStatusClass()).characters(testClass.getFormattedSuccessRate()).endElement();
+                htmlWriter.endElement();
             }
         }
+        htmlWriter.endElement();
+        htmlWriter.endElement();
     }
 }
index 4f1dbb7..796617f 100644 (file)
  */
 package com.android.build.gradle.internal.test.report;
 
-import org.gradle.api.Action;
-import org.w3c.dom.Element;
+import org.gradle.api.internal.ErroringAction;
+import org.gradle.api.internal.html.SimpleHtmlWriter;
+
+import java.io.IOException;
 
 /**
  * Custom PackagePageRenderer based on Gradle's PackagePageRenderer
@@ -32,45 +34,50 @@ public class PackagePageRenderer extends PageRenderer<PackageTestResults> {
         return getModel().getTitle();
     }
 
-    @Override protected void renderBreadcrumbs(Element parent) {
-        Element div = append(parent, "div");
-        div.setAttribute("class", "breadcrumbs");
-        appendLink(div, "index.html", "all");
-        appendText(div, String.format(" > %s", getResults().getName()));
+    @Override
+    protected void renderBreadcrumbs(SimpleHtmlWriter htmlWriter) throws IOException {
+        htmlWriter.startElement("div").attribute("class", "breadcrumbs");
+        htmlWriter.startElement("a").attribute("href", "index.html").characters("all").endElement();
+        htmlWriter.characters(String.format(" > %s", getResults().getName()));
+        htmlWriter.endElement();
     }
 
-    private void renderClasses(Element parent) {
-        Element table = append(parent, "table");
-        Element thead = append(table, "thead");
-        Element tr = append(thead, "tr");
-        appendWithText(tr, "th", "Class");
-        appendWithText(tr, "th", "Tests");
-        appendWithText(tr, "th", "Failures");
-        appendWithText(tr, "th", "Duration");
-        appendWithText(tr, "th", "Success rate");
+    private void renderClasses(SimpleHtmlWriter htmlWriter) throws IOException {
+        htmlWriter.startElement("table");
+        htmlWriter.startElement("thread");
+        htmlWriter.startElement("tr");
+
+        htmlWriter.startElement("th").characters("Class").endElement();
+        htmlWriter.startElement("th").characters("Tests").endElement();
+        htmlWriter.startElement("th").characters("Failures").endElement();
+        htmlWriter.startElement("th").characters("Duration").endElement();
+        htmlWriter.startElement("th").characters("Success rate").endElement();
+
+        htmlWriter.endElement();
+        htmlWriter.endElement();
+
         for (ClassTestResults testClass : getResults().getClasses()) {
-            tr = append(table, "tr");
-            Element td = append(tr, "td");
-            td.setAttribute("class", testClass.getStatusClass());
-            appendLink(td,
-                    String.format("%s.html", testClass.getFilename(reportType)),
-                    testClass.getSimpleName());
-            appendWithText(tr, "td", testClass.getTestCount());
-            appendWithText(tr, "td", testClass.getFailureCount());
-            appendWithText(tr, "td", testClass.getFormattedDuration());
-            td = appendWithText(tr, "td", testClass.getFormattedSuccessRate());
-            td.setAttribute("class", testClass.getStatusClass());
+            htmlWriter.startElement("tr");
+            htmlWriter.startElement("td").attribute("class", testClass.getStatusClass());
+            htmlWriter.startElement("a").attribute("href", String.format("%s.html", testClass.getFilename(reportType))).characters(testClass.getSimpleName()).endElement();
+            htmlWriter.endElement();
+            htmlWriter.startElement("td").characters(Integer.toString(testClass.getTestCount())).endElement();
+            htmlWriter.startElement("td").characters(Integer.toString(testClass.getFailureCount())).endElement();
+            htmlWriter.startElement("td").characters(testClass.getFormattedDuration()).endElement();
+            htmlWriter.startElement("td").attribute("class", testClass.getStatusClass()).characters(testClass.getFormattedSuccessRate()).endElement();
+            htmlWriter.endElement();
         }
+        htmlWriter.endElement();
     }
 
-    @Override protected void registerTabs() {
+    @Override
+    protected void registerTabs() {
         addFailuresTab();
-        addTab("Classes", new Action<Element>() {
+        addTab("Classes", new ErroringAction<SimpleHtmlWriter>() {
             @Override
-            public void execute(Element element) {
-                renderClasses(element);
+            public void doExecute(SimpleHtmlWriter htmlWriter) throws IOException {
+                renderClasses(htmlWriter);
             }
         });
-        addDeviceAndVariantTabs();
     }
 }
index aa958d0..f240cf9 100644 (file)
 package com.android.build.gradle.internal.test.report;
 
 import org.gradle.api.Action;
-import org.gradle.api.internal.tasks.testing.junit.report.TestResultModel;
-import org.gradle.reporting.DomReportRenderer;
+import org.gradle.api.internal.ErroringAction;
+import org.gradle.api.internal.html.SimpleHtmlWriter;
+import org.gradle.reporting.ReportRenderer;
 import org.gradle.reporting.TabbedPageRenderer;
 import org.gradle.reporting.TabsRenderer;
-import org.w3c.dom.Element;
 
+import java.io.IOException;
 import java.util.Map;
 
 /**
@@ -40,29 +41,29 @@ abstract class PageRenderer<T extends CompositeTestResults> extends TabbedPageRe
         return results;
     }
 
-    protected abstract void renderBreadcrumbs(Element parent);
+    protected abstract void renderBreadcrumbs(SimpleHtmlWriter htmlWriter) throws IOException;
 
     protected abstract void registerTabs();
 
-    protected void addTab(String title, final Action<Element> contentRenderer) {
-        tabsRenderer.add(title, new DomReportRenderer<T>() {
+    protected void addTab(String title, final Action<SimpleHtmlWriter> contentRenderer) {
+        tabsRenderer.add(title, new ReportRenderer<T, SimpleHtmlWriter>() {
             @Override
-            public void render(T model, Element parent) {
-                contentRenderer.execute(parent);
+            public void render(T model, SimpleHtmlWriter writer) {
+                contentRenderer.execute(writer);
             }
         });
     }
 
-    protected void renderTabs(Element element) {
-        tabsRenderer.render(getModel(), element);
+    protected void renderTabs(SimpleHtmlWriter htmlWriter) throws IOException {
+        tabsRenderer.render(getModel(), htmlWriter);
     }
 
     protected void addFailuresTab() {
         if (!results.getFailures().isEmpty()) {
-            addTab("Failed tests", new Action<Element>() {
+            addTab("Failed tests", new ErroringAction<SimpleHtmlWriter>() {
                 @Override
-                public void execute(Element element) {
-                    renderFailures(element);
+                public void doExecute(SimpleHtmlWriter writer) throws IOException {
+                    renderFailures(writer);
                 }
             });
         }
@@ -70,122 +71,112 @@ abstract class PageRenderer<T extends CompositeTestResults> extends TabbedPageRe
 
     protected void addDeviceAndVariantTabs() {
         if (results.getResultsPerDevices().size() > 1) {
-            addTab("Devices", new Action<Element>() {
+            addTab("Devices", new ErroringAction<SimpleHtmlWriter>() {
                 @Override
-                public void execute(Element element) {
-                    renderCompositeResults(element, results.getResultsPerDevices(), "Devices");
+                public void doExecute(SimpleHtmlWriter writer) throws IOException {
+                    renderCompositeResults(writer, results.getResultsPerDevices(), "Devices");
                 }
             });
 
         }
 
         if (results.getResultsPerVariants().size() > 1) {
-            addTab("Variants", new Action<Element>() {
+            addTab("Variants", new ErroringAction<SimpleHtmlWriter>() {
                 @Override
-                public void execute(Element element) {
-                    renderCompositeResults(element, results.getResultsPerVariants(), "Variants");
+                public void doExecute(SimpleHtmlWriter writer) throws IOException {
+                    renderCompositeResults(writer, results.getResultsPerVariants(), "Variants");
                 }
             });
         }
     }
 
-    protected void renderFailures(Element parent) {
-        Element ul = append(parent, "ul");
-        ul.setAttribute("class", "linkList");
+    protected void renderFailures(SimpleHtmlWriter htmlWriter) throws IOException {
+
+        htmlWriter.startElement("ul").attribute("class", "linkList");
 
         boolean multiDevices = results.getResultsPerDevices().size() > 1;
         boolean multiVariants = results.getResultsPerVariants().size() > 1;
 
-        Element table = append(parent, "table");
-        Element thead = append(table, "thead");
-        Element tr = append(thead, "tr");
+        htmlWriter.startElement("table");
+        htmlWriter.startElement("thead");
+
+        htmlWriter.startElement("tr");
         if (multiDevices) {
-            appendWithText(tr, "th", "Devices");
+            htmlWriter.startElement("th").characters("Devices").endElement();
         }
         if (multiVariants) {
             if (reportType == ReportType.MULTI_PROJECT) {
-                appendWithText(tr, "th", "Project");
-                appendWithText(tr, "th", "Flavor");
+                htmlWriter.startElement("th").characters("Project").endElement();
+                htmlWriter.startElement("th").characters("Flavor").endElement();
             } else if (reportType == ReportType.MULTI_FLAVOR) {
-                appendWithText(tr, "th", "Flavor");
+                htmlWriter.startElement("th").characters("Flavor").endElement();
             }
-
         }
-        appendWithText(tr, "th", "Class");
-        appendWithText(tr, "th", "Test");
+        htmlWriter.startElement("th").characters("Class").endElement();
+        htmlWriter.startElement("th").characters("Test").endElement();
+
+        htmlWriter.endElement(); //tr
+        htmlWriter.endElement(); //thead
+
         for (TestResult test : results.getFailures()) {
-            tr = append(table, "tr");
-            Element td;
+            htmlWriter.startElement("tr");
 
             if (multiDevices) {
-                appendWithText(tr, "td", test.getDevice());
+                htmlWriter.startElement("td").characters(test.getDevice()).endElement();
             }
             if (multiVariants) {
                 if (reportType == ReportType.MULTI_PROJECT) {
-                    appendWithText(tr, "td", test.getProject());
-                    appendWithText(tr, "td", test.getFlavor());
+                    htmlWriter.startElement("td").characters(test.getProject()).endElement();
+                    htmlWriter.startElement("td").characters(test.getFlavor()).endElement();
                 } else if (reportType == ReportType.MULTI_FLAVOR) {
-                    appendWithText(tr, "td", test.getFlavor());
+                    htmlWriter.startElement("td").characters(test.getFlavor()).endElement();
                 }
-
             }
 
-            td = append(tr, "td");
-            appendLink(td,
-                    String.format("%s.html", test.getClassResults().getFilename(reportType)),
-                    test.getClassResults().getSimpleName());
-
-            td = append(tr, "td");
-            appendLink(td,
-                    String.format("%s.html#%s",
-                            test.getClassResults().getFilename(reportType),
-                            test.getName()),
-                    test.getName());
+            htmlWriter.startElement("td").attribute("class", test.getStatusClass());
+            htmlWriter.endElement();
+
+            htmlWriter.startElement("td")
+                .startElement("a").attribute("href", String.format("%s.html", test.getClassResults().getFilename(reportType)))
+                    .characters(test.getClassResults().getSimpleName()).endElement()
+            .endElement();
+
+            htmlWriter.startElement("td")
+                    .startElement("a").attribute("href", String.format("%s.html#s", test.getClassResults().getFilename(reportType), test.getName()))
+                    .characters(test.getName()).endElement()
+                    .endElement();
+            htmlWriter.endElement(); //tr
         }
+        htmlWriter.endElement(); //table
+        htmlWriter.endElement(); // ul
+
     }
 
-    protected void renderCompositeResults(Element parent,
+    protected void renderCompositeResults(SimpleHtmlWriter htmlWriter,
                                           Map<String, ? extends CompositeTestResults> map,
-                                          String name) {
-        Element table = append(parent, "table");
-        Element thead = append(table, "thead");
-        Element tr = append(thead, "tr");
-        appendWithText(tr, "th", name);
-        appendWithText(tr, "th", "Tests");
-        appendWithText(tr, "th", "Failures");
-        appendWithText(tr, "th", "Duration");
-        appendWithText(tr, "th", "Success rate");
+                                          String name) throws IOException {
+        htmlWriter.startElement("table");
+        htmlWriter.startElement("thead");
+        htmlWriter.startElement("tr");
+        htmlWriter.startElement("th").characters(name).endElement();
+        htmlWriter.startElement("th").characters("Tests").endElement();
+        htmlWriter.startElement("th").characters("Failures").endElement();
+        htmlWriter.startElement("th").characters("Duration").endElement();
+        htmlWriter.startElement("th").characters("Success rate").endElement();
+        htmlWriter.endElement(); //tr
+        htmlWriter.endElement(); //thead
+
         for (CompositeTestResults results : map.values()) {
-            tr = append(table, "tr");
-            Element td;
-
-            td = appendWithText(tr, "td", results.getName());
-            td.setAttribute("class", results.getStatusClass());
-            appendWithText(tr, "td", results.getTestCount());
-            appendWithText(tr, "td", results.getFailureCount());
-            appendWithText(tr, "td", results.getFormattedDuration());
-            td = appendWithText(tr, "td", results.getFormattedSuccessRate());
-            td.setAttribute("class", results.getStatusClass());
+            htmlWriter.startElement("tr");
+            htmlWriter.startElement("td").attribute("class", results.getStatusClass()).characters(results.getName()).endElement();
+            htmlWriter.startElement("td").characters(Integer.toString(results.getTestCount())).endElement();
+            htmlWriter.startElement("td").characters(Integer.toString(results.getFailureCount())).endElement();
+            htmlWriter.startElement("td").characters(results.getFormattedDuration()).endElement();
+            htmlWriter.startElement("td").characters(results.getFormattedSuccessRate()).endElement();
+            htmlWriter.endElement(); //tr
         }
-    }
 
-    protected Element appendTableAndRow(Element parent) {
-        return append(append(parent, "table"), "tr");
-    }
-
-    protected Element appendCell(Element parent) {
-        return append(append(parent, "td"), "div");
-    }
-
-    protected <T extends TestResultModel> DomReportRenderer<T> withStatus(
-            final DomReportRenderer<T> renderer) {
-        return new DomReportRenderer<T>() {
-            @Override
-            public void render(T model, Element parent) {
-                parent.setAttribute("class", model.getStatusClass());
-                renderer.render(model, parent);
-            }
-        };
+        htmlWriter.endElement(); //table
     }
 
     @Override
@@ -199,61 +190,65 @@ abstract class PageRenderer<T extends CompositeTestResults> extends TabbedPageRe
     }
 
     @Override
-    protected DomReportRenderer<T> getHeaderRenderer() {
-        return new DomReportRenderer<T>() {
+    protected ReportRenderer<T, SimpleHtmlWriter> getHeaderRenderer() {
+        return new ReportRenderer<T, SimpleHtmlWriter>() {
             @Override
-            public void render(T model, Element content) {
+            public void render(T model, SimpleHtmlWriter htmlWriter) throws IOException {
                 PageRenderer.this.results = model;
-                renderBreadcrumbs(content);
+                renderBreadcrumbs(htmlWriter);
 
                 // summary
-                Element summary = appendWithId(content, "div", "summary");
-                Element row = appendTableAndRow(summary);
-                Element group = appendCell(row);
-                group.setAttribute("class", "summaryGroup");
-                Element summaryRow = appendTableAndRow(group);
-
-                Element tests = appendCell(summaryRow);
-                tests.setAttribute("id", "tests");
-                tests.setAttribute("class", "infoBox");
-                Element div = appendWithText(tests, "div", results.getTestCount());
-                div.setAttribute("class", "counter");
-                appendWithText(tests, "p", "tests");
-
-                Element failures = appendCell(summaryRow);
-                failures.setAttribute("id", "failures");
-                failures.setAttribute("class", "infoBox");
-                div = appendWithText(failures, "div", results.getFailureCount());
-                div.setAttribute("class", "counter");
-                appendWithText(failures, "p", "failures");
-
-                Element duration = appendCell(summaryRow);
-                duration.setAttribute("id", "duration");
-                duration.setAttribute("class", "infoBox");
-                div = appendWithText(duration, "div", results.getFormattedDuration());
-                div.setAttribute("class", "counter");
-                appendWithText(duration, "p", "duration");
-
-                Element successRate = appendCell(row);
-                successRate.setAttribute("id", "successRate");
-                successRate.setAttribute("class",
-                        String.format("infoBox %s", results.getStatusClass()));
-                div = appendWithText(successRate, "div", results.getFormattedSuccessRate());
-                div.setAttribute("class", "percent");
-                appendWithText(successRate, "p", "successful");
+                htmlWriter.startElement("div").attribute("id", "summary");
+                htmlWriter.startElement("table");
+                htmlWriter.startElement("tr");
+                htmlWriter.startElement("td");
+                htmlWriter.startElement("div").attribute("class", "summaryGroup");
+                htmlWriter.startElement("table");
+                htmlWriter.startElement("tr");
+                htmlWriter.startElement("td");
+                htmlWriter.startElement("div").attribute("class", "infoBox").attribute("id", "tests");
+                htmlWriter.startElement("div").attribute("class", "counter").characters(Integer.toString(results.getTestCount())).endElement();
+                htmlWriter.startElement("p").characters("tests").endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.startElement("td");
+                htmlWriter.startElement("div").attribute("class", "infoBox").attribute("id", "failures");
+                htmlWriter.startElement("div").attribute("class", "counter").characters(Integer.toString(results.getFailureCount())).endElement();
+                htmlWriter.startElement("p").characters("failures").endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.startElement("td");
+                htmlWriter.startElement("div").attribute("class", "infoBox").attribute("id", "duration");
+                htmlWriter.startElement("div").attribute("class", "counter").characters(results.getFormattedDuration()).endElement();
+                htmlWriter.startElement("p").characters("duration").endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.startElement("td");
+                htmlWriter.startElement("div").attribute("class", String.format("infoBox %s", results.getStatusClass())).attribute("id", "successRate");
+                htmlWriter.startElement("div").attribute("class", "percent").characters(results.getFormattedSuccessRate()).endElement();
+                htmlWriter.startElement("p").characters("successful").endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
+                htmlWriter.endElement();
             }
         };
     }
 
     @Override
-    protected DomReportRenderer<T> getContentRenderer() {
-        return new DomReportRenderer<T>() {
+    protected ReportRenderer<T, SimpleHtmlWriter> getContentRenderer() {
+        return new ReportRenderer<T, SimpleHtmlWriter>() {
             @Override
-            public void render(T model, Element content) {
+            public void render(T model, SimpleHtmlWriter htmlWriter) throws IOException {
                 PageRenderer.this.results = model;
                 tabsRenderer.clear();
                 registerTabs();
-                renderTabs(content);
+                renderTabs(htmlWriter);
             }
         };
     }