Merge pull request #39 from jacoco/topic/shadeantasm

Move ASM classes to org.jacoco namespace for jacocoant.jar
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-hault/invoker.properties b/jacoco-maven-plugin.test/it/it-check-fails-hault/invoker.properties
new file mode 100644
index 0000000..324b5fb
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-hault/invoker.properties
@@ -0,0 +1 @@
+invoker.buildResult=failure
\ No newline at end of file
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-hault/pom.xml b/jacoco-maven-plugin.test/it/it-check-fails-hault/pom.xml
new file mode 100644
index 0000000..6a98764
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-hault/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2012 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
+-->
+<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>setup-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>it-check-fails-hault</artifactId>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>@project.groupId@</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>check</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <configuration>
+              <check>
+                <classRatio>100</classRatio>
+                <instructionRatio>100</instructionRatio>
+                <methodRatio>100</methodRatio>
+                <branchRatio>100</branchRatio>
+                <complexityRatio>100</complexityRatio>
+                <lineRatio>100</lineRatio>
+              </check>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-hault/src/main/java/Example.java b/jacoco-maven-plugin.test/it/it-check-fails-hault/src/main/java/Example.java
new file mode 100644
index 0000000..0965a90
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-hault/src/main/java/Example.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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
+ *
+ *******************************************************************************/
+public class Example {
+
+  public void sayHello() {
+    System.out.println("Hello world");
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-hault/src/test/java/ExampleTest.java b/jacoco-maven-plugin.test/it/it-check-fails-hault/src/test/java/ExampleTest.java
new file mode 100644
index 0000000..81bd55b
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-hault/src/test/java/ExampleTest.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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
+ *
+ *******************************************************************************/
+import org.junit.Test;
+
+public class ExampleTest {
+
+  @Test
+  public void test() {
+    new Example();
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-hault/verify.bsh b/jacoco-maven-plugin.test/it/it-check-fails-hault/verify.bsh
new file mode 100644
index 0000000..de91b45
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-hault/verify.bsh
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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 
+ *
+ *******************************************************************************/
+import java.io.*;
+import org.codehaus.plexus.util.*;
+
+String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) );
+if ( buildLog.indexOf( "Coverage checks have not been met." ) < 0 ) {
+    throw new RuntimeException( "Coverage checks should not have been met." );
+}
+
+if ( buildLog.indexOf( "Insufficient code coverage for" ) < 0 ) {
+    throw new RuntimeException( "Should have displayed insufficient code coverage messages." );
+}
+
+if ( buildLog.indexOf( "BUILD FAILURE" ) < 0 ) {
+    throw new RuntimeException( "Build failed but it should have succeeded." );
+}
+
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-no-hault/pom.xml b/jacoco-maven-plugin.test/it/it-check-fails-no-hault/pom.xml
new file mode 100644
index 0000000..3e0ddb7
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-no-hault/pom.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2012 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
+-->
+<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>setup-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>it-check-fails-no-hault</artifactId>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>@project.groupId@</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>check</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <configuration>
+              <haltOnFailure>false</haltOnFailure>
+              <check>
+                <classRatio>100</classRatio>
+                <instructionRatio>100</instructionRatio>
+                <methodRatio>100</methodRatio>
+                <branchRatio>100</branchRatio>
+                <complexityRatio>100</complexityRatio>
+                <lineRatio>100</lineRatio>
+              </check>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-no-hault/src/main/java/Example.java b/jacoco-maven-plugin.test/it/it-check-fails-no-hault/src/main/java/Example.java
new file mode 100644
index 0000000..0965a90
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-no-hault/src/main/java/Example.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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
+ *
+ *******************************************************************************/
+public class Example {
+
+  public void sayHello() {
+    System.out.println("Hello world");
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-no-hault/src/test/java/ExampleTest.java b/jacoco-maven-plugin.test/it/it-check-fails-no-hault/src/test/java/ExampleTest.java
new file mode 100644
index 0000000..81bd55b
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-no-hault/src/test/java/ExampleTest.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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
+ *
+ *******************************************************************************/
+import org.junit.Test;
+
+public class ExampleTest {
+
+  @Test
+  public void test() {
+    new Example();
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-check-fails-no-hault/verify.bsh b/jacoco-maven-plugin.test/it/it-check-fails-no-hault/verify.bsh
new file mode 100644
index 0000000..5cd4df2
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-fails-no-hault/verify.bsh
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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
+ *
+ *******************************************************************************/
+import java.io.*;
+import org.codehaus.plexus.util.*;
+
+String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) );
+if ( buildLog.indexOf( "Coverage checks have not been met." ) < 0 ) {
+    throw new RuntimeException( "Coverage checks should not have been met." );
+}
+
+if ( buildLog.indexOf( "Insufficient code coverage for" ) < 0 ) {
+    throw new RuntimeException( "Should have displayed insufficient code coverage messages." );
+}
+
+if ( buildLog.indexOf( "BUILD SUCCESS" ) < 0 ) {
+    throw new RuntimeException( "Build failed but it should have succeeded." );
+}
+
diff --git a/jacoco-maven-plugin.test/it/it-check-passes/pom.xml b/jacoco-maven-plugin.test/it/it-check-passes/pom.xml
new file mode 100644
index 0000000..969bc9f
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-passes/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright (c) 2009, 2012 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
+-->
+<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>setup-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>it-check-passes</artifactId>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>@project.groupId@</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>check</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <configuration>
+              <check>
+                <classRatio>100</classRatio>
+                <instructionRatio>100</instructionRatio>
+                <methodRatio>100</methodRatio>
+                <branchRatio>100</branchRatio>
+                <complexityRatio>100</complexityRatio>
+                <lineRatio>100</lineRatio>
+              </check>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/jacoco-maven-plugin.test/it/it-check-passes/src/main/java/Example.java b/jacoco-maven-plugin.test/it/it-check-passes/src/main/java/Example.java
new file mode 100644
index 0000000..0965a90
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-passes/src/main/java/Example.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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
+ *
+ *******************************************************************************/
+public class Example {
+
+  public void sayHello() {
+    System.out.println("Hello world");
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-check-passes/src/test/java/ExampleTest.java b/jacoco-maven-plugin.test/it/it-check-passes/src/test/java/ExampleTest.java
new file mode 100644
index 0000000..bf300c1
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-passes/src/test/java/ExampleTest.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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
+ *
+ *******************************************************************************/
+import org.junit.Test;
+
+public class ExampleTest {
+
+  @Test
+  public void test() {
+    new Example().sayHello();
+  }
+
+}
diff --git a/jacoco-maven-plugin.test/it/it-check-passes/verify.bsh b/jacoco-maven-plugin.test/it/it-check-passes/verify.bsh
new file mode 100644
index 0000000..c9c840f
--- /dev/null
+++ b/jacoco-maven-plugin.test/it/it-check-passes/verify.bsh
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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
+ *
+ *******************************************************************************/
+import java.io.*;
+import org.codehaus.plexus.util.*;
+
+String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) );
+if ( buildLog.indexOf( "All coverage checks have been met." ) < 0 ) {
+    throw new RuntimeException( "Coverage checks were not met." );
+}
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java
index 78d22fa..665ad36 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java
@@ -14,6 +14,8 @@
 import java.util.List;
 
 import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
 
 /**
@@ -54,7 +56,8 @@
 	 */
 	private boolean skip;
 
-	public final void execute() {
+	public final void execute() throws MojoExecutionException,
+			MojoFailureException {
 		if ("pom".equals(project.getPackaging())) {
 			getLog().info(
 					"Skipping JaCoCo for project with packaging type 'pom'");
@@ -69,8 +72,17 @@
 
 	/**
 	 * Executes Mojo.
+	 * 
+	 * @throws MojoExecutionException
+	 *             if an unexpected problem occurs. Throwing this exception
+	 *             causes a "BUILD ERROR" message to be displayed.
+	 * @throws MojoFailureException
+	 *             if an expected problem (such as a compilation failure)
+	 *             occurs. Throwing this exception causes a "BUILD FAILURE"
+	 *             message to be displayed.
 	 */
-	protected abstract void executeMojo();
+	protected abstract void executeMojo() throws MojoExecutionException,
+			MojoFailureException;
 
 	/**
 	 * @return Maven project
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java b/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java
new file mode 100644
index 0000000..79ccd9f
--- /dev/null
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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 java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+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.data.ExecutionDataStore;
+
+/**
+ * Creates an IBundleCoverage.
+ */
+public final class BundleCreator {
+
+	private final MavenProject project;
+	private final FileFilter fileFilter;
+
+	/**
+	 * Construct a new BundleCreator given the MavenProject and FileFilter.
+	 * 
+	 * @param project
+	 *            the MavenProject
+	 * @param fileFilter
+	 *            the FileFilter
+	 */
+	public BundleCreator(final MavenProject project, final FileFilter fileFilter) {
+		this.project = project;
+		this.fileFilter = fileFilter;
+	}
+
+	/**
+	 * Create an IBundleCoverage for the given ExecutionDataStore.
+	 * 
+	 * @param executionDataStore
+	 *            the execution data.
+	 * @return the coverage data.
+	 * @throws IOException
+	 */
+	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);
+		}
+
+		return builder.getBundle(this.project.getName());
+	}
+}
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/CheckConfiguration.java b/jacoco-maven-plugin/src/org/jacoco/maven/CheckConfiguration.java
new file mode 100644
index 0000000..16b487a
--- /dev/null
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/CheckConfiguration.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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 java.util.HashMap;
+import java.util.Map;
+
+import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
+
+/**
+ * Used in the configuration of the "check" goal for specifying minimum ratios
+ * of coverage.
+ */
+public class CheckConfiguration {
+
+	private static final double DEFAULT_RATIO = 0;
+
+	private final Map<CounterEntity, Double> configuration;
+
+	/**
+	 * Construct a new CheckConfiguration instance.
+	 */
+	public CheckConfiguration() {
+		this.configuration = new HashMap<CounterEntity, Double>();
+	}
+
+	/**
+	 * Set the minimum allowed code coverage for instructions.
+	 * 
+	 * @param ratio
+	 *            percent of instructions covered
+	 */
+	public void setInstructionRatio(final Double ratio) {
+		this.configuration.put(CounterEntity.INSTRUCTION, ratio);
+	}
+
+	/**
+	 * Set the minimum allowed code coverage for branches.
+	 * 
+	 * @param ratio
+	 *            percent of branches covered
+	 */
+	public void setBranchRatio(final Double ratio) {
+		this.configuration.put(CounterEntity.BRANCH, ratio);
+	}
+
+	/**
+	 * Set the minimum allowed code coverage for lines.
+	 * 
+	 * @param ratio
+	 *            percent of lines covered
+	 */
+	public void setLineRatio(final Double ratio) {
+		this.configuration.put(CounterEntity.LINE, ratio);
+	}
+
+	/**
+	 * Set the minimum allowed code coverage for complexity.
+	 * 
+	 * @param ratio
+	 *            percent of complexities covered
+	 */
+	public void setComplexityRatio(final Double ratio) {
+		this.configuration.put(CounterEntity.COMPLEXITY, ratio);
+	}
+
+	/**
+	 * Set the minimum allowed code coverage for methods.
+	 * 
+	 * @param ratio
+	 *            percent of methods covered
+	 */
+	public void setMethodRatio(final Double ratio) {
+		this.configuration.put(CounterEntity.METHOD, ratio);
+	}
+
+	/**
+	 * Set the minimum allowed code coverage for classes.
+	 * 
+	 * @param ratio
+	 *            percent of classes covered
+	 */
+	public void setClassRatio(final Double ratio) {
+		this.configuration.put(CounterEntity.CLASS, ratio);
+	}
+
+	/**
+	 * Get the ratio for the given CounterEntity
+	 * 
+	 * @param entity
+	 *            the counter type
+	 * @return minimum percent covered for given CounterEntity
+	 */
+	public double getRatio(final CounterEntity entity) {
+		final Double ratio = this.configuration.get(entity);
+		return ratio == null ? DEFAULT_RATIO : ratio.doubleValue();
+	}
+}
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java
new file mode 100644
index 0000000..c50eb79
--- /dev/null
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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 java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.jacoco.core.analysis.IBundleCoverage;
+import org.jacoco.core.analysis.ICounter;
+import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
+import org.jacoco.core.data.ExecutionDataReader;
+import org.jacoco.core.data.ExecutionDataStore;
+import org.jacoco.core.data.SessionInfoStore;
+
+/**
+ * Checks that the code coverage metrics are being met.
+ * 
+ * @goal check
+ * @phase verify
+ * @requiresProject true
+ * @threadSafe
+ */
+public class CheckMojo extends AbstractJacocoMojo {
+
+	private static final String MSG_SKIPPING = "Skipping JaCoCo execution due to missing execution data file";
+
+	private static final String ERROR_UNABLE_TO_READ = "Unable to read execution data file %s: %s";
+	private static final String ERROR_CHECKING_COVERAGE = "Error while checking coverage: %s";
+
+	private static final String INSUFFICIENT_COVERAGE = "Insufficient code coverage for %s: %2$.2f%% < %3$.2f%%";
+	private static final String CHECK_FAILED = "Coverage checks have not been met. See report for details.";
+	private static final String CHECK_SUCCESS = "All coverage checks have been met.";
+
+	/**
+	 * <p>
+	 * Check configuration. Used to specify minimum coverage percentages that
+	 * must be met. Defaults to 0% if a percentage ratio is not specified.
+	 * </p>
+	 * 
+	 * <p>
+	 * Example requiring 100% coverage for class, instruction, method, branch,
+	 * complexity, and line:
+	 * </p>
+	 * 
+	 * <pre>
+	 * {@code
+	 * <check>
+	 *   <classRatio>100</classRatio>
+	 *   <instructionRatio>100</instructionRatio>
+	 *   <methodRatio>100</methodRatio>
+	 *   <branchRatio>100</branchRatio>
+	 *   <complexityRatio>100</complexityRatio>
+	 *   <lineRatio>100</lineRatio>
+	 * </check>}
+	 * </pre>
+	 * 
+	 * @parameter
+	 * @required
+	 */
+	private CheckConfiguration check;
+
+	/**
+	 * Halt the build if any of the checks fail.
+	 * 
+	 * @parameter expression="${jacoco.haltOnFailure}" default-value="true"
+	 * @required
+	 */
+	private boolean haltOnFailure;
+
+	/**
+	 * File with execution data.
+	 * 
+	 * @parameter default-value="${project.build.directory}/jacoco.exec"
+	 */
+	private File dataFile;
+
+	private SessionInfoStore sessionInfoStore;
+
+	private ExecutionDataStore executionDataStore;
+
+	private boolean canCheckCoverage() {
+		if (!dataFile.exists()) {
+			getLog().info(MSG_SKIPPING);
+			return false;
+		}
+		return true;
+	}
+
+	@Override
+	public void executeMojo() throws MojoExecutionException,
+			MojoExecutionException {
+		if (!canCheckCoverage()) {
+			return;
+		}
+		executeCheck();
+	}
+
+	private void executeCheck() throws MojoExecutionException {
+		try {
+			loadExecutionData();
+		} catch (final IOException e) {
+			throw new MojoExecutionException(String.format(
+					ERROR_UNABLE_TO_READ, dataFile, e.getMessage()), e);
+		}
+		try {
+			if (check()) {
+				this.getLog().info(CHECK_SUCCESS);
+			} else {
+				this.handleFailure();
+			}
+		} catch (final IOException e) {
+			throw new MojoExecutionException(String.format(
+					ERROR_CHECKING_COVERAGE, e.getMessage()), e);
+		}
+	}
+
+	private void loadExecutionData() throws IOException {
+		sessionInfoStore = new SessionInfoStore();
+		executionDataStore = new ExecutionDataStore();
+		FileInputStream in = null;
+		try {
+			in = new FileInputStream(dataFile);
+			final ExecutionDataReader reader = new ExecutionDataReader(in);
+			reader.setSessionInfoVisitor(sessionInfoStore);
+			reader.setExecutionDataVisitor(executionDataStore);
+			reader.read();
+		} finally {
+			if (in != null) {
+				in.close();
+			}
+		}
+	}
+
+	private boolean check() throws IOException {
+		final FileFilter fileFilter = new FileFilter(this.getIncludes(),
+				this.getExcludes());
+		final BundleCreator creator = new BundleCreator(this.getProject(),
+				fileFilter);
+		final IBundleCoverage bundle = creator.createBundle(executionDataStore);
+
+		boolean passed = true;
+
+		for (final CounterEntity entity : CounterEntity.values()) {
+			passed = this.checkCounter(entity, bundle.getCounter(entity),
+					check.getRatio(entity))
+					&& passed;
+		}
+
+		return passed;
+	}
+
+	private boolean checkCounter(final CounterEntity entity,
+			final ICounter counter, final double checkRatio) {
+		boolean passed = true;
+
+		final double ratio = counter.getCoveredRatio() * 100;
+
+		if (ratio < checkRatio) {
+			this.getLog().warn(
+					String.format(INSUFFICIENT_COVERAGE, entity.name(),
+							Double.valueOf(ratio), Double.valueOf(checkRatio)));
+			passed = false;
+		}
+		return passed;
+	}
+
+	private void handleFailure() throws MojoExecutionException {
+		if (this.haltOnFailure) {
+			throw new MojoExecutionException(CHECK_FAILED);
+		} else {
+			this.getLog().warn(CHECK_FAILED);
+		}
+	}
+}
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java b/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java
new file mode 100644
index 0000000..5a215df
--- /dev/null
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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 java.util.List;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * A file filter using includes/excludes patterns.
+ */
+public class FileFilter {
+
+	private static final String DEFAULT_INCLUDES = "**";
+	private static final String DEFAULT_EXCLUDES = "";
+
+	private final List<String> includes;
+	private final List<String> excludes;
+
+	/**
+	 * Construct a new FileFilter
+	 * 
+	 * @param includes
+	 *            list of includes patterns
+	 * @param excludes
+	 *            list of excludes patterns
+	 */
+	public FileFilter(final List<String> includes, final List<String> excludes) {
+		this.includes = includes;
+		this.excludes = excludes;
+	}
+
+	/**
+	 * Get the includes pattern
+	 * 
+	 * @return the pattern
+	 */
+	public String getIncludes() {
+		return this.buildPattern(this.includes, DEFAULT_INCLUDES);
+	}
+
+	/**
+	 * Get the excludes pattern
+	 * 
+	 * @return the pattern
+	 */
+	public String getExcludes() {
+		return this.buildPattern(this.excludes, DEFAULT_EXCLUDES);
+	}
+
+	private String buildPattern(final List<String> patterns,
+			final String defaultPattern) {
+		String pattern = defaultPattern;
+		if (CollectionUtils.isNotEmpty(patterns)) {
+			pattern = StringUtils.join(patterns.iterator(), ",");
+		}
+		return pattern;
+	}
+}
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java
index 35fd7b1..62f0046 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *    Evgeny Mandrikov - initial API and implementation
+ *	  Kyle Lieber - implementation of CheckMojo
  *
  *******************************************************************************/
 package org.jacoco.maven;
@@ -26,10 +27,6 @@
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.reporting.AbstractMavenReport;
 import org.apache.maven.reporting.MavenReportException;
-import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.StringUtils;
-import org.jacoco.core.analysis.Analyzer;
-import org.jacoco.core.analysis.CoverageBuilder;
 import org.jacoco.core.analysis.IBundleCoverage;
 import org.jacoco.core.analysis.ICoverageNode;
 import org.jacoco.core.data.ExecutionDataReader;
@@ -203,7 +200,7 @@
 		}
 		if (!dataFile.exists()) {
 			getLog().info(
-				"Skipping JaCoCo execution due to missing execution data file");
+					"Skipping JaCoCo execution due to missing execution data file");
 			return false;
 		}
 		return true;
@@ -243,8 +240,8 @@
 			createReport(visitor);
 			visitor.visitEnd();
 		} catch (final Exception e) {
-			throw new MavenReportException(
-					"Error while creating report: " + e.getMessage(), e);
+			throw new MavenReportException("Error while creating report: "
+					+ e.getMessage(), e);
 		}
 	}
 
