# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with this
# work for additional information regarding copyright ownership. The ASF
# licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
module Buildr
# Provides the emma:html
and emma:xml
tasks.
# Require explicitly using require "buildr/emma"
.
#
# You can generate emma reports for a single project
# using the project name as prefix:
#
# project_name:emma:html
#
# You can also specify which classes to include/exclude from instrumentation by
# passing a class name regexp to the emma.include
or
# emma.exclude
methods.
#
# define 'someModule' do
# emma.include 'some.package.*'
# emma.exclude 'some.foo.util.SimpleUtil'
# end
module Emma
VERSION = '2.0.5312'
class << self
def version
Buildr.settings.build['emma'] || VERSION
end
def dependencies
@dependencies ||= ["emma:emma_ant:jar:#{version}", "emma:emma:jar:#{version}"]
end
def report_to format=nil
File.expand_path('reports/emma')
end
def data_file()
File.join(report_to, 'coverage.es')
end
def ant
Buildr.ant 'emma' do |ant|
ant.taskdef :resource=>'emma_ant.properties',
:classpath=>Buildr.artifacts(dependencies).each(&:invoke).map(&:to_s).join(File::PATH_SEPARATOR)
ant.emma :verbosity=>(trace?(:emma) ? 'verbose' : 'warning') do
yield ant
end
end
end
end
class EmmaConfig # :nodoc:
def initialize(project)
@project = project
end
attr_reader :project
private :project
attr_writer :metadata_file, :coverage_file, :instrumented_dir, :report_dir
def coverage_file
@coverage_file ||= File.join(report_dir, 'coverage.ec')
end
def metadata_file
@metadata_file ||= File.join(report_dir, 'coverage.em')
end
def instrumented_dir
@instrumented_dir ||= project.path_to(:target, :instrumented, :classes)
end
def report_dir
@report_dir ||= project.path_to(:reports, :emma)
end
def report_to format
report_dir
end
# :call-seq:
# project.emma.include(*classPatterns)
#
def include(*classPatterns)
includes.push(*classPatterns)
self
end
def includes
@includeClasses ||= []
end
# :call-seq:
# project.emma.exclude(*classPatterns)
#
def exclude(*classPatterns)
excludes.push(*classPatterns)
self
end
def excludes
@excludeClasses ||= []
end
def sources
project.compile.sources
end
end
module EmmaExtension # :nodoc:
include Buildr::Extension
def emma
@emma_config ||= EmmaConfig.new(self)
end
after_define do |project|
emma = project.emma
namespace 'emma' do
unless project.compile.target.nil?
# Instrumented bytecode goes in a different directory. This task creates before running the test
# cases and monitors for changes in the generate bytecode.
instrumented = project.file(emma.instrumented_dir => project.compile.target) do |task|
unless project.compile.sources.empty?
info "Instrumenting classes with emma metadata file #{emma.metadata_file}"
Emma.ant do |ant|
ant.instr :instrpath=>project.compile.target.to_s, :destdir=>task.to_s, :metadatafile=>emma.metadata_file do
ant.filter :includes=>emma.includes.join(', ') unless emma.includes.empty?
ant.filter :excludes=>emma.excludes.join(', ') unless emma.excludes.empty?
end
end
touch task.to_s
end
end
task 'instrument' => instrumented
# We now have two target directories with bytecode.
project.test.dependencies.unshift emma.instrumented_dir
project.test.with Emma.dependencies
project.test.options[:properties]["emma.coverage.out.file"] = emma.coverage_file
[:xml, :html].each do |format|
task format => ['instrument', 'test'] do
missing_required_files = [emma.metadata_file, emma.coverage_file].reject { |f| File.exist?(f) }
if missing_required_files.empty?
info "Creating test coverage reports in #{emma.report_dir}"
mkdir_p emma.report_dir
Emma.ant do |ant|
ant.report do
ant.infileset :file=>emma.metadata_file
ant.infileset :file=>emma.coverage_file
ant.send format, :outfile=>File.join(emma.report_to(format),"coverage.#{format}")
ant.sourcepath do
emma.sources.flatten.each do |src|
ant.dirset(:dir=>src.to_s) if File.exist?(src.to_s)
end
end
end
end
else
info "No test coverage report for #{project}. Missing: #{missing_required_files.join(', ')}"
end
end
end
end
end
project.clean do
rm_rf [emma.report_dir, emma.coverage_file, emma.metadata_file, emma.instrumented_dir]
end
end
end
class Buildr::Project
include EmmaExtension
end
namespace "emma" do
Project.local_task('instrument') { |name| "Instrumenting #{name}" }
[:xml, :html].each do |format|
desc "Run the test cases and produce code coverage reports in #{format}"
task format => ['instrument', 'test'] do
info "Creating test coverage reports in #{format}"
mkdir_p report_to(format)
Emma.ant do |ant|
ant.merge :outfile=>data_file do
Buildr.projects.each do |project|
[project.emma.metadata_file, project.emma.coverage_file].each do |data_file|
ant.fileset :file=>data_file if File.exist?(data_file)
end
end
end
ant.report do
ant.infileset :file=>data_file
ant.send format, :outfile=>File.join(report_to(format), "coverage.#{format}")
ant.sourcepath do
Buildr.projects.map(&:emma).map(&:sources).flatten.map(&:to_s).each do |src|
ant.dirset :dir=>src if File.exist?(src)
end
end
end
end
end
end
task :clean do
rm_rf [report_to, data_file]
end
end
task :clean do
task('emma:clean').invoke if Dir.pwd == Rake.application.original_dir
end
end
end