Fix reporting to handle multi-devices.
Xavier Ducrohet [Thu, 14 Feb 2013 22:11:36 +0000 (14:11 -0800)]
Change-Id: I1d8a60f23ed3659297372a876fe57ff7b18f8440

13 files changed:
gradle/src/build-test/groovy/com/android/build/gradle/AutomatedBuildTest.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/AllTestResults.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/ClassPageRenderer.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/ClassTestResults.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/CompositeTestResults.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/DeviceTestResults.java [new file with mode: 0644]
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/PackageTestResults.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/PageRenderer.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/TestReport.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/TestResult.java
gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/VariantTestResults.java [new file with mode: 0644]

index a23b560..06dd9d9 100644 (file)
@@ -34,7 +34,7 @@ public class AutomatedBuildTest extends BuildTest {
     private static enum TestType { BUILD, REPORT };
 
     private static final String[] sBuiltProjects = new String[] {
-            "aidl", "api", "assets", "applibtest", "assets", "basic", "dependencies", "flavored",
+            "aidl", "api", "applibtest", "assets", "basic", "dependencies", "flavored",
             "flavorlib", "flavors", "libsTest", "migrated", "multiproject", "multires",
             "overlay1", "overlay2", "renderscript", "renderscriptInLib", "renderscriptMultiSrc",
             "tictactoe"
index 33d01a8..db0873d 100644 (file)
@@ -28,7 +28,7 @@ class AllTestResults extends CompositeTestResults {
     private final Map<String, PackageTestResults> packages = new TreeMap<String, PackageTestResults>();
 
     public AllTestResults() {
-        super(null, null, null, null);
+        super(null);
     }
 
     @Override
@@ -47,20 +47,21 @@ class AllTestResults extends CompositeTestResults {
 
     public TestResult addTest(String className, String testName, long duration,
                               String device, String project, String flavor) {
-        PackageTestResults packageResults = addPackageForClass(className,
-                device, project, flavor);
-        return addTest(packageResults.addTest(className, testName, duration,
-                device, project, flavor));
+        PackageTestResults packageResults = addPackageForClass(className);
+        TestResult testResult = addTest(
+                packageResults.addTest(className, testName, duration, device, project, flavor));
+
+        addDevice(device, testResult);
+        addVariant(project, flavor, testResult);
+
+        return testResult;
     }
 
-    public ClassTestResults addTestClass(String className,
-                                         String device, String project, String flavor) {
-        return addPackageForClass(className, device, project, flavor).addClass(className,
-                device, project, flavor);
+    public ClassTestResults addTestClass(String className) {
+        return addPackageForClass(className).addClass(className);
     }
 
-    private PackageTestResults addPackageForClass(String className,
-                                                  String device, String project, String flavor) {
+    private PackageTestResults addPackageForClass(String className) {
         String packageName;
         int pos = className.lastIndexOf(".");
         if (pos != -1) {
@@ -68,17 +69,15 @@ class AllTestResults extends CompositeTestResults {
         } else {
             packageName = "";
         }
-        return addPackage(packageName, device, project, flavor);
+        return addPackage(packageName);
     }
 
-    private PackageTestResults addPackage(String packageName,
-                                          String device, String project, String flavor) {
-        String key = device + "/" + project + "/" + flavor + "/" + packageName;
+    private PackageTestResults addPackage(String packageName) {
 
-        PackageTestResults packageResults = packages.get(key);
+        PackageTestResults packageResults = packages.get(packageName);
         if (packageResults == null) {
-            packageResults = new PackageTestResults(packageName, this, device, project, flavor);
-            packages.put(key, packageResults);
+            packageResults = new PackageTestResults(packageName, this);
+            packages.put(packageName, packageResults);
         }
         return packageResults;
     }
index 292696f..5e8c345 100644 (file)
@@ -43,16 +43,7 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
 
     @Override
     protected String getTitle() {
-        ClassTestResults model = getModel();
-
-        switch (reportType) {
-            case MULTI_PROJECT:
-                return model.getProject() + ": " + model.getFlavor() + ": " + model.getTitle();
-            case MULTI_FLAVOR:
-                return model.getFlavor() + ": " + model.getTitle();
-        }
-
-        return model.getTitle();
+        return getModel().getTitle();
     }
 
     @Override protected void renderBreadcrumbs(Element parent) {
@@ -249,5 +240,6 @@ class ClassPageRenderer extends PageRenderer<ClassTestResults> {
                 }
             });
         }
+        addDeviceAndVariantTabs();
     }
 }
index 4108b52..c7b924f 100644 (file)
@@ -18,7 +18,6 @@ package com.android.build.gradle.internal.test.report;
 
 import com.google.common.collect.Maps;
 
-import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -34,9 +33,8 @@ class ClassTestResults extends CompositeTestResults {
     private final StringBuilder standardOutput = new StringBuilder();
     private final StringBuilder standardError = new StringBuilder();
 
-    public ClassTestResults(String name, PackageTestResults packageResults,
-                            String device, String project, String flavor) {
-        super(packageResults, device, project, flavor);
+    public ClassTestResults(String name, PackageTestResults packageResults) {
+        super(packageResults);
         this.name = name;
         this.packageResults = packageResults;
     }
@@ -80,10 +78,6 @@ class ClassTestResults extends CompositeTestResults {
         return map;
     }
 
-    public Collection<TestResult> getTestResults() {
-        return results;
-    }
-
     public CharSequence getStandardError() {
         return standardError;
     }
@@ -96,6 +90,10 @@ class ClassTestResults extends CompositeTestResults {
                               String device, String project, String flavor) {
         TestResult test = new TestResult(testName, duration, device, project, flavor, this);
         results.add(test);
+
+        addDevice(device, test);
+        addVariant(project, flavor, test);
+
         return addTest(test);
     }
 
index 1fe3eda..4d5d10d 100644 (file)
@@ -19,7 +19,9 @@ package com.android.build.gradle.internal.test.report;
 import org.gradle.api.internal.tasks.testing.junit.report.TestResultModel;
 
 import java.math.BigDecimal;
+import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.TreeSet;
 
 import static org.gradle.api.tasks.testing.TestResult.ResultType;
@@ -33,26 +35,15 @@ public abstract class CompositeTestResults extends TestResultModel {
     private final Set<TestResult> failures = new TreeSet<TestResult>();
     private long duration;
 
-    private final String device;
-    private final String project;
-    private final String flavor;
+    private final Map<String, DeviceTestResults> devices = new TreeMap<String, DeviceTestResults>();
+    private final Map<String, VariantTestResults> variants = new TreeMap<String, VariantTestResults>();
 
-    protected CompositeTestResults(CompositeTestResults parent,
-                                   String device, String project, String flavor) {
+
+    protected CompositeTestResults(CompositeTestResults parent) {
         this.parent = parent;
-        this.device = device;
-        this.project = project;
-        this.flavor = flavor;
     }
 
     public String getFilename(ReportType reportType) {
-        switch (reportType) {
-            case MULTI_PROJECT:
-                return project + "-" + flavor + "-" + getName();
-            case MULTI_FLAVOR:
-                return flavor + "-" + getName();
-        }
-
         return getName();
     }
 
@@ -66,18 +57,6 @@ public abstract class CompositeTestResults extends TestResultModel {
         return failures.size();
     }
 
-    public String getDevice() {
-        return device;
-    }
-
-    public String getProject() {
-        return project;
-    }
-
-    public String getFlavor() {
-        return flavor;
-    }
-
     @Override
     public long getDuration() {
         return duration;
@@ -92,6 +71,14 @@ public abstract class CompositeTestResults extends TestResultModel {
         return failures;
     }
 
+    Map<String, DeviceTestResults> getResultsPerDevices() {
+        return devices;
+    }
+
+    Map<String, VariantTestResults> getResultsPerVariants() {
+        return variants;
+    }
+
     @Override
     public ResultType getResultType() {
         return failures.isEmpty() ? ResultType.SUCCESS : ResultType.FAILURE;
@@ -117,10 +104,22 @@ public abstract class CompositeTestResults extends TestResultModel {
                 BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(100)).intValue();
     }
 
-    protected void failed(TestResult failedTest) {
+    protected void failed(TestResult failedTest,
+                          String deviceName, String projectName, String flavorName) {
         failures.add(failedTest);
         if (parent != null) {
-            parent.failed(failedTest);
+            parent.failed(failedTest, deviceName, projectName, flavorName);
+        }
+
+        DeviceTestResults deviceResults = devices.get(deviceName);
+        if (deviceResults != null) {
+            deviceResults.failed(failedTest, deviceName, projectName, flavorName);
+        }
+
+        String key = getVariantKey(projectName, flavorName);
+        VariantTestResults variantResults = variants.get(key);
+        if (variantResults != null) {
+            variantResults.failed(failedTest, deviceName, projectName, flavorName);
         }
     }
 
@@ -129,4 +128,33 @@ public abstract class CompositeTestResults extends TestResultModel {
         duration += test.getDuration();
         return test;
     }
+
+    protected void addDevice(String deviceName, TestResult testResult) {
+        DeviceTestResults deviceResults = devices.get(deviceName);
+        if (deviceResults == null) {
+            deviceResults = new DeviceTestResults(deviceName, null);
+            devices.put(deviceName, deviceResults);
+        }
+
+        deviceResults.addTest(testResult);
+    }
+
+    protected void addVariant(String projectName, String flavorName, TestResult testResult) {
+        String key = getVariantKey(projectName, flavorName);
+        VariantTestResults variantResults = variants.get(key);
+        if (variantResults == null) {
+            variantResults = new VariantTestResults(key, null);
+            variants.put(key, variantResults);
+        }
+
+        variantResults.addTest(testResult);
+    }
+
+    private static String getVariantKey(String projectName, String flavorName) {
+        if (flavorName.equals("Main")) {
+            return projectName;
+        }
+
+        return projectName + ":" + flavorName;
+    }
 }
diff --git a/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/DeviceTestResults.java b/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/DeviceTestResults.java
new file mode 100644 (file)
index 0000000..f801e7b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.android.build.gradle.internal.test.report;
+
+import com.android.annotations.NonNull;
+
+/**
+ * DeviceTestResults to accumulate results per device.
+ */
+class DeviceTestResults extends CompositeTestResults {
+
+    private final String name;
+
+    public DeviceTestResults(@NonNull String name, CompositeTestResults parent) {
+        super(parent);
+        this.name = name;
+    }
+
+    @Override
+    public String getTitle() {
+        return name;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+}
index d51c701..450eb55 100644 (file)
@@ -44,6 +44,7 @@ class OverviewPageRenderer extends PageRenderer<AllTestResults> {
                 renderClasses(element);
             }
         });
+        addDeviceAndVariantTabs();
     }
 
     @Override protected void renderBreadcrumbs(Element element) {
@@ -53,12 +54,6 @@ class OverviewPageRenderer extends PageRenderer<AllTestResults> {
         Element table = append(parent, "table");
         Element thead = append(table, "thead");
         Element tr = append(thead, "tr");
-        if (reportType == ReportType.MULTI_PROJECT) {
-            appendWithText(tr, "th", "Project");
-            appendWithText(tr, "th", "Flavor");
-        } else if (reportType == ReportType.MULTI_FLAVOR) {
-            appendWithText(tr, "th", "Flavor");
-        }
         appendWithText(tr, "th", "Package");
         appendWithText(tr, "th", "Tests");
         appendWithText(tr, "th", "Failures");
@@ -67,17 +62,6 @@ class OverviewPageRenderer extends PageRenderer<AllTestResults> {
         for (PackageTestResults testPackage : getResults().getPackages()) {
             tr = append(table, "tr");
             Element td;
-
-            if (reportType == ReportType.MULTI_PROJECT) {
-                td = appendWithText(tr, "td", testPackage.getProject());
-                td.setAttribute("class", testPackage.getStatusClass());
-                td = appendWithText(tr, "td", testPackage.getFlavor());
-                td.setAttribute("class", testPackage.getStatusClass());
-            } else if (reportType == ReportType.MULTI_FLAVOR) {
-                td = appendWithText(tr, "td", testPackage.getFlavor());
-                td.setAttribute("class", testPackage.getStatusClass());
-            }
-
             td = append(tr, "td");
             td.setAttribute("class", testPackage.getStatusClass());
             appendLink(td,
@@ -95,12 +79,6 @@ class OverviewPageRenderer extends PageRenderer<AllTestResults> {
         Element table = append(parent, "table");
         Element thead = append(table, "thead");
         Element tr = append(thead, "tr");
-        if (reportType == ReportType.MULTI_PROJECT) {
-            appendWithText(tr, "th", "Project");
-            appendWithText(tr, "th", "Flavor");
-        } else if (reportType == ReportType.MULTI_FLAVOR) {
-            appendWithText(tr, "th", "Flavor");
-        }
         appendWithText(tr, "th", "Class");
         appendWithText(tr, "th", "Tests");
         appendWithText(tr, "th", "Failures");
@@ -111,16 +89,6 @@ class OverviewPageRenderer extends PageRenderer<AllTestResults> {
                 tr = append(table, "tr");
                 Element td;
 
-                if (reportType == ReportType.MULTI_PROJECT) {
-                    td = appendWithText(tr, "td", testClass.getProject());
-                    td.setAttribute("class", testClass.getStatusClass());
-                    td = appendWithText(tr, "td", testClass.getFlavor());
-                    td.setAttribute("class", testClass.getStatusClass());
-                } else if (reportType == ReportType.MULTI_FLAVOR) {
-                    td = appendWithText(tr, "td", testClass.getFlavor());
-                    td.setAttribute("class", testClass.getStatusClass());
-                }
-
                 td = append(tr, "td");
                 td.setAttribute("class", testClass.getStatusClass());
                 appendLink(td,
index ce5e548..4f1dbb7 100644 (file)
@@ -29,16 +29,7 @@ public class PackagePageRenderer extends PageRenderer<PackageTestResults> {
 
     @Override
     protected String getTitle() {
-        PackageTestResults model = getModel();
-
-        switch (reportType) {
-            case MULTI_PROJECT:
-                return model.getProject() + ": " + model.getFlavor() + ": " + model.getTitle();
-            case MULTI_FLAVOR:
-                return model.getFlavor() + ": " + model.getTitle();
-        }
-
-        return model.getTitle();
+        return getModel().getTitle();
     }
 
     @Override protected void renderBreadcrumbs(Element parent) {
@@ -80,5 +71,6 @@ public class PackagePageRenderer extends PageRenderer<PackageTestResults> {
                 renderClasses(element);
             }
         });
+        addDeviceAndVariantTabs();
     }
 }
index 4e6e5db..4f410a8 100644 (file)
@@ -28,9 +28,8 @@ class PackageTestResults extends CompositeTestResults {
     private final String name;
     private final Map<String, ClassTestResults> classes = new TreeMap<String, ClassTestResults>();
 
-    public PackageTestResults(String name, AllTestResults model,
-                              String device, String project, String flavor) {
-        super(model, device, project, flavor);
+    public PackageTestResults(String name, AllTestResults model) {
+        super(model);
         this.name = name.length() == 0 ? DEFAULT_PACKAGE : name;
     }
 
@@ -39,6 +38,7 @@ class PackageTestResults extends CompositeTestResults {
         return name.equals(DEFAULT_PACKAGE) ? "Default package" : String.format("Package %s", name);
     }
 
+    @Override
     public String getName() {
         return name;
     }
@@ -49,19 +49,21 @@ class PackageTestResults extends CompositeTestResults {
 
     public TestResult addTest(String className, String testName, long duration,
                               String device, String project, String flavor) {
-        ClassTestResults classResults = addClass(className, device, project, flavor);
-        return addTest(classResults.addTest(testName, duration, device, project, flavor));
-    }
+        ClassTestResults classResults = addClass(className);
+        TestResult testResult = addTest(
+                classResults.addTest(testName, duration, device, project, flavor));
 
+        addDevice(device, testResult);
+        addVariant(project, flavor, testResult);
 
-    public ClassTestResults addClass(String className,
-                                     String device, String project, String flavor) {
-        String key = device + "/" + project + "/" + flavor + "/" + className;
+        return testResult;
+    }
 
-        ClassTestResults classResults = classes.get(key);
+    public ClassTestResults addClass(String className) {
+        ClassTestResults classResults = classes.get(className);
         if (classResults == null) {
-            classResults = new ClassTestResults(className, this, device, project, flavor);
-            classes.put(key, classResults);
+            classResults = new ClassTestResults(className, this);
+            classes.put(className, classResults);
         }
         return classResults;
     }
index 3fe3a1f..aa958d0 100644 (file)
@@ -22,6 +22,8 @@ import org.gradle.reporting.TabbedPageRenderer;
 import org.gradle.reporting.TabsRenderer;
 import org.w3c.dom.Element;
 
+import java.util.Map;
+
 /**
  * Custom PageRenderer based on Gradle's PageRenderer
  */
@@ -66,33 +68,107 @@ abstract class PageRenderer<T extends CompositeTestResults> extends TabbedPageRe
         }
     }
 
+    protected void addDeviceAndVariantTabs() {
+        if (results.getResultsPerDevices().size() > 1) {
+            addTab("Devices", new Action<Element>() {
+                @Override
+                public void execute(Element element) {
+                    renderCompositeResults(element, results.getResultsPerDevices(), "Devices");
+                }
+            });
+
+        }
+
+        if (results.getResultsPerVariants().size() > 1) {
+            addTab("Variants", new Action<Element>() {
+                @Override
+                public void execute(Element element) {
+                    renderCompositeResults(element, results.getResultsPerVariants(), "Variants");
+                }
+            });
+        }
+    }
+
     protected void renderFailures(Element parent) {
         Element ul = append(parent, "ul");
         ul.setAttribute("class", "linkList");
 
-        // TODO
+        boolean multiDevices = results.getResultsPerDevices().size() > 1;
+        boolean multiVariants = results.getResultsPerVariants().size() > 1;
 
-        for (TestResult test : results.getFailures()) {
-            Element li = append(ul, "li");
+        Element table = append(parent, "table");
+        Element thead = append(table, "thead");
+        Element tr = append(thead, "tr");
+        if (multiDevices) {
+            appendWithText(tr, "th", "Devices");
+        }
+        if (multiVariants) {
             if (reportType == ReportType.MULTI_PROJECT) {
-                appendText(li, test.getProject());
-                appendText(li, ".");
-                appendText(li, test.getFlavor());
-                appendText(li, ".");
+                appendWithText(tr, "th", "Project");
+                appendWithText(tr, "th", "Flavor");
             } else if (reportType == ReportType.MULTI_FLAVOR) {
-                appendText(li, test.getFlavor());
-                appendText(li, ".");
+                appendWithText(tr, "th", "Flavor");
+            }
+
+        }
+        appendWithText(tr, "th", "Class");
+        appendWithText(tr, "th", "Test");
+        for (TestResult test : results.getFailures()) {
+            tr = append(table, "tr");
+            Element td;
+
+            if (multiDevices) {
+                appendWithText(tr, "td", test.getDevice());
             }
-            appendLink(li, String.format("%s.html", test.getClassResults().getFilename(reportType)),
+            if (multiVariants) {
+                if (reportType == ReportType.MULTI_PROJECT) {
+                    appendWithText(tr, "td", test.getProject());
+                    appendWithText(tr, "td", test.getFlavor());
+                } else if (reportType == ReportType.MULTI_FLAVOR) {
+                    appendWithText(tr, "td", test.getFlavor());
+                }
+
+            }
+
+            td = append(tr, "td");
+            appendLink(td,
+                    String.format("%s.html", test.getClassResults().getFilename(reportType)),
                     test.getClassResults().getSimpleName());
-            appendText(li, ".");
-            appendLink(li,
-                    String.format("%s.html#%s", test.getClassResults().getFilename(reportType),
+
+            td = append(tr, "td");
+            appendLink(td,
+                    String.format("%s.html#%s",
+                            test.getClassResults().getFilename(reportType),
                             test.getName()),
                     test.getName());
         }
     }
 
+    protected void renderCompositeResults(Element parent,
+                                          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");
+        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());
+        }
+    }
+
     protected Element appendTableAndRow(Element parent) {
         return append(append(parent, "table"), "tr");
     }
index b5b715f..57675e5 100644 (file)
@@ -99,8 +99,9 @@ public class TestReport {
                         deviceName, projectName, flavorName);
                 for (int j = 0; j < failures.getLength(); j++) {
                     Element failure = (Element) failures.item(j);
-                    testResult.addFailure(failure.getAttribute("message"),
-                            failure.getTextContent());
+                    testResult.addFailure(
+                            failure.getAttribute("message"), failure.getTextContent(),
+                            deviceName, projectName, flavorName);
                 }
             }
             NodeList ignoredTestCases = document.getElementsByTagName("ignored-testcase");
@@ -111,8 +112,7 @@ public class TestReport {
                 model.addTest(className, testName, 0, deviceName, projectName, flavorName).ignored();
             }
             String suiteClassName = document.getDocumentElement().getAttribute("name");
-            ClassTestResults suiteResults = model.addTestClass(suiteClassName,
-                    deviceName, projectName, flavorName);
+            ClassTestResults suiteResults = model.addTestClass(suiteClassName);
             NodeList stdOutElements = document.getElementsByTagName("system-out");
             for (int i = 0; i < stdOutElements.getLength(); i++) {
                 suiteResults.addStandardOutput(stdOutElements.item(i).getTextContent());
index 63aa8a8..a4435d5 100644 (file)
@@ -98,8 +98,9 @@ class TestResult extends TestResultModel implements Comparable<TestResult> {
         return failures;
     }
 
-    public void addFailure(String message, String stackTrace) {
-        classResults.failed(this);
+    public void addFailure(String message, String stackTrace,
+                           String deviceName, String projectName, String flavorName) {
+        classResults.failed(this, deviceName, projectName, flavorName);
         failures.add(new TestFailure(message, stackTrace));
     }
 
diff --git a/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/VariantTestResults.java b/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/VariantTestResults.java
new file mode 100644 (file)
index 0000000..eb1e0b1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.android.build.gradle.internal.test.report;
+
+import com.android.annotations.NonNull;
+
+/**
+ * VariantTestResults to accumulate results per variant
+ */
+class VariantTestResults extends CompositeTestResults {
+
+    private final String name;
+
+    public VariantTestResults(@NonNull String name, CompositeTestResults parent) {
+        super(parent);
+        this.name = name;
+    }
+
+    @Override
+    public String getTitle() {
+        return name;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+}