GitHub #388: New Maven goal "report-aggregate" to create reports for multi-module projects
diff --git a/jacoco-maven-plugin.test/it/it-multi-module/verify.bsh b/jacoco-maven-plugin.test/it/it-multi-module/verify.bsh
index 7efaea9..5593569 100644
--- a/jacoco-maven-plugin.test/it/it-multi-module/verify.bsh
+++ b/jacoco-maven-plugin.test/it/it-multi-module/verify.bsh
@@ -13,7 +13,7 @@
 import org.codehaus.plexus.util.*;
 
 String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) );
-if ( buildLog.indexOf( "Skipping JaCoCo execution due to missing classes directory:" ) < 0 ) {
+if ( buildLog.indexOf( "Skipping JaCoCo execution due to missing classes directory." ) < 0 ) {
     throw new RuntimeException( "Execution should be skipped when target/classes does not exist." );
 }
 
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/pom.xml
new file mode 100644
index 0000000..d65b7a6
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+   All rights reserved. This program and the accompanying materials
+   are made available under the terms of the Eclipse Public License v1.0
+   which accompanies this distribution, and is available at
+   http://www.eclipse.org/legal/epl-v10.html
+
+   Contributors:
+      Marc R. Hoffmann, Jan Wloka - initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>jacoco</groupId>
+    <artifactId>it-report-aggregate</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>child1-test</artifactId>
+  <packaging>jar</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>jacoco</groupId>
+      <artifactId>child1</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+  
+</project>
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/src/test/java/package1/Example1bTest.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/src/test/java/package1/Example1bTest.java
new file mode 100644
index 0000000..2b621c6
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/src/test/java/package1/Example1bTest.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Marc R. Hoffmann, Jan Wloka - initial API and implementation
+ *
+ *******************************************************************************/
+package package1;
+
+import org.junit.Test;
+
+public class Example1bTest {
+
+  @Test
+  public void test() {
+    new Example1b().b();
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/pom.xml
new file mode 100644
index 0000000..530e0a1
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+   All rights reserved. This program and the accompanying materials
+   are made available under the terms of the Eclipse Public License v1.0
+   which accompanies this distribution, and is available at
+   http://www.eclipse.org/legal/epl-v10.html
+
+   Contributors:
+      Marc R. Hoffmann, Jan Wloka - initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>jacoco</groupId>
+    <artifactId>it-report-aggregate</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>child1</artifactId>
+  <packaging>jar</packaging>
+  
+</project>
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1a.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1a.java
new file mode 100644
index 0000000..99e6534
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1a.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Marc R. Hoffmann, Jan Wloka - initial API and implementation
+ *
+ *******************************************************************************/
+package package1;
+
+public class Example1a {
+
+  public void a() {
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1b.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1b.java
new file mode 100644
index 0000000..a574146
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1b.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Marc R. Hoffmann, Jan Wloka - initial API and implementation
+ *
+ *******************************************************************************/
+package package1;
+
+public class Example1b {
+
+  public void b() {
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/test/java/package1/Example1aTest.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/test/java/package1/Example1aTest.java
new file mode 100644
index 0000000..04ffa75
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/test/java/package1/Example1aTest.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Marc R. Hoffmann, Jan Wloka - initial API and implementation
+ *
+ *******************************************************************************/
+package package1;
+
+import org.junit.Test;
+
+public class Example1aTest {
+
+  @Test
+  public void test() {
+    new Example1a().a();
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/pom.xml
new file mode 100644
index 0000000..e340ca2
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+   All rights reserved. This program and the accompanying materials
+   are made available under the terms of the Eclipse Public License v1.0
+   which accompanies this distribution, and is available at
+   http://www.eclipse.org/legal/epl-v10.html
+
+   Contributors:
+      Marc R. Hoffmann, Jan Wloka - initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>jacoco</groupId>
+    <artifactId>it-report-aggregate</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>child2</artifactId>
+  <packaging>jar</packaging>
+  
+</project>
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/main/java/package2/Example2.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/main/java/package2/Example2.java
new file mode 100644
index 0000000..5895fbb
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/main/java/package2/Example2.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Marc R. Hoffmann, Jan Wloka - initial API and implementation
+ *
+ *******************************************************************************/
+package package2;
+
+public class Example2 {
+
+  public void a() {
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/test/java/package2/Example2Test.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/test/java/package2/Example2Test.java
new file mode 100644
index 0000000..f382fc2
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/test/java/package2/Example2Test.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Marc R. Hoffmann, Jan Wloka - initial API and implementation
+ *
+ *******************************************************************************/
+package package2;
+
+import org.junit.Test;
+
+public class Example2Test {
+
+  @Test
+  public void test() {
+    new Example2().a();
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml
new file mode 100644
index 0000000..71b7a19
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+   All rights reserved. This program and the accompanying materials
+   are made available under the terms of the Eclipse Public License v1.0
+   which accompanies this distribution, and is available at
+   http://www.eclipse.org/legal/epl-v10.html
+
+   Contributors:
+      Marc R. Hoffmann, Jan Wloka - initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>jacoco</groupId>
+    <artifactId>setup-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>it-report-aggregate</artifactId>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>child1</module>
+    <module>child1-test</module>
+    <module>child2</module>
+    <module>report</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>@project.groupId@</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>prepare-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml
new file mode 100644
index 0000000..d6e6fc7
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+   All rights reserved. This program and the accompanying materials
+   are made available under the terms of the Eclipse Public License v1.0
+   which accompanies this distribution, and is available at
+   http://www.eclipse.org/legal/epl-v10.html
+
+   Contributors:
+      Marc R. Hoffmann, Jan Wloka - initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>jacoco</groupId>
+    <artifactId>it-report-aggregate</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>report</artifactId>
+  <name>Aggregate Report</name>
+  
+  <dependencies>
+    <dependency>
+      <groupId>jacoco</groupId>
+      <artifactId>child1</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>jacoco</groupId>
+      <artifactId>child1-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>jacoco</groupId>
+      <artifactId>child2</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>@project.groupId@</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>report-aggregate</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>report-aggregate</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh b/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh
new file mode 100644
index 0000000..32a52dc
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Marc R. Hoffmann, Jan Wloka - initial API and implementation
+ *
+ *******************************************************************************/
+import org.codehaus.plexus.util.*;
+
+String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) );
+
+if ( buildLog.indexOf( "/child1/target/jacoco.exec" ) < 0 ) {
+    throw new RuntimeException( "Execution data from child1 was not loaded." );
+}
+
+if ( buildLog.indexOf( "/child1-test/target/jacoco.exec" ) < 0 ) {
+    throw new RuntimeException( "Execution data from child1-test was not loaded." );
+}
+
+if ( buildLog.indexOf( "/child2/target/jacoco.exec" ) < 0 ) {
+    throw new RuntimeException( "Execution data from child2 was not loaded." );
+}
+
+File reportChild1 = new File( basedir, "report/target/site/jacoco-aggregate/child1/index.html" );
+if ( !reportChild1.isFile() ) {
+    throw new RuntimeException( "Report for child1 was not created." );
+}
+
+File reportChild1test = new File( basedir, "report/target/site/jacoco-aggregate/child1-test/index.html" );
+if ( reportChild1test.isFile() ) {
+    throw new RuntimeException( "Report for child1-test should not be created." );
+}
+
+File reportChild2 = new File( basedir, "report/target/site/jacoco-aggregate/child2/index.html" );
+if ( !reportChild2.isFile() ) {
+    throw new RuntimeException( "Report for child2 was not created." );
+}
diff --git a/jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh b/jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh
index 90a58a9..a53ee99 100644
--- a/jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh
+++ b/jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh
@@ -13,6 +13,6 @@
 import org.codehaus.plexus.util.*;
 
 String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) );
-if ( buildLog.indexOf( "Unable to read execution data file" ) < 0 ) {
+if ( buildLog.indexOf( "Invalid execution data file." ) < 0 ) {
     throw new RuntimeException( "Error was not printed" );
 }
diff --git a/jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh b/jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh
index 00a7667..458148b 100644
--- a/jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh
+++ b/jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh
@@ -13,7 +13,7 @@
 import org.codehaus.plexus.util.*;
 
 String projectReportsPage = FileUtils.fileRead( new File( basedir, "target/site/project-reports.html" ) );
-if ( projectReportsPage.indexOf( "JaCoCo Test Coverage Report." ) < 0 ) {
+if ( projectReportsPage.indexOf( "JaCoCo Coverage Report." ) < 0 ) {
     throw new RuntimeException( "project-reports.html does not contain link to JaCoCo report" );
 }
 
diff --git a/jacoco-maven-plugin.test/it/it-site/verify.bsh b/jacoco-maven-plugin.test/it/it-site/verify.bsh
index f2ea829..d1c7cd3 100644
--- a/jacoco-maven-plugin.test/it/it-site/verify.bsh
+++ b/jacoco-maven-plugin.test/it/it-site/verify.bsh
@@ -13,7 +13,7 @@
 import org.codehaus.plexus.util.*;
 
 String projectReportsPage = FileUtils.fileRead( new File( basedir, "target/site/project-reports.html" ) );
-if ( projectReportsPage.indexOf( "JaCoCo Test Coverage Report." ) < 0 ) {
+if ( projectReportsPage.indexOf( "JaCoCo Coverage Report." ) < 0 ) {
     throw new RuntimeException( "project-reports.html does not contain link to JaCoCo report" );
 }
 
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java
index 5d9d7c1..0db69d6 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java
@@ -11,13 +11,7 @@
  *******************************************************************************/
 package org.jacoco.maven;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
@@ -26,19 +20,8 @@
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.reporting.AbstractMavenReport;
 import org.apache.maven.reporting.MavenReportException;
-import org.jacoco.core.analysis.IBundleCoverage;
-import org.jacoco.core.analysis.ICoverageNode;
-import org.jacoco.core.data.ExecutionDataStore;
-import org.jacoco.core.data.SessionInfoStore;
-import org.jacoco.core.tools.ExecFileLoader;
-import org.jacoco.report.FileMultiReportOutput;
 import org.jacoco.report.IReportGroupVisitor;
 import org.jacoco.report.IReportVisitor;
-import org.jacoco.report.ISourceFileLocator;
-import org.jacoco.report.MultiReportVisitor;
-import org.jacoco.report.csv.CSVFormatter;
-import org.jacoco.report.html.HTMLFormatter;
-import org.jacoco.report.xml.XMLFormatter;
 
 /**
  * Base class for creating a code coverage report for tests of a single project
@@ -53,13 +36,30 @@
 	 *            default-value="UTF-8"
 	 */
 	String outputEncoding;
+
+	/**
+	 * Name of the root node HTML report pages.
+	 * 
+	 * @parameter default-value="${project.name}"
+	 * @since 0.7.7
+	 */
+	String title;
+
+	/**
+	 * Footer text used in HTML report pages.
+	 * 
+	 * @parameter
+	 * @since 0.7.7
+	 */
+	String footer;
+
 	/**
 	 * Encoding of the source files.
 	 * 
-	 * @parameter property="project.build.sourceEncoding"
-	 *            default-value="UTF-8"
+	 * @parameter property="project.build.sourceEncoding" default-value="UTF-8"
 	 */
 	String sourceEncoding;
+
 	/**
 	 * A list of class files to include in the report. May use wildcard
 	 * characters (* and ?). When not specified everything will be included.
@@ -67,6 +67,7 @@
 	 * @parameter
 	 */
 	List<String> includes;
+
 	/**
 	 * A list of class files to exclude from the report. May use wildcard
 	 * characters (* and ?). When not specified nothing will be excluded.
@@ -74,12 +75,14 @@
 	 * @parameter
 	 */
 	List<String> excludes;
+
 	/**
 	 * Flag used to suppress execution.
 	 * 
 	 * @parameter property="jacoco.skip" default-value="false"
 	 */
 	boolean skip;
+
 	/**
 	 * Maven project.
 	 * 
@@ -87,18 +90,13 @@
 	 * @readonly
 	 */
 	MavenProject project;
+
 	/**
 	 * Doxia Site Renderer.
 	 * 
 	 * @component
 	 */
 	Renderer siteRenderer;
-	SessionInfoStore sessionInfoStore;
-	ExecutionDataStore executionDataStore;
-
-	public abstract String getOutputName();
-
-	public abstract String getName(final Locale locale);
 
 	public String getDescription(final Locale locale) {
 		return getName(locale) + " Coverage Report.";
@@ -138,33 +136,29 @@
 	}
 
 	@Override
-	public abstract void setReportOutputDirectory(
-			final File reportOutputDirectory);
-
-	@Override
 	public boolean canGenerateReport() {
 		if (skip) {
 			getLog().info(
 					"Skipping JaCoCo execution because property jacoco.skip is set.");
 			return false;
 		}
-		if (!getDataFile().exists()) {
+		if (!canGenerateReportRegardingDataFiles()) {
 			getLog().info(
-					"Skipping JaCoCo execution due to missing execution data file:"
-							+ getDataFile());
+					"Skipping JaCoCo execution due to missing execution data file.");
 			return false;
 		}
-		final File classesDirectory = new File(getProject().getBuild()
-				.getOutputDirectory());
-		if (!classesDirectory.exists()) {
+		if (!canGenerateReportRegardingClassesDirectory()) {
 			getLog().info(
-					"Skipping JaCoCo execution due to missing classes directory:"
-							+ classesDirectory);
+					"Skipping JaCoCo execution due to missing classes directory.");
 			return false;
 		}
 		return true;
 	}
 
+	abstract boolean canGenerateReportRegardingDataFiles();
+
+	abstract boolean canGenerateReportRegardingClassesDirectory();
+
 	/**
 	 * This method is called when the report generation is invoked directly as a
 	 * standalone Mojo.
@@ -185,12 +179,12 @@
 	@Override
 	protected void executeReport(final Locale locale)
 			throws MavenReportException {
-		loadExecutionData();
 		try {
-			final IReportVisitor visitor = createVisitor(locale);
-			visitor.visitInfo(sessionInfoStore.getInfos(),
-					executionDataStore.getContents());
-			createReport(visitor);
+			final ReportSupport support = new ReportSupport(getLog());
+			loadExecutionData(support);
+			addFormatters(support, locale);
+			final IReportVisitor visitor = support.initRootVisitor();
+			createReport(visitor, support);
 			visitor.visitEnd();
 		} catch (final IOException e) {
 			throw new MavenReportException("Error while creating report: "
@@ -198,110 +192,13 @@
 		}
 	}
 
-	void loadExecutionData() throws MavenReportException {
-		final ExecFileLoader loader = new ExecFileLoader();
-		try {
-			loader.load(getDataFile());
-		} catch (final IOException e) {
-			throw new MavenReportException(
-					"Unable to read execution data file " + getDataFile()
-							+ ": " + e.getMessage(), e);
-		}
-		sessionInfoStore = loader.getSessionInfoStore();
-		executionDataStore = loader.getExecutionDataStore();
-	}
+	abstract void loadExecutionData(final ReportSupport support)
+			throws IOException;
 
-	void createReport(final IReportGroupVisitor visitor) throws IOException {
-		final FileFilter fileFilter = new FileFilter(this.getIncludes(),
-				this.getExcludes());
-		final BundleCreator creator = new BundleCreator(this.getProject(),
-				fileFilter, getLog());
-		final IBundleCoverage bundle = creator.createBundle(executionDataStore);
-		final SourceFileCollection locator = new SourceFileCollection(
-				getCompileSourceRoots(), sourceEncoding);
-		checkForMissingDebugInformation(bundle);
-		visitor.visitBundle(bundle, locator);
-	}
+	abstract void addFormatters(final ReportSupport support, final Locale locale)
+			throws IOException;
 
-	void checkForMissingDebugInformation(final ICoverageNode node) {
-		if (node.getClassCounter().getTotalCount() > 0
-				&& node.getLineCounter().getTotalCount() == 0) {
-			getLog().warn(
-					"To enable source code annotation class files have to be compiled with debug information.");
-		}
-	}
-
-	IReportVisitor createVisitor(final Locale locale) throws IOException {
-		final List<IReportVisitor> visitors = new ArrayList<IReportVisitor>();
-		getOutputDirectoryFile().mkdirs();
-		final XMLFormatter xmlFormatter = new XMLFormatter();
-		xmlFormatter.setOutputEncoding(outputEncoding);
-		visitors.add(xmlFormatter.createVisitor(new FileOutputStream(new File(
-				getOutputDirectoryFile(), "jacoco.xml"))));
-		final CSVFormatter csvFormatter = new CSVFormatter();
-		csvFormatter.setOutputEncoding(outputEncoding);
-		visitors.add(csvFormatter.createVisitor(new FileOutputStream(new File(
-				getOutputDirectoryFile(), "jacoco.csv"))));
-		final HTMLFormatter htmlFormatter = new HTMLFormatter();
-		htmlFormatter.setOutputEncoding(outputEncoding);
-		htmlFormatter.setLocale(locale);
-		visitors.add(htmlFormatter.createVisitor(new FileMultiReportOutput(
-				getOutputDirectoryFile())));
-		return new MultiReportVisitor(visitors);
-	}
-
-	File resolvePath(final String path) {
-		File file = new File(path);
-		if (!file.isAbsolute()) {
-			file = new File(getProject().getBasedir(), path);
-		}
-		return file;
-	}
-
-	List<File> getCompileSourceRoots() {
-		final List<File> result = new ArrayList<File>();
-		for (final Object path : getProject().getCompileSourceRoots()) {
-			result.add(resolvePath((String) path));
-		}
-		return result;
-	}
-
-	private static class SourceFileCollection implements ISourceFileLocator {
-
-		private final List<File> sourceRoots;
-		private final String encoding;
-
-		public SourceFileCollection(final List<File> sourceRoots,
-				final String encoding) {
-			this.sourceRoots = sourceRoots;
-			this.encoding = encoding;
-		}
-
-		public Reader getSourceFile(final String packageName,
-				final String fileName) throws IOException {
-			final String r;
-			if (packageName.length() > 0) {
-				r = packageName + '/' + fileName;
-			} else {
-				r = fileName;
-			}
-			for (final File sourceRoot : sourceRoots) {
-				final File file = new File(sourceRoot, r);
-				if (file.exists() && file.isFile()) {
-					return new InputStreamReader(new FileInputStream(file),
-							encoding);
-				}
-			}
-			return null;
-		}
-
-		public int getTabWidth() {
-			return 4;
-		}
-	}
-
-	abstract File getDataFile();
-
-	abstract File getOutputDirectoryFile();
+	abstract void createReport(final IReportGroupVisitor visitor,
+			final ReportSupport support) throws IOException;
 
 }
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java b/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java
deleted file mode 100644
index b4c8179..0000000
--- a/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Evgeny Mandrikov - initial API and implementation
- *    Kyle Lieber - implementation of CheckMojo
- *
- *******************************************************************************/
-package org.jacoco.maven;
-
-import static java.lang.String.format;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.FileUtils;
-import org.jacoco.core.analysis.Analyzer;
-import org.jacoco.core.analysis.CoverageBuilder;
-import org.jacoco.core.analysis.IBundleCoverage;
-import org.jacoco.core.analysis.IClassCoverage;
-import org.jacoco.core.data.ExecutionDataStore;
-
-/**
- * Creates an IBundleCoverage.
- */
-public final class BundleCreator {
-
-	private final MavenProject project;
-	private final FileFilter fileFilter;
-	private final Log log;
-
-	/**
-	 * Construct a new BundleCreator given the MavenProject and FileFilter.
-	 * 
-	 * @param project
-	 *            the MavenProject
-	 * @param fileFilter
-	 *            the FileFilter
-	 * @param log
-	 *            for log output
-	 */
-	public BundleCreator(final MavenProject project,
-			final FileFilter fileFilter, final Log log) {
-		this.project = project;
-		this.fileFilter = fileFilter;
-		this.log = log;
-	}
-
-	/**
-	 * Create an IBundleCoverage for the given ExecutionDataStore.
-	 * 
-	 * @param executionDataStore
-	 *            the execution data.
-	 * @return the coverage data.
-	 * @throws IOException
-	 *             if class files can't be read
-	 */
-	public IBundleCoverage createBundle(
-			final ExecutionDataStore executionDataStore) throws IOException {
-		final CoverageBuilder builder = new CoverageBuilder();
-		final Analyzer analyzer = new Analyzer(executionDataStore, builder);
-		final File classesDir = new File(this.project.getBuild()
-				.getOutputDirectory());
-
-		@SuppressWarnings("unchecked")
-		final List<File> filesToAnalyze = FileUtils.getFiles(classesDir,
-				fileFilter.getIncludes(), fileFilter.getExcludes());
-
-		for (final File file : filesToAnalyze) {
-			analyzer.analyzeAll(file);
-		}
-
-		final IBundleCoverage bundle = builder
-				.getBundle(this.project.getName());
-		logBundleInfo(bundle, builder.getNoMatchClasses());
-
-		return bundle;
-	}
-
-	private void logBundleInfo(final IBundleCoverage bundle,
-			final Collection<IClassCoverage> nomatch) {
-		log.info(format("Analyzed bundle '%s' with %s classes",
-				bundle.getName(),
-				Integer.valueOf(bundle.getClassCounter().getTotalCount())));
-		if (!nomatch.isEmpty()) {
-			log.warn(format(
-					"Classes in bundle '%s' do no match with execution data. "
-							+ "For report generation the same class files must be used as at runtime.",
-					bundle.getName()));
-			for (final IClassCoverage c : nomatch) {
-				log.warn(format("Execution data for class %s does not match.",
-						c.getName()));
-			}
-		}
-	}
-
-}
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java
index 10ec9eb..b61acee 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java
@@ -19,15 +19,11 @@
 import java.util.List;
 
 import org.apache.maven.plugin.MojoExecutionException;
-import org.jacoco.core.analysis.IBundleCoverage;
 import org.jacoco.core.analysis.ICoverageNode;
-import org.jacoco.core.data.ExecutionDataStore;
-import org.jacoco.core.tools.ExecFileLoader;
 import org.jacoco.report.IReportVisitor;
 import org.jacoco.report.check.IViolationsOutput;
 import org.jacoco.report.check.Limit;
 import org.jacoco.report.check.Rule;
-import org.jacoco.report.check.RulesChecker;
 
 /**
  * Checks that the code coverage metrics are being met.
@@ -170,19 +166,22 @@
 	}
 
 	private void executeCheck() throws MojoExecutionException {
-		final IBundleCoverage bundle = loadBundle();
 		violations = false;
 
-		final RulesChecker checker = new RulesChecker();
+		final ReportSupport support = new ReportSupport(getLog());
+
 		final List<Rule> checkerrules = new ArrayList<Rule>();
 		for (final RuleConfiguration r : rules) {
 			checkerrules.add(r.rule);
 		}
-		checker.setRules(checkerrules);
+		support.addRulesChecker(checkerrules, this);
 
-		final IReportVisitor visitor = checker.createVisitor(this);
 		try {
-			visitor.visitBundle(bundle, null);
+			final IReportVisitor visitor = support.initRootVisitor();
+			support.loadExecutionData(dataFile);
+			support.processProject(visitor, getProject(), this.getIncludes(),
+					this.getExcludes());
+			visitor.visitEnd();
 		} catch (final IOException e) {
 			throw new MojoExecutionException(
 					"Error while checking code coverage: " + e.getMessage(), e);
@@ -198,26 +197,6 @@
 		}
 	}
 
-	private IBundleCoverage loadBundle() throws MojoExecutionException {
-		final FileFilter fileFilter = new FileFilter(this.getIncludes(),
-				this.getExcludes());
-		final BundleCreator creator = new BundleCreator(getProject(),
-				fileFilter, getLog());
-		try {
-			final ExecutionDataStore executionData = loadExecutionData();
-			return creator.createBundle(executionData);
-		} catch (final IOException e) {
-			throw new MojoExecutionException(
-					"Error while reading code coverage: " + e.getMessage(), e);
-		}
-	}
-
-	private ExecutionDataStore loadExecutionData() throws IOException {
-		final ExecFileLoader loader = new ExecFileLoader();
-		loader.load(dataFile);
-		return loader.getExecutionDataStore();
-	}
-
 	public void onViolation(final ICoverageNode node, final Rule rule,
 			final Limit limit, final String message) {
 		this.getLog().warn(message);
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java b/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java
index d4be742..3da4941 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java
@@ -45,7 +45,7 @@
 	}
 
 	/**
-	 * Returns a list of files.
+	 * Returns a list of file names.
 	 * 
 	 * @param directory
 	 *            the directory to scan
@@ -60,6 +60,20 @@
 	}
 
 	/**
+	 * Returns a list of files.
+	 * 
+	 * @param directory
+	 *            the directory to scan
+	 * @return a list of files
+	 * @throws IOException
+	 *             if file system access fails
+	 */
+	@SuppressWarnings("unchecked")
+	public List<File> getFiles(final File directory) throws IOException {
+		return FileUtils.getFiles(directory, getIncludes(), getExcludes());
+	}
+
+	/**
 	 * Get the includes pattern
 	 * 
 	 * @return the pattern
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java
new file mode 100644
index 0000000..e808769
--- /dev/null
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    John Oliver, Marc R. Hoffmann, Jan Wloka - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.maven;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.jacoco.report.IReportGroupVisitor;
+
+/**
+ * <p>
+ * Creates a structured code coverage report (HTML, XML, and CSV) from multiple
+ * projects within reactor. The report is created from all modules this project
+ * depends on. From those projects class and source files as well as JaCoCo
+ * execution data files will be collected. This also allows to create coverage
+ * reports when tests are in separate projects than the code under test, for
+ * example in case of integration tests.
+ * </p>
+ * 
+ * <p>
+ * Using the dependency scope allows to distinguish projects which contribute
+ * execution data but should not be part of the report itself:
+ * </p>
+ * 
+ * <ul>
+ * <li><code>compile</code>: Project source and execution data is included in
+ * the report.</li>
+ * <li><code>test</code>: Only execution data is considered for the report.</li>
+ * </ul>
+ * 
+ * @goal report-aggregate
+ * @requiresProject true
+ * @threadSafe
+ * @since 0.7.7
+ */
+public class ReportAggregateMojo extends AbstractReportMojo {
+
+	/**
+	 * A list of execution data files to include in the report from each
+	 * project. May use wildcard characters (* and ?). When not specified all
+	 * *.exec files from the target folder will be included.
+	 * 
+	 * @parameter default-value="target/*.exec"
+	 */
+	List<String> dataFileIncludes;
+
+	/**
+	 * A list of execution data files to exclude from the report. May use
+	 * wildcard characters (* and ?). When not specified nothing will be
+	 * excluded.
+	 * 
+	 * @parameter
+	 */
+	List<String> dataFileExcludes;
+
+	/**
+	 * Output directory for the reports. Note that this parameter is only
+	 * relevant if the goal is run from the command line or from the default
+	 * build lifecycle. If the goal is run indirectly as part of a site
+	 * generation, the output directory configured in the Maven Site Plugin is
+	 * used instead.
+	 * 
+	 * @parameter 
+	 *            default-value="${project.reporting.outputDirectory}/jacoco-aggregate"
+	 */
+	private File outputDirectory;
+
+	/**
+	 * The projects in the reactor.
+	 * 
+	 * @parameter property="reactorProjects"
+	 * @readonly
+	 */
+	private List<MavenProject> reactorProjects;
+
+	@Override
+	boolean canGenerateReportRegardingDataFiles() {
+		return true;
+	}
+
+	@Override
+	boolean canGenerateReportRegardingClassesDirectory() {
+		return true;
+	}
+
+	@Override
+	void loadExecutionData(final ReportSupport support) throws IOException {
+		final FileFilter filter = new FileFilter(dataFileIncludes,
+				dataFileExcludes);
+		for (final MavenProject dependency : findDependencies(
+				Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST)) {
+			for (final File execFile : filter.getFiles(dependency.getBasedir())) {
+				support.loadExecutionData(execFile);
+			}
+		}
+	}
+
+	@Override
+	void addFormatters(final ReportSupport support, final Locale locale)
+			throws IOException {
+		support.addAllFormatters(outputDirectory, outputEncoding, footer,
+				locale);
+	}
+
+	@Override
+	void createReport(final IReportGroupVisitor visitor,
+			final ReportSupport support) throws IOException {
+		final IReportGroupVisitor group = visitor.visitGroup(title);
+		for (final MavenProject dependency : findDependencies(Artifact.SCOPE_COMPILE)) {
+			support.processProject(group, dependency.getArtifactId(),
+					dependency, getIncludes(), getExcludes(), sourceEncoding);
+		}
+	}
+
+	@Override
+	protected String getOutputDirectory() {
+		return outputDirectory.getAbsolutePath();
+	}
+
+	@Override
+	public void setReportOutputDirectory(final File reportOutputDirectory) {
+		if (reportOutputDirectory != null
+				&& !reportOutputDirectory.getAbsolutePath().endsWith(
+						"jacoco-aggregate")) {
+			outputDirectory = new File(reportOutputDirectory,
+					"jacoco-aggregate");
+		} else {
+			outputDirectory = reportOutputDirectory;
+		}
+	}
+
+	public String getOutputName() {
+		return "jacoco-aggregate/index";
+	}
+
+	public String getName(final Locale locale) {
+		return "JaCoCo Aggregate";
+	}
+
+	private List<MavenProject> findDependencies(final String... scopes) {
+		final List<MavenProject> result = new ArrayList<MavenProject>();
+		final List<String> scopeList = Arrays.asList(scopes);
+		for (final Object dependencyObject : getProject().getDependencies()) {
+			final Dependency dependency = (Dependency) dependencyObject;
+			if (scopeList.contains(dependency.getScope())) {
+				final MavenProject project = findProjectFromReactor(dependency);
+				if (project != null) {
+					result.add(project);
+				}
+			}
+		}
+		return result;
+	}
+
+	private MavenProject findProjectFromReactor(final Dependency d) {
+		for (final MavenProject p : reactorProjects) {
+			if (p.getGroupId().equals(d.getGroupId())
+					&& p.getArtifactId().equals(d.getArtifactId())
+					&& p.getVersion().equals(d.getVersion())) {
+				return p;
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java
index 9d8ef27..e0b0217 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java
@@ -13,8 +13,11 @@
 package org.jacoco.maven;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Locale;
 
+import org.jacoco.report.IReportGroupVisitor;
+
 /**
  * Same as <code>report</code>, but provides default values suitable for
  * integration-tests:
@@ -50,6 +53,35 @@
 	private File dataFile;
 
 	@Override
+	boolean canGenerateReportRegardingDataFiles() {
+		return dataFile.exists();
+	}
+
+	@Override
+	boolean canGenerateReportRegardingClassesDirectory() {
+		return new File(getProject().getBuild().getOutputDirectory()).exists();
+	}
+
+	@Override
+	void loadExecutionData(final ReportSupport support) throws IOException {
+		support.loadExecutionData(dataFile);
+	}
+
+	@Override
+	void addFormatters(final ReportSupport support, final Locale locale)
+			throws IOException {
+		support.addAllFormatters(outputDirectory, outputEncoding, footer,
+				locale);
+	}
+
+	@Override
+	void createReport(final IReportGroupVisitor visitor,
+			final ReportSupport support) throws IOException {
+		support.processProject(visitor, title, getProject(), getIncludes(),
+				getExcludes(), sourceEncoding);
+	}
+
+	@Override
 	protected String getOutputDirectory() {
 		return outputDirectory.getAbsolutePath();
 	}
@@ -65,22 +97,10 @@
 		}
 	}
 
-	@Override
-	File getDataFile() {
-		return dataFile;
-	}
-
-	@Override
-	File getOutputDirectoryFile() {
-		return outputDirectory;
-	}
-
-	@Override
 	public String getOutputName() {
 		return "jacoco-it/index";
 	}
 
-	@Override
 	public String getName(final Locale locale) {
 		return "JaCoCo IT";
 	}
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java
index f6abdaf..23c80e4 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java
@@ -12,8 +12,11 @@
 package org.jacoco.maven;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Locale;
 
+import org.jacoco.report.IReportGroupVisitor;
+
 /**
  * Creates a code coverage report for tests of a single project in multiple
  * formats (HTML, XML, and CSV).
@@ -45,6 +48,35 @@
 	private File dataFile;
 
 	@Override
+	boolean canGenerateReportRegardingDataFiles() {
+		return dataFile.exists();
+	}
+
+	@Override
+	boolean canGenerateReportRegardingClassesDirectory() {
+		return new File(getProject().getBuild().getOutputDirectory()).exists();
+	}
+
+	@Override
+	void loadExecutionData(final ReportSupport support) throws IOException {
+		support.loadExecutionData(dataFile);
+	}
+
+	@Override
+	void addFormatters(final ReportSupport support, final Locale locale)
+			throws IOException {
+		support.addAllFormatters(outputDirectory, outputEncoding, footer,
+				locale);
+	}
+
+	@Override
+	void createReport(final IReportGroupVisitor visitor,
+			final ReportSupport support) throws IOException {
+		support.processProject(visitor, title, getProject(), getIncludes(),
+				getExcludes(), sourceEncoding);
+	}
+
+	@Override
 	protected String getOutputDirectory() {
 		return outputDirectory.getAbsolutePath();
 	}
@@ -59,23 +91,11 @@
 		}
 	}
 
-	@Override
-	File getDataFile() {
-		return dataFile;
-	}
-
-	@Override
-	File getOutputDirectoryFile() {
-		return outputDirectory;
-	}
-
-	@Override
 	public String getOutputName() {
 		return "jacoco/index";
 	}
 
-	@Override
 	public String getName(final Locale locale) {
-		return "JaCoCo Test";
+		return "JaCoCo";
 	}
 }
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java
new file mode 100644
index 0000000..6281977
--- /dev/null
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java
@@ -0,0 +1,294 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Evgeny Mandrikov - initial API and implementation
+ *    Kyle Lieber - implementation of CheckMojo
+ *
+ *******************************************************************************/
+package org.jacoco.maven;
+
+import static java.lang.String.format;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.jacoco.core.analysis.Analyzer;
+import org.jacoco.core.analysis.CoverageBuilder;
+import org.jacoco.core.analysis.IBundleCoverage;
+import org.jacoco.core.analysis.IClassCoverage;
+import org.jacoco.core.tools.ExecFileLoader;
+import org.jacoco.report.FileMultiReportOutput;
+import org.jacoco.report.IReportGroupVisitor;
+import org.jacoco.report.IReportVisitor;
+import org.jacoco.report.ISourceFileLocator;
+import org.jacoco.report.MultiReportVisitor;
+import org.jacoco.report.check.IViolationsOutput;
+import org.jacoco.report.check.Rule;
+import org.jacoco.report.check.RulesChecker;
+import org.jacoco.report.csv.CSVFormatter;
+import org.jacoco.report.html.HTMLFormatter;
+import org.jacoco.report.xml.XMLFormatter;
+
+/**
+ * Encapsulates the tasks to create reports for Maven projects. Instances are
+ * supposed to be used in the following sequence:
+ * 
+ * <ol>
+ * <li>Create an instance</li>
+ * <li>Load one or multiple exec files with <code>loadExecutionData()</code></li>
+ * <li>Add one ore multiple formatters with <code>addXXX()</code> methods</li>
+ * <li>Create the root visitor with <code>initRootVisitor()</code></li>
+ * <li>Process one or multiple projects with <code>processProject()</code></li>
+ * </ol>
+ */
+final class ReportSupport {
+
+	private final Log log;
+	private final ExecFileLoader loader;
+	private final List<IReportVisitor> formatters;
+
+	/**
+	 * Construct a new instance with the given log output.
+	 * 
+	 * @param log
+	 *            for log output
+	 */
+	public ReportSupport(final Log log) {
+		this.log = log;
+		this.loader = new ExecFileLoader();
+		this.formatters = new ArrayList<IReportVisitor>();
+	}
+
+	/**
+	 * Loads the given execution data file.
+	 * 
+	 * @param execFile
+	 *            execution data file to load
+	 * @throws IOException
+	 *             if the file can't be loaded
+	 */
+	public void loadExecutionData(final File execFile) throws IOException {
+		log.info("Loading execution data file " + execFile);
+		loader.load(execFile);
+	}
+
+	public void addXmlFormatter(final File targetfile, final String encoding)
+			throws IOException {
+		final XMLFormatter xml = new XMLFormatter();
+		xml.setOutputEncoding(encoding);
+		formatters.add(xml.createVisitor(new FileOutputStream(targetfile)));
+	}
+
+	public void addCsvFormatter(final File targetfile, final String encoding)
+			throws IOException {
+		final CSVFormatter csv = new CSVFormatter();
+		csv.setOutputEncoding(encoding);
+		formatters.add(csv.createVisitor(new FileOutputStream(targetfile)));
+	}
+
+	public void addHtmlFormatter(final File targetdir, final String encoding,
+			final String footer, final Locale locale) throws IOException {
+		final HTMLFormatter htmlFormatter = new HTMLFormatter();
+		htmlFormatter.setOutputEncoding(encoding);
+		htmlFormatter.setLocale(locale);
+		if (footer != null) {
+			htmlFormatter.setFooterText(footer);
+		}
+		formatters.add(htmlFormatter.createVisitor(new FileMultiReportOutput(
+				targetdir)));
+	}
+
+	public void addAllFormatters(final File targetdir, final String encoding,
+			final String footer, final Locale locale) throws IOException {
+		targetdir.mkdirs();
+		addXmlFormatter(new File(targetdir, "jacoco.xml"), encoding);
+		addCsvFormatter(new File(targetdir, "jacoco.csv"), encoding);
+		addHtmlFormatter(targetdir, encoding, footer, locale);
+	}
+
+	public void addRulesChecker(final List<Rule> rules,
+			final IViolationsOutput output) {
+		final RulesChecker checker = new RulesChecker();
+		checker.setRules(rules);
+		formatters.add(checker.createVisitor(output));
+	}
+
+	public IReportVisitor initRootVisitor() throws IOException {
+		final IReportVisitor visitor = new MultiReportVisitor(formatters);
+		visitor.visitInfo(loader.getSessionInfoStore().getInfos(), loader
+				.getExecutionDataStore().getContents());
+		return visitor;
+	}
+
+	/**
+	 * Calculates coverage for the given project and emits it to the report
+	 * group without source references
+	 * 
+	 * @param visitor
+	 *            group visitor to emit the project's coverage to
+	 * @param project
+	 *            the MavenProject
+	 * @param includes
+	 *            list of includes patterns
+	 * @param excludes
+	 *            list of excludes patterns
+	 * @throws IOException
+	 *             if class files can't be read
+	 */
+	public void processProject(final IReportGroupVisitor visitor,
+			final MavenProject project, final List<String> includes,
+			final List<String> excludes) throws IOException {
+		processProject(visitor, project.getArtifactId(), project, includes,
+				excludes, new NoSourceLocator());
+	}
+
+	/**
+	 * Calculates coverage for the given project and emits it to the report
+	 * group including source references
+	 * 
+	 * @param visitor
+	 *            group visitor to emit the project's coverage to
+	 * @param bundeName
+	 *            name for this project in the report
+	 * @param project
+	 *            the MavenProject
+	 * @param includes
+	 *            list of includes patterns
+	 * @param excludes
+	 *            list of excludes patterns
+	 * @param srcEncoding
+	 *            encoding of the source files within this project
+	 * @throws IOException
+	 *             if class files can't be read
+	 */
+	public void processProject(final IReportGroupVisitor visitor,
+			final String bundeName, final MavenProject project,
+			final List<String> includes, final List<String> excludes,
+			final String srcEncoding) throws IOException {
+		processProject(visitor, bundeName, project, includes, excludes,
+				new SourceFileCollection(project, srcEncoding));
+	}
+
+	private void processProject(final IReportGroupVisitor visitor,
+			final String bundeName, final MavenProject project,
+			final List<String> includes, final List<String> excludes,
+			final ISourceFileLocator locator) throws IOException {
+		final CoverageBuilder builder = new CoverageBuilder();
+		final File classesDir = new File(project.getBuild()
+				.getOutputDirectory());
+
+		if (classesDir.isDirectory()) {
+			final Analyzer analyzer = new Analyzer(
+					loader.getExecutionDataStore(), builder);
+			final FileFilter filter = new FileFilter(includes, excludes);
+			for (final File file : filter.getFiles(classesDir)) {
+				analyzer.analyzeAll(file);
+			}
+		}
+
+		final IBundleCoverage bundle = builder.getBundle(bundeName);
+		logBundleInfo(bundle, builder.getNoMatchClasses());
+
+		visitor.visitBundle(bundle, locator);
+	}
+
+	private void logBundleInfo(final IBundleCoverage bundle,
+			final Collection<IClassCoverage> nomatch) {
+		log.info(format("Analyzed bundle '%s' with %s classes",
+				bundle.getName(),
+				Integer.valueOf(bundle.getClassCounter().getTotalCount())));
+		if (!nomatch.isEmpty()) {
+			log.warn(format(
+					"Classes in bundle '%s' do no match with execution data. "
+							+ "For report generation the same class files must be used as at runtime.",
+					bundle.getName()));
+			for (final IClassCoverage c : nomatch) {
+				log.warn(format("Execution data for class %s does not match.",
+						c.getName()));
+			}
+		}
+		if (bundle.getClassCounter().getTotalCount() > 0
+				&& bundle.getLineCounter().getTotalCount() == 0) {
+			log.warn("To enable source code annotation class files have to be compiled with debug information.");
+		}
+	}
+
+	private class NoSourceLocator implements ISourceFileLocator {
+
+		public Reader getSourceFile(final String packageName,
+				final String fileName) {
+			return null;
+		}
+
+		public int getTabWidth() {
+			return 0;
+		}
+	}
+
+	private class SourceFileCollection implements ISourceFileLocator {
+
+		private final List<File> sourceRoots;
+		private final String encoding;
+
+		public SourceFileCollection(final MavenProject project,
+				final String encoding) {
+			this.sourceRoots = getCompileSourceRoots(project);
+			this.encoding = encoding;
+		}
+
+		public Reader getSourceFile(final String packageName,
+				final String fileName) throws IOException {
+			final String r;
+			if (packageName.length() > 0) {
+				r = packageName + '/' + fileName;
+			} else {
+				r = fileName;
+			}
+			for (final File sourceRoot : sourceRoots) {
+				final File file = new File(sourceRoot, r);
+				if (file.exists() && file.isFile()) {
+					return new InputStreamReader(new FileInputStream(file),
+							encoding);
+				}
+			}
+			return null;
+		}
+
+		public int getTabWidth() {
+			return 4;
+		}
+	}
+
+	private static List<File> getCompileSourceRoots(final MavenProject project) {
+		final List<File> result = new ArrayList<File>();
+		for (final Object path : project.getCompileSourceRoots()) {
+			result.add(resolvePath(project, (String) path));
+		}
+		return result;
+	}
+
+	private static File resolvePath(final MavenProject project,
+			final String path) {
+		File file = new File(path);
+		if (!file.isAbsolute()) {
+			file = new File(project.getBasedir(), path);
+		}
+		return file;
+	}
+
+}
diff --git a/jacoco/assembly.xml b/jacoco/assembly.xml
index 4d662c9..4cebdd6 100644
--- a/jacoco/assembly.xml
+++ b/jacoco/assembly.xml
@@ -40,7 +40,7 @@
       </excludes>
     </fileSet>
     <fileSet>
-      <directory>${basedir}/../org.jacoco.doc/target/coverage</directory>
+      <directory>${basedir}/../org.jacoco.tests.coverage/target/site/jacoco-aggregate</directory>
       <outputDirectory>/coverage</outputDirectory>
     </fileSet>
     <fileSet>
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 1aaa431..031750d 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -20,6 +20,15 @@
 
 <h2>Snapshot Build @qualified.bundle.version@ (@build.date@)</h2>
 
+<h3>New Features</h3>
+<ul>
+  <li>New Maven goal <code>report-aggregate</code> to create reports for
+      multi-module projects
+      (GitHub <a href="https://github.com/jacoco/jacoco/issues/388">#388</a>).</li>
+  <li>New parameters <code>title</code> and <code>footer</code> for Maven
+      reporting goals allow customization of generated reports.</li>
+</ul>
+
 <h3>Fixed Bugs</h3>
 <ul>
   <li>Don't suppress EOF errors in case of truncated execution data files
diff --git a/org.jacoco.doc/docroot/doc/maven.html b/org.jacoco.doc/docroot/doc/maven.html
index 8e786c5..52fee00 100644
--- a/org.jacoco.doc/docroot/doc/maven.html
+++ b/org.jacoco.doc/docroot/doc/maven.html
@@ -116,6 +116,7 @@
   <li><a href="merge-mojo.html">merge</a></li>
   <li><a href="report-mojo.html">report</a></li>
   <li><a href="report-integration-mojo.html">report-integration</a></li>
+  <li><a href="report-aggregate-mojo.html">report-aggregate</a></li>
   <li><a href="check-mojo.html">check</a></li>
   <li><a href="dump-mojo.html">dump</a></li>
   <li><a href="instrument-mojo.html">instrument</a></li>
diff --git a/org.jacoco.doc/pom.xml b/org.jacoco.doc/pom.xml
index aaf7522..1405a4d 100644
--- a/org.jacoco.doc/pom.xml
+++ b/org.jacoco.doc/pom.xml
@@ -85,84 +85,6 @@
             </goals>
             <configuration>
               <target>
-                <typedef resource="org/jacoco/ant/antlib.xml"/>
-                <echo message="Coverage report"/>
-                <report>
-                  <executiondata>
-                    <fileset dir="../org.jacoco.agent.test/target" includes="jacoco.exec"/>
-                    <fileset dir="../org.jacoco.agent.rt.test/target" includes="jacoco.exec"/>
-                    <fileset dir="../org.jacoco.ant.test/target" includes="jacoco.exec"/>
-                    <fileset dir="../org.jacoco.core.test/target" includes="jacoco.exec"/>
-                    <fileset dir="../org.jacoco.examples.test/target" includes="jacoco.exec"/>
-                    <fileset dir="../org.jacoco.report.test/target" includes="jacoco.exec"/>
-                    <fileset dir="../jacoco-maven-plugin.test/target" includes="jacoco.exec"/>
-                  </executiondata>
-                  <structure name="JaCoCo">
-                    <group name="org.jacoco.agent">
-                      <classfiles>
-                        <!-- Process class files only, ignore jacocoagent.jar -->
-                        <fileset dir="../org.jacoco.agent/target/classes" includes="**/*.class"/>
-                      </classfiles>
-                      <sourcefiles>
-                        <fileset dir="../org.jacoco.agent/src"/>
-                      </sourcefiles>
-                    </group>
-                    <group name="org.jacoco.agent.rt">
-                      <classfiles>
-                        <fileset dir="../org.jacoco.agent.rt/target/classes"/>
-                      </classfiles>
-                      <sourcefiles>
-                        <fileset dir="../org.jacoco.agent.rt/src"/>
-                      </sourcefiles>
-                    </group>
-                    <group name="org.jacoco.ant">
-                      <classfiles>
-                        <fileset dir="../org.jacoco.ant/target/classes"/>
-                      </classfiles>
-                      <sourcefiles>
-                        <fileset dir="../org.jacoco.ant/src"/>
-                      </sourcefiles>
-                    </group>
-                    <group name="org.jacoco.core">
-                      <classfiles>
-                        <fileset dir="../org.jacoco.core/target/classes"/>
-                      </classfiles>
-                      <sourcefiles>
-                        <fileset dir="../org.jacoco.core/src"/>
-                      </sourcefiles>
-                    </group>
-                    <group name="org.jacoco.examples">
-                      <classfiles>
-                        <fileset dir="../org.jacoco.examples/target/classes"/>
-                      </classfiles>
-                      <sourcefiles>
-                        <fileset dir="../org.jacoco.examples/src"/>
-                      </sourcefiles>
-                    </group>
-                    <group name="org.jacoco.report">
-                      <classfiles>
-                        <fileset dir="../org.jacoco.report/target/classes"/>
-                      </classfiles>
-                      <sourcefiles>
-                        <fileset dir="../org.jacoco.report/src"/>
-                      </sourcefiles>
-                    </group>
-                    <group name="jacoco-maven-plugin">
-                      <classfiles>
-                        <fileset dir="../jacoco-maven-plugin/target/classes" excludes="**/HelpMojo.class"/>
-                      </classfiles>
-                      <sourcefiles>
-                        <fileset dir="../jacoco-maven-plugin/src"/>
-                      </sourcefiles>
-                    </group>
-                  </structure>
-                  <html destdir="${project.build.directory}/coverage"
-                        footer="Code Coverage Report for JaCoCo ${project.version}"
-                        locale="en"/>
-                  <csv destfile="${project.build.directory}/coverage/coverage.csv"/>
-                  <xml destfile="${project.build.directory}/coverage/coverage.xml"/>
-                </report>
-
                 <echo message="JUnit report"/>
                 <mkdir dir="${project.build.directory}/junit"/>
                 <junitreport todir="${project.build.directory}/junit">
@@ -185,11 +107,6 @@
         </executions>
         <dependencies>
           <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>org.jacoco.ant</artifactId>
-            <version>${project.version}</version>
-          </dependency>
-          <dependency>
             <groupId>org.apache.ant</groupId>
             <artifactId>ant-junit</artifactId>
             <version>1.8.2</version>
diff --git a/org.jacoco.tests.coverage/.gitignore b/org.jacoco.tests.coverage/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/org.jacoco.tests.coverage/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/org.jacoco.tests.coverage/.project b/org.jacoco.tests.coverage/.project
new file mode 100644
index 0000000..a1bcc18
--- /dev/null
+++ b/org.jacoco.tests.coverage/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.jacoco.tests.coverage</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.jacoco.tests.coverage/META-INF/MANIFEST.MF b/org.jacoco.tests.coverage/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..075c5d1
--- /dev/null
+++ b/org.jacoco.tests.coverage/META-INF/MANIFEST.MF
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0

+Bundle-ManifestVersion: 2

+Bundle-Name: JaCoCo Coverage Report

+Bundle-SymbolicName: org.jacoco.tests.coverage

+Bundle-Version: 0.7.7.qualifier

+Bundle-Vendor: Mountainminds GmbH & Co. KG

diff --git a/org.jacoco.tests.coverage/build.properties b/org.jacoco.tests.coverage/build.properties
new file mode 100644
index 0000000..5f22cdd
--- /dev/null
+++ b/org.jacoco.tests.coverage/build.properties
@@ -0,0 +1 @@
+bin.includes = META-INF/
diff --git a/org.jacoco.tests.coverage/pom.xml b/org.jacoco.tests.coverage/pom.xml
new file mode 100644
index 0000000..94c9a24
--- /dev/null
+++ b/org.jacoco.tests.coverage/pom.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors
+   All rights reserved. This program and the accompanying materials
+   are made available under the terms of the Eclipse Public License v1.0
+   which accompanies this distribution, and is available at
+   http://www.eclipse.org/legal/epl-v10.html
+
+   Contributors:
+      Evgeny Mandrikov - initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.jacoco</groupId>
+    <artifactId>org.jacoco.tests</artifactId>
+    <version>0.7.7-SNAPSHOT</version>
+    <relativePath>../org.jacoco.tests</relativePath>
+  </parent>
+
+  <artifactId>org.jacoco.tests.coverage</artifactId>
+  <packaging>pom</packaging>
+
+  <name>JaCoCo :: Coverage Report</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.core.test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.report</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.report.test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.agent</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.agent.test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.agent.rt</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.agent.rt.test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.ant</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.ant.test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>jacoco-maven-plugin</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>jacoco-maven-plugin.test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.examples</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>org.jacoco.examples.test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <properties>
+    <maven.deploy.skip>true</maven.deploy.skip>
+    <!-- Analyze class files only to exclude shaded agent JAR from report -->
+    <jacoco.includes>**/*.class</jacoco.includes>
+    <jacoco.excludes>**/HelpMojo.class</jacoco.excludes>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <version>${project.version}</version>
+        <executions>
+          <execution>
+            <id>report-aggregate</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>report-aggregate</goal>
+            </goals>
+            <configuration>
+              <title>JaCoCo</title>
+              <footer>Code Coverage Report for JaCoCo ${project.version}</footer>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml
index eb8bf87..aecd0aa 100644
--- a/org.jacoco.tests/pom.xml
+++ b/org.jacoco.tests/pom.xml
@@ -33,6 +33,7 @@
     <module>../org.jacoco.ant.test</module>
     <module>../jacoco-maven-plugin.test</module>
     <module>../org.jacoco.examples.test</module>
+    <module>../org.jacoco.tests.coverage</module>
   </modules>
 
   <properties>