buildr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lac...@apache.org
Subject svn commit: r688213 - in /incubator/buildr/trunk: addon/buildr/cobertura.rb spec/cobertura_spec.rb spec/sandbox.rb spec/test_coverage_spec.rb
Date Fri, 22 Aug 2008 22:54:59 GMT
Author: lacton
Date: Fri Aug 22 15:54:59 2008
New Revision: 688213

URL: http://svn.apache.org/viewvc?rev=688213&view=rev
Log:
BUILDR-127: Tests for Cobertura addon

The tests are divided between those that are specific to Cobertura (cobertura_spec.rb) and
those that should be true for most test coverage tool (test_coverage_spec.rb).
Changed 'sandbox.rb' so that loading the Cobertura addon does not affect other tests (i.e.,
the sandbox removes the Cobertura callbacks).  Otherwise, some tests fail for wrong reasons.

Added:
    incubator/buildr/trunk/spec/cobertura_spec.rb
    incubator/buildr/trunk/spec/test_coverage_spec.rb
Modified:
    incubator/buildr/trunk/addon/buildr/cobertura.rb
    incubator/buildr/trunk/spec/sandbox.rb

Modified: incubator/buildr/trunk/addon/buildr/cobertura.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/addon/buildr/cobertura.rb?rev=688213&r1=688212&r2=688213&view=diff
==============================================================================
--- incubator/buildr/trunk/addon/buildr/cobertura.rb (original)
+++ incubator/buildr/trunk/addon/buildr/cobertura.rb Fri Aug 22 15:54:59 2008
@@ -42,7 +42,7 @@
     class << self
 
       REQUIRES = ["net.sourceforge.cobertura:cobertura:jar:1.9", "log4j:log4j:jar:1.2.9",
-        "asm:asm:jar:2.2.1", "asm:asm-tree:jar:2.2.1", "oro:oro:jar:2.0.8"]
+        "asm:asm:jar:2.2.1", "asm:asm-tree:jar:2.2.1", "oro:oro:jar:2.0.8"] unless const_defined?('REQUIRES')
 
       def requires()
         @requires ||= Buildr.artifacts(REQUIRES).each(&:invoke).map(&:to_s)