@@ -267,7 +264,12 @@
 
 	private void createReport(final IReportGroupVisitor visitor)
 			throws IOException {
-		final IBundleCoverage bundle = createBundle();
+		final FileFilter fileFilter = new FileFilter(this.getIncludes(),
+				this.getExcludes());
+		final BundleCreator creator = new BundleCreator(this.getProject(),
+				fileFilter);
+		final IBundleCoverage bundle = creator.createBundle(executionDataStore);
+
 		final SourceFileCollection locator = new SourceFileCollection(
 				getCompileSourceRoots(), sourceEncoding);
 		checkForMissingDebugInformation(bundle);
@@ -282,21 +284,6 @@
 		}
 	}
 
-	private IBundleCoverage createBundle() throws IOException {
-		final CoverageBuilder builder = new CoverageBuilder();
-		final Analyzer analyzer = new Analyzer(executionDataStore, builder);
-		final File classesDir = new File(getProject().getBuild()
-				.getOutputDirectory());
-
-		final List<File> filesToAnalyze = getFilesToAnalyze(classesDir);
-
-		for (final File file : filesToAnalyze) {
-			analyzer.analyzeAll(file);
-		}
-
-		return builder.getBundle(getProject().getName());
-	}
-
 	private IReportVisitor createVisitor() throws IOException {
 		final List<IReportVisitor> visitors = new ArrayList<IReportVisitor>();
 
@@ -371,24 +358,4 @@
 		}
 		return result;
 	}
