| # 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 #:nodoc: |
| |
| # Provides the <code>cobertura:html</code>, <code>cobertura:xml</code> and <code>cobertura:check</code> tasks. |
| # Require explicitly using <code>require "buildr/java/cobertura"</code>. |
| # |
| # You can generate cobertura reports for a single project |
| # using the project name as prefix: |
| # |
| # project_name:cobertura:html |
| # |
| # You can also specify which classes to include/exclude from instrumentation by |
| # passing a class name regexp to the <code>cobertura.include</code> or |
| # <code>cobertura.exclude</code> methods. |
| # |
| # define 'someModule' do |
| # cobertura.include 'some.package.*' |
| # cobertura.include /some.(foo|bar).*/ |
| # cobertura.exclude 'some.foo.util.SimpleUtil' |
| # cobertura.exclude /*.Const(ants)?/i |
| # end |
| # |
| # You can also specify the top level directory to which the top level cobertura tasks |
| # will generate reports by setting the value of the <code>Buildr::Cobertura.report_dir</code> |
| # configuration parameter. |
| # |
| module Cobertura |
| |
| VERSION = '1.9.4.1' |
| |
| class << self |
| def version |
| Buildr.settings.build['cobertura'] || VERSION |
| end |
| end |
| |
| REQUIRES = ArtifactNamespace.for(self).tap do |ns| |
| ns.cobertura! "net.sourceforge.cobertura:cobertura:jar:#{version}", '>=1.9' |
| ns.log4j! 'log4j:log4j:jar:1.2.9', ">=1.2.9" |
| ns.asm! 'asm:asm:jar:2.2.1', '>=2.2.1' |
| ns.asm_tree! 'asm:asm-tree:jar:2.2.1', '>=2.2.1' |
| ns.oro! 'oro:oro:jar:2.0.8', '>=2.0.8' |
| end |
| |
| class << self |
| def dependencies |
| if (VersionRequirement.create('>=1.9.1').satisfied_by?(REQUIRES.cobertura.version)) |
| [:asm, :asm_tree].each { |s| REQUIRES[s] = '3.0' unless REQUIRES[s].selected? } |
| end |
| |
| REQUIRES.artifacts |
| end |
| |
| attr_writer :report_dir |
| |
| def report_dir |
| @report_dir || "reports/cobertura" |
| end |
| |
| def report_to(file = nil) |
| File.expand_path(File.join(*[report_dir, file.to_s].compact)) |
| end |
| |
| def data_file |
| File.expand_path("#{report_dir}.ser") |
| end |
| |
| end |
| |
| class CoberturaConfig # :nodoc: |
| |
| def initialize(project) |
| @project = project |
| end |
| |
| attr_reader :project |
| private :project |
| |
| attr_writer :data_file, :instrumented_dir, :report_dir |
| |
| def data_file |
| @data_file ||= project.path_to(:reports, 'cobertura.ser') |
| end |
| |
| def instrumented_dir |
| @instrumented_dir ||= project.path_to(:target, :instrumented, :classes) |
| end |
| |
| def report_dir |
| @report_dir ||= project.path_to(:reports, :cobertura) |
| end |
| |
| def report_to(file = nil) |
| File.expand_path(File.join(*[report_dir, file.to_s].compact)) |
| end |
| |
| # :call-seq: |
| # project.cobertura.include(*classPatterns) |
| # |
| def include(*classPatterns) |
| includes.push(*classPatterns.map { |p| String === p ? Regexp.new(p) : p }) |
| self |
| end |
| |
| def includes |
| @includeClasses ||= [] |
| end |
| |
| # :call-seq: |
| # project.cobertura.exclude(*classPatterns) |
| # |
| def exclude(*classPatterns) |
| excludes.push(*classPatterns.map { |p| String === p ? Regexp.new(p) : p }) |
| self |
| end |
| |
| def excludes |
| @excludeClasses ||= [] |
| end |
| |
| def ignore(*regexps) |
| ignores.push(*regexps) |
| end |
| |
| def ignores |
| @ignores ||= [] |
| end |
| |
| def sources |
| project.compile.sources |
| end |
| |
| def check |
| @check ||= CoberturaCheck.new |
| end |
| end |
| |
| class CoberturaCheck |
| attr_writer :branch_rate, :line_rate, :total_branch_rate, :total_line_rate, :package_line_rate, :package_branch_rate |
| attr_reader :branch_rate, :line_rate, :total_branch_rate, :total_line_rate, :package_line_rate, :package_branch_rate |
| end |
| |
| module CoberturaExtension # :nodoc: |
| include Buildr::Extension |
| |
| def cobertura |
| @cobertura_config ||= CoberturaConfig.new(self) |
| end |
| |
| after_define do |project| |
| cobertura = project.cobertura |
| |
| namespace 'cobertura' 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(cobertura.instrumented_dir => project.compile.target) do |task| |
| mkdir_p task.to_s |
| unless project.compile.sources.empty? |
| info "Instrumenting classes with cobertura data file #{cobertura.data_file}" |
| Buildr.ant "cobertura" do |ant| |
| ant.taskdef :resource=>"tasks.properties", |
| :classpath=>Buildr.artifacts(Cobertura.dependencies).each(&:invoke).map(&:to_s).join(File::PATH_SEPARATOR) |
| ant.send "cobertura-instrument", :todir=>task.to_s, :datafile=>cobertura.data_file do |
| includes, excludes = cobertura.includes, cobertura.excludes |
| |
| classes_dir = project.compile.target.to_s |
| if includes.empty? && excludes.empty? |
| ant.fileset :dir => classes_dir do |
| ant.include :name => "**/*.class" |
| end |
| else |
| includes = [//] if includes.empty? |
| Dir.glob(File.join(classes_dir, "**/*.class")) do |cls| |
| cls_name = cls.gsub(/#{classes_dir}\/?|\.class$/, '').gsub('/', '.') |
| if includes.any? { |p| p === cls_name } && !excludes.any? { |p| p === cls_name } |
| ant.fileset :file => cls |
| end |
| end |
| end |
| |
| cobertura.ignores.each { |r| ant.ignore :regex => r } |
| end |
| end |
| end |
| touch task.to_s |
| end |
| |
| task 'instrument' => instrumented |
| |
| # We now have two target directories with bytecode. It would make sense to remove compile.target |
| # and add instrumented instead, but apparently Cobertura only creates some of the classes, so |
| # we need both directories and instrumented must come first. |
| project.test.dependencies.unshift cobertura.instrumented_dir |
| project.test.with Cobertura.dependencies |
| project.test.options[:properties]["net.sourceforge.cobertura.datafile"] = cobertura.data_file |
| |
| unless project.compile.sources.empty? |
| [:xml, :html].each do |format| |
| task format => ['instrument', 'test'] do |
| info "Creating test coverage reports in #{cobertura.report_to(format)}" |
| Buildr.ant "cobertura" do |ant| |
| ant.taskdef :resource=>"tasks.properties", |
| :classpath=>Buildr.artifacts(Cobertura.dependencies).each(&:invoke).map(&:to_s).join(File::PATH_SEPARATOR) |
| ant.send "cobertura-report", :format=>format, |
| :destdir=>cobertura.report_to(format), :datafile=>cobertura.data_file do |
| cobertura.sources.flatten.each do |src| |
| ant.fileset(:dir=>src.to_s) if File.exist?(src.to_s) |
| end |
| end |
| end |
| end |
| end |
| end |
| |
| task :check => [:instrument, :test] do |
| Buildr.ant "cobertura" do |ant| |
| ant.taskdef :classpath=>Cobertura.dependencies.join(File::PATH_SEPARATOR), :resource=>"tasks.properties" |
| params = { :datafile => Cobertura.data_file } |
| |
| # oh so ugly... |
| params[:branchrate] = cobertura.check.branch_rate if cobertura.check.branch_rate |
| params[:linerate] = cobertura.check.line_rate if cobertura.check.line_rate |
| params[:totalbranchrate] = cobertura.check.total_branch_rate if cobertura.check.total_branch_rate |
| params[:totallinerate] = cobertura.check.total_line_rate if cobertura.check.total_line_rate |
| params[:packagebranchrate] = cobertura.check.package_branch_rate if cobertura.check.package_branch_rate |
| params[:packagelinerate] = cobertura.check.package_line_rate if cobertura.check.package_line_rate |
| |
| ant.send("cobertura-check", params) do |
| end |
| end |
| end |
| |
| end |
| end |
| |
| project.clean do |
| rm_rf [cobertura.report_to, cobertura.data_file, cobertura.instrumented_dir] |
| end |
| |
| end |
| |
| end |
| |
| class Buildr::Project |
| include CoberturaExtension |
| end |
| |
| namespace "cobertura" do |
| |
| task "instrument" do |
| Buildr.projects.each do |project| |
| project.cobertura.data_file = data_file |
| project.test.options[:properties]["net.sourceforge.cobertura.datafile"] = data_file |
| instrument_task ="#{project.name}:cobertura:instrument" |
| task(instrument_task).invoke if Rake::Task.task_defined?(instrument_task) |
| end |
| end |
| |
| [:xml, :html].each do |format| |
| desc "Run the test cases and produce code coverage reports" |
| task format => ["instrument", "test"] do |
| report_target = report_to(format) |
| if Buildr.projects.detect { |project| !project.compile.sources.empty? } |
| info "Creating test coverage reports in #{report_target}" |
| Buildr.ant "cobertura" do |ant| |
| ant.taskdef :resource=>"tasks.properties", |
| :classpath=>Buildr.artifacts(Cobertura.dependencies).each(&:invoke).map(&:to_s).join(File::PATH_SEPARATOR) |
| ant.send "cobertura-report", :destdir=>report_target, :format=>format, :datafile=>data_file do |
| Buildr.projects.map(&:cobertura).map(&:sources).flatten.each do |src| |
| ant.fileset :dir=>src.to_s if File.exist?(src.to_s) |
| end |
| end |
| end |
| end |
| end |
| end |
| |
| task "clean" do |
| rm_rf [report_to, data_file] |
| end |
| end |
| |
| task "clean" do |
| task("cobertura:clean").invoke if Dir.pwd == Rake.application.original_dir |
| end |
| |
| end |
| end |