Added: incubator/buildr/trunk/spec/cobertura_spec.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/cobertura_spec.rb?rev=688213&view=auto
==============================================================================
--- incubator/buildr/trunk/spec/cobertura_spec.rb (added)
+++ incubator/buildr/trunk/spec/cobertura_spec.rb Fri Aug 22 15:54:59 2008
@@ -0,0 +1,78 @@
+# 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.
+
+
+require File.join(File.dirname(__FILE__), 'spec_helpers')
+require File.join(File.dirname(__FILE__), 'test_coverage_spec')
+Sandbox.require_addon File.join(File.dirname(__FILE__), '../addon', 'buildr/cobertura')
+
+Buildr::Cobertura::requires
+
+
+describe Buildr::Cobertura do
+  before do
+    # Reloading the addon because the sandbox removes all its actions
+    load File.expand_path('../addon/buildr/cobertura.rb')
+    @tool_module = Buildr::Cobertura 
+  end
+  
+  it_should_behave_like 'test coverage tool'
+  
+  describe 'project-specific' do
+    
+    describe 'data file' do
+      it 'should have a default value' do
+        define('foo').cobertura.data_file.should point_to_path('reports/cobertura.ser')
+      end
+      
+      it 'should be overridable' do
+        define('foo') { cobertura.data_file = path_to('target/data.cobertura') }
+        project('foo').cobertura.data_file.should point_to_path('target/data.cobertura')
+      end
+      
+      it 'should be created during instrumentation' do
+        write 'src/main/java/Foo.java', 'public class Foo {}'
+        define('foo')
+        task('foo:cobertura:instrument').invoke
+        file(project('foo').cobertura.data_file).should exist
+      end
+    end
+      
+    describe 'instrumentation' do
+      before do
+        ['Foo', 'Bar'].each { |cls| write File.join('src/main/java', "#{cls}.java"), "public
class #{cls} {}" }
+      end
+      
+      it 'should instrument only included classes' do
+        define('foo') { cobertura.include 'Foo' }
+        task("foo:cobertura:instrument").invoke
+        Dir.chdir('target/instrumented/classes') { Dir.glob('*').sort.should == ['Foo.class']
}
+      end
+      
+      it 'should not instrument excluded classes' do
+        define('foo') { cobertura.exclude 'Foo' }
+        task("foo:cobertura:instrument").invoke
+        Dir.chdir('target/instrumented/classes') { Dir.glob('*').sort.should == ['Bar.class']
}
+      end
+      
+      it 'should instrument classes that are included but not excluded' do
+        write 'src/main/java/Baz.java', 'public class Baz {}'
+        define('foo') { cobertura.include('Ba').exclude('ar') }
+        task("foo:cobertura:instrument").invoke
+        Dir.chdir('target/instrumented/classes') { Dir.glob('*').sort.should == ['Baz.class']
}
+      end
+    end
+  end
+end
\ No newline at end of file

Modified: incubator/buildr/trunk/spec/sandbox.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/sandbox.rb?rev=688213&r1=688212&r2=688213&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/sandbox.rb (original)
+++ incubator/buildr/trunk/spec/sandbox.rb Fri Aug 22 15:54:59 2008
@@ -40,6 +40,16 @@
       spec.before(:each) { sandbox }
       spec.after(:each) { reset }
     end
+    
+    # Require an addon without letting its callbacks pollute the Project class.
+    def require_addon addon_require_path
+      project_callbacks_without_addon = Project.class_eval { @callbacks }.dup
+      begin
+        require addon_require_path
+      ensure
+        Project.class_eval { @callbacks = project_callbacks_without_addon }
+      end
+    end
   end
 
   @tasks = Buildr.application.tasks.collect do |original|
@@ -75,6 +85,7 @@
     
     # Later on we'll want to lose all the on_define created during the test.
     @_sandbox[:on_define] = Project.class_eval { (@on_define || []).dup }
+    @_sandbox[:callbacks] = Project.class_eval { (@callbacks || []).dup }
     @_sandbox[:layout] = Layout.default.clone
 
     # Create a local repository we can play with. However, our local repository will be void
@@ -105,6 +116,8 @@
     Project.clear
     on_define = @_sandbox[:on_define]
     Project.class_eval { @on_define = on_define }
+    callbacks = @_sandbox[:callbacks]
+    Project.class_eval { @callbacks = callbacks }
     Layout.default = @_sandbox[:layout].clone
 
     $LOAD_PATH.replace @_sandbox[:load_path]

Added: incubator/buildr/trunk/spec/test_coverage_spec.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/test_coverage_spec.rb?rev=688213&view=auto
==============================================================================
--- incubator/buildr/trunk/spec/test_coverage_spec.rb (added)
+++ incubator/buildr/trunk/spec/test_coverage_spec.rb Fri Aug 22 15:54:59 2008
@@ -0,0 +1,221 @@
+# 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.
+
+
+require File.join(File.dirname(__FILE__), 'spec_helpers')
+
+module TestCoverageHelper
+  def write_test options
+    write File.join(options[:in], "#{options[:for]}Test.java"),
+      "public class #{options[:for]}Test extends junit.framework.TestCase { public void test#{options[:for]}()
{ new #{options[:for]}(); } }"
+  end
+
+  # Rspec matcher using file glob patterns.
+  class FileNamePatternMatcher
+    def initialize(pattern)
+      @expected_pattern = pattern
+      @pattern_matcher = lambda { |filename| File.fnmatch? pattern, filename }
+    end
+    
+    def matches?(directory)
+      @actual_filenames = Dir[File.join(directory,'*')]
+      @actual_filenames.any? &@pattern_matcher
+    end
+    
+    def failure_message
+      "Expected to find at least one element matching '#{@expected_pattern}' among #{@actual_filenames.inspect},
but found none"
+    end
+    
+    def negative_failure_message
+      "Expected to find no element matching '#{@expected_pattern}' among #{@actual_filenames.inspect},
but found matching element(s) #{@actual_filenames.select(&@pattern_matcher).inspect}"
+    end
+  end
+  
+  def have_files_matching pattern
+    FileNamePatternMatcher.new pattern
+  end
+end
+
+describe 'test coverage tool', :shared=>true do
+  include TestCoverageHelper
+
+  def toolname
+    @tool_module.name.split('::').last.downcase
+  end
+
+  describe 'project-specific' do
+
+    before do
+      write 'src/main/java/Foo.java', 'public class Foo {}'
+      write_test :for=>'Foo', :in=>'src/test/java'
+    end
+
+    def test_coverage_config
+      project('foo').send(toolname)
+    end
+
+    describe 'clean' do
+      before { define('foo') }
+      
+      it 'should remove the instrumented directory' do
+        mkdir_p test_coverage_config.instrumented_dir.to_s
+        task('foo:clean').invoke
+        file(test_coverage_config.instrumented_dir).should_not exist
+      end
+      
+      it 'should remove the reporting directory' do
+        mkdir_p test_coverage_config.report_dir
+        task('foo:clean').invoke
+        file(test_coverage_config.report_dir).should_not exist
+      end
+    end
+    
+    describe 'instrumented directory' do
+      it 'should have a default value' do
+        define('foo')
+        test_coverage_config.instrumented_dir.should point_to_path('target/instrumented/classes')
+      end
+
+      it 'should be overridable' do
+        toolname = toolname()
+        define('foo') { send(toolname).instrumented_dir = path_to('target/coverage/classes')
}
+        test_coverage_config.instrumented_dir.should point_to_path('target/coverage/classes')
+      end
+      
+      it 'should be created during instrumentation' do
+        define('foo')
+        task("foo:#{toolname}:instrument").invoke
+        file(test_coverage_config.instrumented_dir).should exist
+      end
+    end
+
+    describe 'instrumentation' do
+      def instrumented_dir
+        file(test_coverage_config.instrumented_dir)
+      end
+
+      it 'should happen after compile' do
+        define('foo')
+        lambda { task("foo:#{toolname}:instrument").invoke }.should run_task('foo:compile')
+      end
+
+      it 'should put classes from compile.target in the instrumented directory' do
+        define('foo')
+        task("foo:#{toolname}:instrument").invoke
+        Dir.entries(instrumented_dir.to_s).should == Dir.entries(project('foo').compile.target.to_s)
+      end
+
+      it 'should touch instrumented directory if anything instrumented' do
+        a_long_time_ago = Time.now - 10
+        define('foo')
+        mkpath instrumented_dir.to_s
+        File.utime(a_long_time_ago, a_long_time_ago, instrumented_dir.to_s)
+        task("foo:#{toolname}:instrument").invoke
+        instrumented_dir.timestamp.should be_close(Time.now, 2)
+      end
+
+      it 'should not touch instrumented directory if nothing instrumented' do
+        a_long_time_ago = Time.now - 10
+        define('foo').compile.invoke
+        mkpath instrumented_dir.to_s
+        [project('foo').compile.target, instrumented_dir].map(&:to_s).each { |dir| File.utime(a_long_time_ago,
a_long_time_ago, dir) }
+        task("foo:#{toolname}:instrument").invoke
+        instrumented_dir.timestamp.should be_close(a_long_time_ago, 2)
+      end
+    end
+
+    describe 'testing classpath' do
+      it 'should give priority to instrumented classes over non-instrumented ones' do
+        define('foo')
+        depends = project('foo').test.dependencies
+        depends.index(test_coverage_config.instrumented_dir).should < depends.index(project('foo').compile.target)
+      end
+
+      it 'should have the test coverage tools artifacts' do
+        define('foo')
+        @tool_module.requires.each { |artifact| project('foo').test.dependencies.should include(artifact)
}
+      end
+    end
+
+    describe 'html report' do
+      it 'should have html files' do
+        define('foo')
+        task("foo:#{toolname}:html").invoke
+        test_coverage_config.report_to(:html).should have_files_matching('*.html')
+      end
+      
+      it 'should contain full source code, including comments' do
+        write 'src/main/java/Foo.java',
+          'public class Foo { /* This comment is a TOKEN to check that test coverage reports
include the source code */ }'
+        define('foo')
+        task("foo:#{toolname}:html").invoke
+        htlm_report_contents = Dir[File.join(test_coverage_config.report_dir, '**/*.html')].map{|path|File.open(path).read}.join
+        htlm_report_contents.should =~ /TOKEN/
+      end
+    end
+  end
+
+  describe 'cross-project' do
+    describe 'reporting' do
+      before do
+        write 'src/main/java/Foo.java', 'public class Foo {}'
+        write 'bar/src/main/java/Bar.java', 'public class Bar {}'
+        write_test :for=>'Bar', :in=>'bar/src/test/java'
+        define('foo') { define('bar')}
+      end
+
+      it 'should have a default target' do
+        @tool_module.report_to.should point_to_path(File.join('reports', toolname))
+      end
+
+      describe 'in html' do
+        it 'should be a defined task' do
+          Rake::Task.task_defined?("#{toolname}:html").should be(true)
+        end
+
+        it 'should happen after project instrumentation and testing' do
+          lambda { task("#{toolname}:html").invoke }.should run_tasks(["foo:#{toolname}:instrument",
'foo:bar:test'])
+        end
+
+        it 'should have html files' do
+          task("#{toolname}:html").invoke
+          @tool_module.report_to(:html).should have_files_matching('*.html')
+        end
+        
+        it 'should contain full source code, including comments' do
+          write 'bar/src/main/java/Bar.java',
+            'public class Bar { /* This comment is a TOKEN to check that test coverage reports
include the source code */ }'
+          task("#{toolname}:html").invoke
+          htlm_report_contents = Dir[File.join(@tool_module.report_to(:html), '**/*.html')].map{|path|File.open(path).read}.join
+          htlm_report_contents.should =~ /TOKEN/
+        end
+      end
+    end
+    
+    describe 'clean' do
+      it 'should remove the report directory' do
+        define('foo')
+        mkdir_p @tool_module.report_to
+        task("#{toolname}:clean").invoke
+        file(@tool_module.report_to).should_not exist
+      end
+      
+      it 'should be called when calling global clean' do
+        define('foo')
+        lambda { task('clean').invoke }.should run_task("#{toolname}:clean")
+      end
+    end
+  end
+end
\ No newline at end of file



Mime
View raw message