-
-	private List<File> getFilesToAnalyze(final File rootDir) throws IOException {
-		final String includes;
-		if (getIncludes() != null && !getIncludes().isEmpty()) {
-			includes = StringUtils.join(getIncludes().iterator(), ",");
-		} else {
-			includes = "**";
-		}
-		final String excludes;
-		if (getExcludes() != null && !getExcludes().isEmpty()) {
-			excludes = StringUtils.join(getExcludes().iterator(), ",");
-		} else {
-			excludes = "";
-		}
-		@SuppressWarnings("unchecked")
-		final List<File> files = FileUtils
-				.getFiles(rootDir, includes, excludes);
-		return files;
-	}
-
 }
diff --git a/org.jacoco.ant.test/src/org/jacoco/ant/MergeTaskTest.xml b/org.jacoco.ant.test/src/org/jacoco/ant/MergeTaskTest.xml
index f7f5000..61cb7ab 100644
--- a/org.jacoco.ant.test/src/org/jacoco/ant/MergeTaskTest.xml
+++ b/org.jacoco.ant.test/src/org/jacoco/ant/MergeTaskTest.xml
@@ -52,6 +52,7 @@
 		<property name="sample2.file" location="${basedir}/data/sample2.exec"/>
 		<au:assertLogContains text="Loading execution data file ${sample1.file}"/>
 		<au:assertLogContains text="Loading execution data file ${sample2.file}"/>
