summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAjay Nadathur <ajayns@google.com>2017-02-21 17:24:54 -0800
committerAjay Nadathur <ajayns@google.com>2017-03-02 14:25:46 -0800
commitab3f5ca46e3f37ca9d16dad6894167969617237c (patch)
treeeb100c40553464af01d6eea19b36c53cb8d8d2b8
parentec93e8cd828f701dea5f92c2de11788945d5f816 (diff)
downloadmisc-ab3f5ca46e3f37ca9d16dad6894167969617237c.tar.gz
Add code coverage support for robolectric tests
- Added targets to generate coverage reports after running robolectric tests. - Use suffix: ${target}-jacoco to run. For example, to run cobertura for setupwizard tests, use: make RunSuwRoboTests-jacoco - Generated reports are placed under $OUT/obj/FAKE/${project}_intermediates/coverage/ bug:32617403 Test: Ran manually, verified that reports are generated. Change-Id: Ia1da0a642901de02bffbbc1d7a0e0d33e9ea3eab
-rw-r--r--common/jacoco/Android.mk30
-rw-r--r--common/jacoco/build.gradle11
-rw-r--r--common/jacoco/lib/NOTICE.txt236
-rw-r--r--common/jacoco/lib/README6
-rw-r--r--common/jacoco/lib/asm-debug-all-5.0.1.jarbin0 -> 380292 bytes
-rw-r--r--common/jacoco/lib/jacocoagent.jarbin0 -> 286862 bytes
-rw-r--r--common/jacoco/lib/org.jacoco.core-0.7.2.201409121644.jarbin0 -> 132915 bytes
-rw-r--r--common/jacoco/lib/org.jacoco.report-0.7.2.201409121644.jarbin0 -> 140205 bytes
-rw-r--r--common/jacoco/src/main/java/com/google/android/jacoco/reporter/ReportGenerator.java201
-rw-r--r--common/robolectric/report-internal.mk58
-rw-r--r--common/robolectric/run_robotests.mk108
11 files changed, 625 insertions, 25 deletions
diff --git a/common/jacoco/Android.mk b/common/jacoco/Android.mk
new file mode 100644
index 00000000..0cc6bf6a
--- /dev/null
+++ b/common/jacoco/Android.mk
@@ -0,0 +1,30 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+my_jacoco_version := 0.7.2.201409121644
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src/main/java) \
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ jvm-jacoco-core \
+ jvm-jacoco-report \
+ jvm-jacoco-asm \
+ commons-cli-1.2
+
+LOCAL_MODULE := jvm-jacoco-reporter
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_IS_HOST_MODULE := true
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+ jvm-jacoco-core:lib/org.jacoco.core-$(my_jacoco_version).jar \
+ jvm-jacoco-report:lib/org.jacoco.report-$(my_jacoco_version).jar \
+ jvm-jacoco-asm:lib/asm-debug-all-5.0.1.jar
+
+include $(BUILD_MULTI_PREBUILT)
+
+my_jacoco_version :=
diff --git a/common/jacoco/build.gradle b/common/jacoco/build.gradle
new file mode 100644
index 00000000..ae2fb4dd
--- /dev/null
+++ b/common/jacoco/build.gradle
@@ -0,0 +1,11 @@
+// NOTE: This is not used during the actual build. Added to conveniently import into intellij
+apply plugin: 'java'
+
+sourceCompatibility = 1.8
+
+def jacocoVersion = "0.7.2.201409121644"
+dependencies {
+ compile files("lib/asm-debug-all-5.0.1.jar")
+ compile files("lib/org.jacoco.core-${jacocoVersion}.jar", "lib/org.jacoco.report-${jacocoVersion}.jar")
+ compile files("../commons-cli/commons-cli-1.2.jar")
+}
diff --git a/common/jacoco/lib/NOTICE.txt b/common/jacoco/lib/NOTICE.txt
new file mode 100644
index 00000000..336f1f70
--- /dev/null
+++ b/common/jacoco/lib/NOTICE.txt
@@ -0,0 +1,236 @@
+License
+
+Copyright © 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+
+The JaCoCo Java Code Coverage Library and all included documentation is made
+available by Mountainminds GmbH & Co. KG, Munich. Except indicated below, the
+Content is provided to you under the terms and conditions of the Eclipse Public
+License Version 1.0 ("EPL"). A copy of the EPL is provided with this Content and
+is also available at http://www.eclipse.org/legal/epl-v10.html.
+
+Trademarks
+
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the
+United States, other countries, or both. Eclipse and all Eclipse related
+trademarks and logos are trademarks of the Eclipse Foundation, Inc. OSGi is a
+trademark, registered trademark, or service mark of The OSGi Alliance in the US
+and other countries. Apache Ant and Apache Maven are trademarks of the Apache
+Software Foundation. Android and Dalvik are trademarks of Google Inc. All other
+trademarks are the property of their respective owners.
+
+Third Party Content
+
+The Content includes items that have been sourced from third parties as set out
+below.
+
+ASM
+
+ASM is subject to the terms and conditions of the following license:
+
+Copyright (c) 2012 France Télécom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+Google Code Prettify
+
+Google Code Prettify is subject to the terms and conditions of the following license:
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
diff --git a/common/jacoco/lib/README b/common/jacoco/lib/README
new file mode 100644
index 00000000..38b583ab
--- /dev/null
+++ b/common/jacoco/lib/README
@@ -0,0 +1,6 @@
+This directory contains JAR files from the distribution of JaCoCo
+(http://eclemma.org/jacoco/), version 0.7.2.201409121644.
+
+URL: http://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.7.2.201409121644/jacoco-0.7.2.201409121644.zip
+
+Only the files that are needed have been included here.
diff --git a/common/jacoco/lib/asm-debug-all-5.0.1.jar b/common/jacoco/lib/asm-debug-all-5.0.1.jar
new file mode 100644
index 00000000..76d4b6a7
--- /dev/null
+++ b/common/jacoco/lib/asm-debug-all-5.0.1.jar
Binary files differ
diff --git a/common/jacoco/lib/jacocoagent.jar b/common/jacoco/lib/jacocoagent.jar
new file mode 100644
index 00000000..29f58bd8
--- /dev/null
+++ b/common/jacoco/lib/jacocoagent.jar
Binary files differ
diff --git a/common/jacoco/lib/org.jacoco.core-0.7.2.201409121644.jar b/common/jacoco/lib/org.jacoco.core-0.7.2.201409121644.jar
new file mode 100644
index 00000000..addca25e
--- /dev/null
+++ b/common/jacoco/lib/org.jacoco.core-0.7.2.201409121644.jar
Binary files differ
diff --git a/common/jacoco/lib/org.jacoco.report-0.7.2.201409121644.jar b/common/jacoco/lib/org.jacoco.report-0.7.2.201409121644.jar
new file mode 100644
index 00000000..6152df44
--- /dev/null
+++ b/common/jacoco/lib/org.jacoco.report-0.7.2.201409121644.jar
Binary files differ
diff --git a/common/jacoco/src/main/java/com/google/android/jacoco/reporter/ReportGenerator.java b/common/jacoco/src/main/java/com/google/android/jacoco/reporter/ReportGenerator.java
new file mode 100644
index 00000000..c428f146
--- /dev/null
+++ b/common/jacoco/src/main/java/com/google/android/jacoco/reporter/ReportGenerator.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.google.android.jacoco.reporter;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+import org.jacoco.core.analysis.Analyzer;
+import org.jacoco.core.analysis.CoverageBuilder;
+import org.jacoco.core.analysis.IBundleCoverage;
+import org.jacoco.core.data.ExecutionDataStore;
+import org.jacoco.core.tools.ExecFileLoader;
+import org.jacoco.report.DirectorySourceFileLocator;
+import org.jacoco.report.FileMultiReportOutput;
+import org.jacoco.report.IMultiReportOutput;
+import org.jacoco.report.IReportVisitor;
+import org.jacoco.report.MultiReportVisitor;
+import org.jacoco.report.MultiSourceFileLocator;
+import org.jacoco.report.html.HTMLFormatter;
+import org.jacoco.report.xml.XMLFormatter;
+import org.objectweb.asm.ClassReader;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ReportGenerator {
+ private static final String OPT_CLASSPATH = "classpath";
+ private static final String OPT_REPORT_NAME = "name";
+ private static final String OPT_EXEC_FILE = "exec-file";
+ private static final String OPT_SOURCES = "srcs";
+ private static final String OPT_REPORT_DIR = "report-dir";
+ private static final int TAB_WIDTH = 4;
+
+ private final Config mConfig;
+
+ private ReportGenerator(Config config) {
+ mConfig = config;
+ }
+
+ private void execute() {
+ ExecFileLoader execFileLoader = new ExecFileLoader();
+ try {
+ execFileLoader.load(mConfig.mExecFileDir);
+ IReportVisitor reportVisitor = new MultiReportVisitor(getVisitors());
+ reportVisitor.visitInfo(execFileLoader.getSessionInfoStore().getInfos(),
+ execFileLoader.getExecutionDataStore().getContents());
+ MultiSourceFileLocator sourceFileLocator = new MultiSourceFileLocator(TAB_WIDTH);
+ mConfig.mSourceDirs.stream().filter(File::isDirectory)
+ .map(sourceDir -> new DirectorySourceFileLocator(sourceDir, null, TAB_WIDTH))
+ .forEach(sourceFileLocator::add);
+ reportVisitor.visitBundle(createBundle(execFileLoader.getExecutionDataStore()),
+ sourceFileLocator);
+ reportVisitor.visitEnd();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private IBundleCoverage createBundle(ExecutionDataStore dataStore) throws IOException {
+ CoverageBuilder coverageBuilder = new CoverageBuilder();
+ Analyzer analyzer = new Analyzer(dataStore, coverageBuilder) {
+ @Override
+ public void analyzeClass(ClassReader reader) {
+ if (weHaveSourceFor(reader.getClassName())) {
+ super.analyzeClass(reader);
+ }
+ }
+
+ private boolean weHaveSourceFor(String asmClassName) {
+ String fileName = asmClassName.replaceFirst("\\$.*", "") + ".java";
+ return mConfig.mSourceDirs.stream().map(parent -> new File(parent, fileName))
+ .anyMatch(File::exists);
+ }
+ };
+
+ for (File file : mConfig.mClasspath) {
+ analyzer.analyzeAll(file);
+ }
+ return coverageBuilder.getBundle(mConfig.mReportName);
+ }
+
+ private List<IReportVisitor> getVisitors() throws Exception {
+ List<IReportVisitor> visitors = new ArrayList<>();
+ visitors.add(new XMLFormatter().createVisitor(mConfig.getXmlOutputStream()));
+ visitors.add(new HTMLFormatter().createVisitor(mConfig.getHtmlReportOutput()));
+ return visitors;
+ }
+
+ private static class Config {
+ final String mReportName;
+ final List<File> mClasspath;
+ final List<File> mSourceDirs;
+ final File mReportDir;
+ final File mExecFileDir;
+
+ Config(String reportName, List<File> classpath, List<File> sourceDirs,
+ File reportDir, File execFileDir) {
+ mReportName = reportName;
+ mClasspath = classpath;
+ mSourceDirs = sourceDirs;
+ mReportDir = reportDir;
+ mExecFileDir = execFileDir;
+ }
+
+ FileOutputStream getXmlOutputStream() throws FileNotFoundException {
+ File xmlFile = new File(mReportDir, "coverage.xml");
+ return new FileOutputStream(xmlFile);
+ }
+
+ static Config from(CommandLine commandLine) {
+ List<File> classpaths = parse(commandLine.getOptionValue(OPT_CLASSPATH),
+ "WARN: Classpath entry [%s] does not exist or is not a directory");
+ List<File> sources = parse(commandLine.getOptionValue(OPT_SOURCES),
+ "WARN: Source entry [%s] does not exist or is not a directory");
+ File execFileDir = new File(commandLine.getOptionValue(OPT_EXEC_FILE));
+ ensure(execFileDir.exists() && execFileDir.canRead() && execFileDir.isFile(),
+ "execFile: [%s] does not exist or could not be read.", execFileDir);
+
+ File reportDir = new File(commandLine.getOptionValue(OPT_REPORT_DIR));
+ ensure(reportDir.exists() || reportDir.mkdirs(),
+ "Unable to create report dir [%s]", reportDir);
+
+ return new Config(commandLine.getOptionValue(OPT_REPORT_NAME), classpaths, sources,
+ reportDir, execFileDir);
+ }
+
+ IMultiReportOutput getHtmlReportOutput() {
+ return new FileMultiReportOutput(mReportDir);
+ }
+ }
+
+ private static void ensure(boolean condition, String errorMessage, Object... args) {
+ if (!condition) {
+ System.err.printf(errorMessage, args);
+ System.exit(0);
+ }
+ }
+
+ private static List<File> parse(String value, String warningMessage) {
+ List<File> files = new ArrayList<>(0);
+ for (String classpath : value.split(System.getProperty("path.separator"))) {
+ File file = new File(classpath);
+ if (file.exists()) {
+ files.add(file);
+ } else {
+ System.out.println(String.format(warningMessage, classpath));
+ }
+ }
+ return files;
+ }
+
+ private static void printHelp(ParseException e, Options options) {
+ System.out.println(e.getMessage());
+ HelpFormatter helpFormatter = new HelpFormatter();
+ helpFormatter.printHelp("java -cp ${report.jar} " + ReportGenerator.class.getName(),
+ "Generates jacoco reports in XML and HTML format.", options, "", true);
+ }
+
+ private static void addOption(Options options, String longName, String description) {
+ Option option = new Option(null, longName, true, description);
+ option.setArgs(1);
+ option.setRequired(true);
+ options.addOption(option);
+ }
+
+ public static void main(String[] args) {
+ Options options = new Options();
+ try {
+ // TODO: Support multiple exec-files
+ addOption(options, OPT_CLASSPATH, "Classpath used during testing");
+ addOption(options, OPT_EXEC_FILE, "File generated by jacoco during testing");
+ addOption(options, OPT_REPORT_NAME, "Name of the project tested");
+ addOption(options, OPT_REPORT_DIR, "Directory into which reports will be generated");
+ addOption(options, OPT_SOURCES, "List of source directories");
+ CommandLine commandLine = new PosixParser().parse(options, args);
+ new ReportGenerator(Config.from(commandLine))
+ .execute();
+ } catch (ParseException e) {
+ printHelp(e, options);
+ System.exit(1);
+ }
+ }
+}
diff --git a/common/robolectric/report-internal.mk b/common/robolectric/report-internal.mk
new file mode 100644
index 00000000..e74fb81f
--- /dev/null
+++ b/common/robolectric/report-internal.mk
@@ -0,0 +1,58 @@
+# Defines a target named $(my_target) for generating a coverage report.
+
+my_report_dir := $(my_coverage_dir)/reports
+my_coverage_output := $(my_report_dir)/html
+
+# Private variables.
+$(my_coverage_output): \
+ PRIVATE_MODULE := $(LOCAL_MODULE)
+$(my_coverage_output): \
+ PRIVATE_COVERAGE_FILE := $(my_coverage_file)
+$(my_coverage_output): \
+ PRIVATE_COVERAGE_SRCS_JARS := $(my_coverage_srcs_jars)
+$(my_coverage_output): \
+ PRIVATE_INSTRUMENT_SOURCE_DIRS := $(my_instrument_source_dirs)
+$(my_coverage_output): \
+ PRIVATE_COVERAGE_REPORT_CLASS := $(my_coverage_report_class)
+$(my_coverage_output): \
+ PRIVATE_COVERAGE_REPORT_JAR := $(my_coverage_report_jar)
+$(my_coverage_output): \
+ PRIVATE_REPORT_DIR := $(my_report_dir)
+
+# Generate the coverage report.
+$(my_coverage_output): $(my_collect_target) $(my_coverage_report_jar)
+ $(hide) rm -rf $(PRIVATE_REPORT_DIR)
+ $(hide) mkdir -p $(PRIVATE_REPORT_DIR)
+ $(hide) java \
+ -cp $(PRIVATE_COVERAGE_REPORT_JAR) \
+ $(PRIVATE_COVERAGE_REPORT_CLASS) \
+ --classpath $(strip $(call normalize-path-list, $(PRIVATE_COVERAGE_SRCS_JARS))) \
+ --exec-file $(PRIVATE_COVERAGE_FILE) \
+ --name $(PRIVATE_MODULE) \
+ --report-dir $(PRIVATE_REPORT_DIR)/ \
+ --srcs $(strip $(call normalize-path-list, $(PRIVATE_INSTRUMENT_SOURCE_DIRS))) \
+ >$(PRIVATE_REPORT_DIR)/reporter.txt 2>&1
+ $(hide) abs="$$(realpath "$(PRIVATE_REPORT_DIR)")"; \
+ echo "Coverage report:" \
+ "file://$$abs/index.html" \
+
+# Generate a ZIP file of the coverage report.
+my_coverage_output_zip := \
+ $(my_coverage_dir)/report-$(my_coverage_report_format).zip
+
+$(my_coverage_output_zip): \
+ PRIVATE_REPORT_DIR := $(my_report_dir)
+$(my_coverage_output_zip): $(my_coverage_output)
+ $(hide) cd $(PRIVATE_REPORT_DIR) && zip -r $(PWD)/$@ .
+
+# Add coverage report zip to dist files.
+$(call dist-for-goals, $(my_target), \
+ $(my_coverage_output_zip):robotests/$(my_coverage_report_dist_file))
+
+# Running the coverage will always generate the report.
+$(my_target): $(my_coverage_output)
+
+# Reset local variables.
+my_coverage_output :=
+my_coverage_output_zip :=
+my_report_dir :=
diff --git a/common/robolectric/run_robotests.mk b/common/robolectric/run_robotests.mk
index 3ea95d67..1f11ae94 100644
--- a/common/robolectric/run_robotests.mk
+++ b/common/robolectric/run_robotests.mk
@@ -109,6 +109,8 @@ my_robolectric_jars := \
$(my_robolectric_path)/xpp3_min-1.1.4c.jar \
$(my_robolectric_path)/xstream-1.4.8.jar
+my_collect_target := $(LOCAL_MODULE)-coverage
+my_report_target := $(LOCAL_MODULE)-jacoco
# Whether or not to ignore the result of running the robotests.
# LOCAL_ROBOTEST_FAILURE_FATAL will take precedence over ROBOTEST_FAILURE_FATAL,
# if present.
@@ -140,25 +142,13 @@ else
my_test_filter_command := grep -E "$(ROBOTEST_FILTER)"
endif
-# Setting the DEBUG_ROBOLECTRIC environment variable will print additional logging from
-# Robolectric and also make it wait for a debugger to be connected.
-# For Android Studio / IntelliJ the debugger can be connected via the "remote" configuration:
-# https://www.jetbrains.com/help/idea/2016.2/run-debug-configuration-remote.html
-# From command line the debugger can be connected via
-# jdb -attach localhost:5005
-ifdef DEBUG_ROBOLECTRIC
- # The arguments to the JVM needed to debug the tests.
- # - server: wait for connection rather than connecting to a debugger
- # - transport: how to accept debugger connections (sockets)
- # - address: the port on which to accept debugger connections
- # - timeout: how long (in ms) to wait for a debugger to connect
- # - suspend: do not start running any code until the debugger connects
- my_java_args := \
- -Drobolectric.logging.enabled=true \
- -Xdebug -agentlib:jdwp=server=y,transport=dt_socket,address=5005,suspend=y
-
- # Remove the timeout so Robolectric doesn't get killed while debugging
- my_timeout := 0
+# The directory containing the sources.
+ifeq ($(strip $(LOCAL_INSTRUMENT_SOURCE_DIRS)),)
+ # If not specified, defaults to the src and java directories in the parent
+ # directory.
+ my_instrument_source_dirs := $(dir $(LOCAL_PATH))/src $(dir $(LOCAL_PATH))/java
+else
+ my_instrument_source_dirs := $(LOCAL_INSTRUMENT_SOURCE_DIRS)
endif
##########################
@@ -207,23 +197,91 @@ my_jars := $(my_robolectric_jars) \
prebuilts/sdk/$(LOCAL_SDK_VERSION)/android.jar \
$(my_srcs_jars)
+
+
# Run tests.
my_target := $(LOCAL_BUILT_MODULE)
+
+# Setting the DEBUG_ROBOLECTRIC environment variable will print additional logging from
+# Robolectric and also make it wait for a debugger to be connected.
+# For Android Studio / IntelliJ the debugger can be connected via the "remote" configuration:
+# https://www.jetbrains.com/help/idea/2016.2/run-debug-configuration-remote.html
+# From command line the debugger can be connected via
+# jdb -attach localhost:5005
+ifdef DEBUG_ROBOLECTRIC
+ # The arguments to the JVM needed to debug the tests.
+ # - server: wait for connection rather than connecting to a debugger
+ # - transport: how to accept debugger connections (sockets)
+ # - address: the port on which to accept debugger connections
+ # - timeout: how long (in ms) to wait for a debugger to connect
+ # - suspend: do not start running any code until the debugger connects
+ my_java_args := \
+ -Drobolectric.logging.enabled=true \
+ -Xdebug -agentlib:jdwp=server=y,transport=dt_socket,address=5005,suspend=y
+
+ # Remove the timeout so Robolectric doesn't get killed while debugging
+ my_timeout := 0
+endif
+
include $(my_robolectric_script_path)/robotest-internal.mk
+# clean local variables
+my_java_args :=
+my_target :=
-# Clear temporary variables.
+# Target for running robolectric tests using jacoco
+my_target := $(my_collect_target)
+my_jacoco_dir := \
+ prebuilts/misc/common/jacoco
+
+my_coverage_dir := $(dir $(LOCAL_BUILT_MODULE))/coverage/
+my_coverage_file := $(my_coverage_dir)/jacoco.exec
+
+# List of packages to exclude jacoco from running
+my_jacoco_excludes := \
+ org.robolectric.*:org.mockito.*:org.junit.*:org.objectweb.*:com.thoughtworks.xstream.*
+# The Jacoco agent JAR.
+my_jacoco_agent_jar := \
+ $(my_jacoco_dir)/lib/jacocoagent.jar
+my_coverage_java_args := \
+ -javaagent:$(my_jacoco_agent_jar)=destfile=$(my_coverage_file),excludes=$(my_jacoco_excludes)
+my_java_args := $(my_coverage_java_args)
+include $(my_robolectric_script_path)/robotest-internal.mk
+# Clear temporary variables
+my_coverage_java_args :=
my_failure_fatal :=
-my_jars :=
+my_jacoco_agent_jar :=
+my_jacoco_dir :=
+my_jacoco_excludes :=
my_java_args :=
my_robolectric_jars :=
my_robolectric_path :=
-my_robolectric_script_path :=
-my_srcs_jars :=
my_target :=
-my_target_message :=
my_test_filter_command :=
my_tests :=
-my_timeout :=
+
+# Target for generating code coverage reports using jacoco.exec
+my_target := $(my_report_target)
+# The JAR file containing the report generation tool.
+my_coverage_report_class := \
+ com.google.android.jacoco.reporter.ReportGenerator
+my_coverage_report_jar := \
+ $(call intermediates-dir-for, \
+ JAVA_LIBRARIES, jvm-jacoco-reporter,host)/javalib.jar
+my_coverage_srcs_jars := $(my_srcs_jars)
+my_coverage_report_dist_file := $(my_report_target)-html.zip
+
+## jacoco code coverage reports
+include $(my_robolectric_script_path)/report-internal.mk
+# Clear temporary variables
+my_coverage_dir :=
+my_coverage_file :=
+my_coverage_report_class :=
+my_coverage_report_dist_file :=
+my_coverage_report_jar :=
+my_coverage_srcs_jars :=
+my_robolectric_script_path :=
+my_srcs_jars :=
+my_target :=
# Clear local variables specific to this build.
LOCAL_ROBOTEST_FAILURE_FATAL :=