+		<au:assertLogContains text="Writing merged execution data to ${exec.file}"/>
 		<au:assertFileExists file="${exec.file}"/>
 	</target>
 	
diff --git a/org.jacoco.ant/src/org/jacoco/ant/MergeTask.java b/org.jacoco.ant/src/org/jacoco/ant/MergeTask.java
index 77dea18..0d9ef39 100644
--- a/org.jacoco.ant/src/org/jacoco/ant/MergeTask.java
+++ b/org.jacoco.ant/src/org/jacoco/ant/MergeTask.java
@@ -71,28 +71,11 @@
 		final SessionInfoStore infoStore = new SessionInfoStore();
 		final ExecutionDataStore dataStore = new ExecutionDataStore();
 
-		loadSourceFiles(infoStore, dataStore);
-
-		OutputStream outputStream = null;
-		try {
-			FileUtils.getFileUtils().createNewFile(destfile, true);
-
-			outputStream = new BufferedOutputStream(new FileOutputStream(
-					destfile));
-			final ExecutionDataWriter dataWriter = new ExecutionDataWriter(
-					outputStream);
-			infoStore.accept(dataWriter);
-			dataStore.accept(dataWriter);
-		} catch (final IOException e) {
-			throw new BuildException(format("Unable to write merged file %s",
-					destfile.getAbsolutePath()), e, getLocation());
-		} finally {
-			FileUtils.close(outputStream);
-		}
-
+		load(infoStore, dataStore);
+		save(infoStore, dataStore);
 	}
 
-	private void loadSourceFiles(final SessionInfoStore infoStore,
+	private void load(final SessionInfoStore infoStore,
 			final ExecutionDataStore dataStore) {
 		final Iterator<?> resourceIterator = files.iterator();
 		while (resourceIterator.hasNext()) {
@@ -121,4 +104,26 @@
 		}
 	}
 
+	private void save(final SessionInfoStore infoStore,
+			final ExecutionDataStore dataStore) {
+		log(format("Writing merged execution data to %s",
+				destfile.getAbsolutePath()));
+		OutputStream outputStream = null;
+		try {
+			FileUtils.getFileUtils().createNewFile(destfile, true);
+
+			outputStream = new BufferedOutputStream(new FileOutputStream(
+					destfile));
+			final ExecutionDataWriter dataWriter = new ExecutionDataWriter(
+					outputStream);
+			infoStore.accept(dataWriter);
+			dataStore.accept(dataWriter);
+		} catch (final IOException e) {
+			throw new BuildException(format("Unable to write merged file %s",
+					destfile.getAbsolutePath()), e, getLocation());
+		} finally {
+			FileUtils.close(outputStream);
+		}
+	}
+
 }
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 8557fa5..241d9df 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -20,9 +20,15 @@
 
 <h2>Trunk Build @qualified.bundle.version@ (@build.date@)</h2>
 
+<h3>New Features</h3>
+<ul>
+  <li>Add a coverage check mojo (GitHub #6)</li>
+</ul>
+
 <h3>Non-functional Changes</h3>
 <ul>
-  <li>Upgrade to ASM 4.1 (GitHub #37)</li>
+  <li>Upgrade to ASM 4.1 (GitHub #37).</li>
+  <li>Log location of merged execution data file in Ant <code>merge</code> task (GitHub #29).</li>
 </ul>
 
 <h2>Release 0.6.0 (2012/10/06)</h2>
diff --git a/org.jacoco.doc/docroot/doc/maven.html b/org.jacoco.doc/docroot/doc/maven.html
index fbe8a29..2c73adc 100644
--- a/org.jacoco.doc/docroot/doc/maven.html
+++ b/org.jacoco.doc/docroot/doc/maven.html
@@ -89,6 +89,7 @@
   <li><a href="help-mojo.html">help</a></li>
   <li><a href="prepare-agent-mojo.html">prepare-agent</a></li>
   <li><a href="report-mojo.html">report</a></li>
+  <li><a href="check-mojo.html">check</a></li>
 </ul>
 
 </div>
diff --git a/org.jacoco.doc/xsl/maven-goal.xsl b/org.jacoco.doc/xsl/maven-goal.xsl
index e55caf9..2c68a5c 100644
--- a/org.jacoco.doc/xsl/maven-goal.xsl
+++ b/org.jacoco.doc/xsl/maven-goal.xsl
@@ -9,6 +9,7 @@
   
    Contributors:
       Marc R. Hoffmann - initial API and implementation
+      Kyle Lieber - implementation of CheckMojo
 -->
 
 <xsl:stylesheet version="1.0"
@@ -119,6 +120,12 @@
 			<xsl:apply-templates />
 		</code>
 	</xsl:template>
+	
+	<xsl:template match="xdoc:pre">
+		<pre>
+			<xsl:apply-templates />
+		</pre>
+	</xsl:template>
 
 	<xsl:template match="xdoc:br">
 		<br />
diff --git a/org.jacoco.examples/build/pom.xml b/org.jacoco.examples/build/pom.xml
index 0f1591b..cc04930 100644
--- a/org.jacoco.examples/build/pom.xml
+++ b/org.jacoco.examples/build/pom.xml
@@ -1,59 +1,74 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
-<!-- 
+<!--
    Copyright (c) 2009, 2012 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 - initial API and implementation
+      Kyle Lieber - implementation of CheckMojo
 -->
-
 <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>
+  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>
 
-	<groupId>org.jacoco</groupId>
-	<artifactId>org.jacoco.examples.maven</artifactId>
-	<version>@project.version@</version>
-	<packaging>jar</packaging>
+  <groupId>org.jacoco</groupId>
+  <artifactId>org.jacoco.examples.maven</artifactId>
+  <version>@project.version@</version>
+  <packaging>jar</packaging>
 
-	<name>JaCoCo Maven plug-in example</name>
-	<url>http://www.eclemma.org/jacoco</url>
+  <name>JaCoCo Maven plug-in example</name>
+  <url>http://www.eclemma.org/jacoco</url>
 
-	<dependencies>
-		<dependency>
-			<groupId>junit</groupId>
-			<artifactId>junit</artifactId>
-			<version>4.10</version>
-			<scope>test</scope>
-		</dependency>
-	</dependencies>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.10</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
 
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.jacoco</groupId>
-				<artifactId>jacoco-maven-plugin</artifactId>
-				<version>@project.version@</version>
-				<executions>
-					<execution>
-						<goals>
-							<goal>prepare-agent</goal>
-						</goals>
-					</execution>
-					<execution>
-						<id>report</id>
-						<phase>prepare-package</phase>
-						<goals>
-							<goal>report</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-	</build>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <version>@project.version@</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>check</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <configuration>
+              <check>
+                <classRatio>100</classRatio>
+                <instructionRatio>90</instructionRatio>
+                <methodRatio>95</methodRatio>
+                <branchRatio>85</branchRatio>
+                <complexityRatio>85</complexityRatio>
+                <lineRatio>90</lineRatio>
+              </check>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
 
-</project>
\ No newline at end of file
+</project>