You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildr.apache.org by as...@apache.org on 2008/01/12 01:48:15 UTC

svn commit: r611339 - in /incubator/buildr/trunk: doc/pages/ lib/core/ lib/java/ spec/

Author: assaf
Date: Fri Jan 11 16:48:12 2008
New Revision: 611339

URL: http://svn.apache.org/viewvc?rev=611339&view=rev
Log:
JUnit and TestNG now working with new test framework

Modified:
    incubator/buildr/trunk/doc/pages/testing.textile
    incubator/buildr/trunk/lib/core/compile.rb
    incubator/buildr/trunk/lib/core/test.rb
    incubator/buildr/trunk/lib/java/compilers.rb
    incubator/buildr/trunk/lib/java/test_frameworks.rb
    incubator/buildr/trunk/spec/compile_spec.rb
    incubator/buildr/trunk/spec/java_compilers.rb
    incubator/buildr/trunk/spec/java_test_frameworks.rb
    incubator/buildr/trunk/spec/sandbox.rb
    incubator/buildr/trunk/spec/spec_helpers.rb
    incubator/buildr/trunk/spec/test_spec.rb

Modified: incubator/buildr/trunk/doc/pages/testing.textile
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/doc/pages/testing.textile?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/doc/pages/testing.textile (original)
+++ incubator/buildr/trunk/doc/pages/testing.textile Fri Jan 11 16:48:12 2008
@@ -15,7 +15,7 @@
 
 The first two tasks to execute are @test.compile@ and @test.resources@.  They
 work similar to @compile@ and @resources@, but uses a different set of
-directories.  For example, Java test cases compile from the @src/test/java@
+directories.  For example, Java tests compile from the @src/test/java@
 directory into the @target/test/classes@ directory, while resources are copied
 from @src/test/resources@ into @target/test/resources@.
 
@@ -30,7 +30,7 @@
 dependency lists separately, but using @test.with@ is good enough in more
 cases.
 
-Once compiled, the @test@ task runs the test cases.
+Once compiled, the @test@ task runs all the tests.
 
 
 h2. Using JUnit
@@ -97,9 +97,9 @@
 
 h2. Excluding Tests and Ignoring Failures
 
-If you have a lot of test cases that are failing or just hanging there
-collecting dusts, you can tell Buildr to ignore them.  You can either tell
-Buildr to only run specific tests, for example:
+If you have a lot of tests that are failing or just hanging there collecting
+dusts, you can tell Buildr to ignore them.  You can either tell Buildr to only
+run specific tests, for example:
 
 {{{!ruby
 test.include 'com.acme.tests.passing.*'
@@ -143,7 +143,7 @@
 It's a good idea to run tests every time you change the source code, so we
 wired the @build@ task to run the @test@ task at the end of the build.  And
 conveniently enough, the @build@ task is the default task, so another way to
-build changes in your code and run your test cases:
+build changes in your code and run your tests:
 
 {{{!sh
 $ buildr
@@ -154,7 +154,7 @@
 @build@ task that does not invoke the @test@ task, so @buildr build@ will run
 the tests cases, but @buildr foo:build@ will not.
 
-While it's a good idea to always run your test cases, it's not always possible.
+While it's a good idea to always run your tests, it's not always possible.
 There are two ways you can get @build@ to not run the @test@ task.  You can set
 the environment variable @test@ to @no@ (but @skip@ and @off@ will also work).
 You can do that when running Buildr:
@@ -174,21 +174,20 @@
 Buildfile or @buildr.rb@ file, by setting @options.test = false@. We didn't say
 it's a good idea, we're just giving you the option.
 
-The @test@ task is just smart enough to run all the test cases it finds, but
-will accept include/exclude patterns.  Often enough you're only working on one
-broken test case and you only want to run that one test case.  Better than
-changing your Buildfile, you can run the @test@ task with a pattern.  For
-example:
+The @test@ task is just smart enough to run all the tests it finds, but will
+accept include/exclude patterns.  Often enough you're only working on one
+broken test and you only want to run that one test.  Better than changing your
+Buildfile, you can run the @test@ task with a pattern.  For example:
 
 {{{!sh
 $ buildr test:KillerAppTest
 }}}
 
-Buildr will then only run tests that contain the value @KillerAppTest@.  It
+Buildr will then run only tests that match the pattern @KillerAppTest@.  It
 uses pattern matching, so @test:Foo@ will run @com.acme.FooTest@ and
-@com.acme.FooBarTest@.  You can use a class name, or a package name to run all
-tests in that package, or any such combination.  In fact, you can specify
-several patterns separated with commas.  For example:
+@com.acme.FooBarTest@.  With Java, you can use this to pick a class name, or a
+package name to run all tests in that package, or any such combination.  In
+fact, you can specify several patterns separated with commas.  For example:
 
 {{{!sh
 $ buildr test:FooTest,BarTest
@@ -214,8 +213,8 @@
 
 So far we talked about unit tests.  Unit tests are run in isolation on the
 specific project they test, in an isolated environment, generally with minimal
-setup and teardown.  You get a sense of that when we told you test cases run
-after the @build@ task, and include JMock in the dependency list.
+setup and teardown.  You get a sense of that when we told you tests run after
+the @build@ task, and include JMock in the dependency list.
 
 In contrast, integration tests are run with a number of components, in an
 environment that resembles production, often with more complicates setup and
@@ -224,8 +223,8 @@
 
 You write integration tests much the same way as you write unit tests, using
 @test.compile@ and @test.resources@.  However, you need to tell Buildr that
-your test cases will execute during integration test.  To do so, add the
-following line in your project definition:
+your tests will execute during integration test.  To do so, add the following
+line in your project definition:
 
 {{{!ruby
 test.using :integration

Modified: incubator/buildr/trunk/lib/core/compile.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/core/compile.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/core/compile.rb (original)
+++ incubator/buildr/trunk/lib/core/compile.rb Fri Jan 11 16:48:12 2008
@@ -22,7 +22,7 @@
       # Adds a compiler to the list of supported compiler.
       #   
       # For example:
-      #   Buildr::Compiler.add Buildr::Javac
+      #   Buildr::Compiler << Buildr::Javac
       def add(compiler)
         @compilers ||= []
         @compilers |= [compiler]
@@ -44,7 +44,7 @@
 
         # The compiler's identifier (e.g. :javac).  Inferred from the class name.
         def to_sym
-          @symbol
+          @symbol ||= name.split('::').last.downcase.to_sym
         end
 
         # The compiled language (e.g. :java).
@@ -59,8 +59,6 @@
         attr_reader :target_ext
         # The default packaging type (e.g. :jar).
         attr_reader :packaging
-        # Options to inherit from parent task.  Defaults to value of OPTIONS constant.
-        attr_reader :inherit_options
 
         # Returns true if this compiler applies to any source code found in the listed source
         # directories.  For example, Javac returns true if any of the source directories contains
@@ -74,17 +72,15 @@
         # For example:
         #   specify :language=>:java, :target=>'classes', :target_ext=>'class', :packaging=>:jar
         def specify(attrs)
-          attrs[:symbol] ||= name.split('::').last.downcase.to_sym
           attrs[:sources] ||= attrs[:language].to_s
           attrs[:source_ext] ||= attrs[:language].to_s
-          attrs[:inherit_options] ||= const_get('OPTIONS').clone rescue []
           attrs.each { |name, value| instance_variable_set("@#{name}", value) }
         end
 
       end
 
       # Construct a new compiler with the specified options.  Note that options may
-      # changed before the compiler is run.
+      # change before the compiler is run.
       def initialize(options)
         @options = options
       end
@@ -183,8 +179,9 @@
 
     def initialize(*args) #:nodoc:
       super
-      @parent_task = Project.parent_task(name)
-      @options = OpenObject.new
+      parent_task = Project.parent_task(name)
+      inherit = lambda { |hash, key| parent_task.options[key] } if parent_task.respond_to?(:options)
+      @options = OpenObject.new &inherit
       @sources = FileList[]
       @dependencies = FileList[]
 
@@ -317,8 +314,6 @@
     def compiler=(name) #:nodoc:
       raise "#{compiler} compiler already selected for this project" if @compiler
       cls = Compiler.select(name) or raise ArgumentError, "No #{name} compiler available. Did you install it?"
-      cls.inherit_options.reject { |name| options.has_key?(name) }.
-        each { |name| options[name] = @parent_task.options[name] } if @parent_task.respond_to?(:options)
       @compiler = cls.new(options)
       from Array(cls.sources).map { |path| @project.path_to(:source, @usage, path) }.
         select { |path| File.exist?(path) } if sources.empty?

Modified: incubator/buildr/trunk/lib/core/test.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/core/test.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/core/test.rb (original)
+++ incubator/buildr/trunk/lib/core/test.rb Fri Jan 11 16:48:12 2008
@@ -7,37 +7,36 @@
 
   # The underlying test framework used by TestTask.
   # To add a new test framework, extend TestFramework::Base and add your framework using:
-  #   Buildr::TestFramework.add MyFramework
+  #   Buildr::TestFramework << MyFramework
   class TestFramework
 
     class << self
 
       # Returns true if the specified test framework exists.
       def has?(name)
-        frameworks.any? { |framework| framework.name == name }
+        frameworks.any? { |framework| framework.to_sym == name.to_sym }
       end
 
       # Select a test framework by its name.
       def select(name)
-        frameworks.detect { |framework| framework.name == name }
+        frameworks.detect { |framework| framework.to_sym == name.to_sym }
       end
 
       # Identify which test framework applies for this project.
-      def identify_from(project)
+      def select_from(project)
         # Look for a suitable test framework based on the compiled language,
         # which may return multiple candidates, e.g. JUnit and TestNG for Java.
         # Pick the one used in the parent project, if not, whichever comes first.
-        candidates = frameworks.select { |framework| framework.supports?(project) }
-        parent = project.parent.test.framework if project.parent
-        candidates.detect { |framework| framework.name == parent } || candidates.first
+        candidates = frameworks.select { |framework| framework.applies_to?(project) }
+        parent = project.parent
+        parent && candidates.detect { |framework| framework.to_sym == parent.test.framework } || candidates.first
       end
 
       # Adds a test framework to the list of supported frameworks.
       #   
       # For example:
-      #   Buildr::TestFramework.add Buildr::JUnit
+      #   Buildr::TestFramework << Buildr::JUnit
       def add(framework)
-        framework = framework.new if Class === framework
         @frameworks ||= []
         @frameworks |= [framework]
       end
@@ -54,21 +53,57 @@
     # (see JUnit as an example).
     class Base
 
-      def initialize(args = {})
-        args[:name] ||= self.class.name.split('::').last.downcase.to_sym
-        args[:requires] ||= []
-        args.each { |name, value| instance_variable_set "@#{name}", value }
+      class << self
+
+        # The framework's identifier (e.g. :junit).  Inferred from the class name.
+        def to_sym
+          @symbol ||= name.split('::').last.downcase.to_sym
+        end
+
+        # Returns true if this framework applies to the current project.  For example, JUnit returns
+        # true if the tests are written in Java.
+        def applies_to?(paths)
+          raise 'Not implemented'
+        end
+
+        # Returns a list of dependencies for this framework.  Defaults to obtaining a list of
+        # artifact specifications from the REQUIRES constant.
+        def dependencies
+          @dependencies ||= FileList[*(const_get('REQUIRES') rescue [])]
+        end
+
+      end
+
+      # Construct a new test framework with the specified options.  Note that options may
+      # change before the framework is run.
+      def initialize(options)
+        @options = options
       end
 
-      attr_accessor :name
-      attr_accessor :requires
+      # Options for this test framework.
+      attr_reader :options
 
-      def tests(path)
-        Dir["#{path}/**/*"]
+      # Returns a list of dependenices for this framework.  Defaults to calling the #dependencies
+      # method on the class.
+      def dependencies
+        self.class.dependencies
       end
 
-      def supports?(project)
-        false
+      # TestTask calls this method to return a list of test names that can be run in this project.
+      # It then applies the include/exclude patterns to arrive at the list of tests that will be
+      # run, and call the #run method with that list.
+      #
+      # This method should return a list suitable for using with the #run method, but also suitable
+      # for the user to manage.  For example, JUnit locates all the tests in the test.compile.target
+      # directory, and returns the class names, which are easier to work with than file names.
+      def tests(project)
+        raise 'Not implemented'
+      end
+
+      # TestTask calls this method to run the named (and only those) tests.  This method returns
+      # the list of tests that ran successfully.
+      def run(tests, task, dependencies)
+        raise 'Not implemented'
       end
 
     end
@@ -81,16 +116,16 @@
   # You can use the test task in three ways. You can access and configure specific test tasks,
   # e.g. enhance the #compile task, or run code during #setup/#teardown.
   #
-  # You can use convenient methods that handle the most common settings. For example, add 
-  # dependencies using #with, or include only specific test cases using #include.
+  # You can use convenient methods that handle the most common settings. For example,
+  # add dependencies using #with, or include only specific tests using #include.
   #
   # You can also enhance this task directly. This task will first execute the #compile task, followed
   # by the #setup task, run the unit tests, any other enhancements, and end by executing #teardown.
   #
-  # Unit tests are fun from classed compiled by the test.compile class that match the TEST_FILE_PATTERN
-  # (i.e. MyClassTest, MyClassTestSuite, etc). The test framework is determined by setting one of the
-  # test framework options to true, for example:
-  #   test.unsing :testng
+  # The test framework is determined based on the available test files, for example, if the test
+  # cases are written in Java, then JUnit is selected as the test framework.  You can also select
+  # a specific test framework, for example, to use TestNG instead of JUnit:
+  #   test.using :testng
   class TestTask < Rake::Task
 
     class << self
@@ -118,7 +153,7 @@
       # Used by the test/integration rule to only run tests that match the specified names.
       def only_run(tests) #:nodoc:
         tests = tests.map { |name| name =~ /\*/ ? name : "*#{name}*" }
-        # Since the test case may reside in a sub-project, we need to set the include/exclude pattern on
+        # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on
         # all sub-projects, but only invoke test on the local project.
         Project.projects.each { |project| project.test.instance_eval { @include = tests ; @exclude.clear } }
       end
@@ -132,13 +167,15 @@
       @dependencies = FileList[]
       @include = []
       @exclude = []
-      @options = OpenObject.new
       parent_task = Project.parent_task(name)
       if parent_task.respond_to?(:options)
-        parent_task.options.each { |name, value| @options[name] = value unless @options.has_key?(name) }
+        @options = OpenObject.new { |hash, key| parent_task.options[key] }
+      else
+        @options = OpenObject.new(DEFAULT_OPTIONS)
+      end
+      enhance do
+        run_tests if framework
       end
-      DEFAULT_OPTIONS.each { |name, value| @options[name] = value unless @options.has_key?(name) }
-      enhance { run_tests }
     end
 
     # The dependencies used for running the tests. Includes the compiled files (compile.target)
@@ -175,11 +212,11 @@
     #
     # The compile task is similar to the Project's compile task. However, it compiles all
     # files found in the src/test/{source} directory into the target/test/{code} directory.
-    # This task is executed by the test task before running any test cases.
+    # This task is executed by the test task before running any tests.
     #
     # Once the project definition is complete, all dependencies from the regular
     # compile task are copied over, so you only need to specify dependencies
-    # specific to your test cases. You can do so by calling #with on the test task.
+    # specific to your tests. You can do so by calling #with on the test task.
     # The dependencies used here are also copied over to the junit task.
     def compile(*sources, &block)
       @project.task('test:compile').from(sources).enhance &block
@@ -217,7 +254,7 @@
     #   with(*specs) => self
     #
     # Specify artifacts (specs, tasks, files, etc) to include in the depdenenciest list
-    # when compiling and running test cases.
+    # when compiling and running tests.
     def with(*artifacts)
       @dependencies |= Buildr.artifacts(artifacts.flatten).uniq
       compile.with artifacts
@@ -230,26 +267,34 @@
     # :call-seq:
     #   using(options) => self
     #
-    # Sets various test options from a hash and returns self.  Can also be used to select
-    # the test framework.  For example:
-    #   test.using :testng, :fork=>:each, :properties=>{ 'url'=>'http://localhost:8080' }
-    #
-    # Currently supports the following options:
-    # * :fail_on_failure -- True to fail on test failure (default is true).
-    # * :fork -- Fork test cases (JUnit only).
-    # * :properties -- System properties.
-    # * :environment -- Environment variables.
-    #
-    # The :fork option takes the following values:
-    # * :once -- Fork one JVM for each project (default).
-    # * :each -- Fork one JVM for each test case.
-    # * false -- Do not fork, running all test cases in the same JVM.
+    # Sets various test options from a hash and returns self.  For example:
+    #   test.using :fork=>:each, :properties=>{ 'url'=>'http://localhost:8080' }
+    #
+    # Can also be used to select the test framework, or to run these tests as
+    # integration tests.  For example:
+    #   test.using :testng
+    #   test.using :integration
+    #
+    # The :fail_on_failure option specifies whether the task should fail if
+    # any of the tests fail (default), or should report the failures but continue
+    # running the build (when set to false).
+    #
+    # All other options depend on the capability of the test framework.  These options
+    # should be used the same way across all frameworks that support them:
+    # * :fork -- Fork once for each project (:once, default), for each test in each
+    #     project (:each), or don't fork at all (false).
+    # * :properties -- Properties pass to the test, e.g. in Java as system properties.
+    # * :environment -- Environment variables.  This hash is made available in the
+    #     form of environment variables.
     def using(*args)
       args.pop.each { |key, value| options[key.to_sym] = value } if Hash === args.last
       args.each do |name|
         if TestFramework.has?(name)
-          select name
+          self.framework = name
+        elsif name == :integration
+          options[:integration] = true
         else
+          warn_deprecated "Please replace with using(:#{name}=>true)"
           options[name.to_sym] = true
         end
       end 
@@ -259,19 +304,16 @@
     # :call-seq:
     #   include(*names) => self
     #
-    # Include only the specified test cases. Unless specified, the default is to include
-    # all test cases. This method accepts multiple arguments and returns self.
-    #
-    # Test cases are specified using the fully qualified class name. You can also use file-like
-    # patterns (glob) to specify collection of files, classes, packages, etc. For example:
-    #   test.include 'com.example.FirstTest'
-    #   test.include 'com.example.*'
-    #   test.include 'com.example.Module*'
-    #   test.include '*.{First,Second}Test'
-    #
-    # By default, all classes that have a name ending with Test or Suite are included.
-    # Use these suffixes for your test and test suite classes respectively, to distinguish them
-    # from stubs, helper classes, etc. 
+    # Include only the specified tests. Unless specified, the default is to include
+    # all tests identified by the test framework. This method accepts multiple arguments
+    # and returns self.
+    #
+    # Tests are specified by their full name, but you can use glob patterns to select
+    # multiple tests, for example:
+    #   test.include 'com.example.FirstTest'  # FirstTest only
+    #   test.include 'com.example.*'          # All tests under com/example
+    #   test.include 'com.example.Module*'    # All tests starting with Module
+    #   test.include '*.{First,Second}Test'   # FirstTest, SecondTest
     def include(*names)
       @include += names
       self
@@ -280,7 +322,7 @@
     # :call-seq:
     #   exclude(*names) => self
     #
-    # Exclude the specified test cases. This method accepts multiple arguments and returns self.
+    # Exclude the specified tests. This method accepts multiple arguments and returns self.
     # See #include for the type of arguments you can use.
     def exclude(*names)
       @exclude += names
@@ -288,60 +330,42 @@
     end
 
     # :call-seq:
-    #    tests() => strings
+    #    tests => strings
     #
-    # List of test files to run. Determined by finding all the test failes in the target directory,
-    # and reducing based on the include/exclude patterns.
+    # List the tests that this task will run.
     def tests
-      return [] unless compile.target
-      fail "No test framework selected" unless @framework
-      @files ||= begin
-        base = Pathname.new(compile.target.to_s)
-        @framework.tests(compile.target.to_s).select { |test| include?(test) }.sort
-      end
+      fail "No test framework selected" unless framework
+      @tests ||= @framework.tests(@project).select { |test| include?(test) }.sort
     end
 
     # *Deprecated*: Use tests instead.
     def classes
-      warn_deprecated 'Use tests instead'
+      warn_deprecated 'Call tests instead of classes'
       tests
     end
 
-    # List of failed tests. Set after running the tests.
+    # After running the task, returns all the tests that failed, empty array if all tests passed.
     attr_reader :failed_tests
 
-    # List of passed tests. Set after running the tests.
+    # After running the task, returns all the tests that passed, empty array if no tests passed.
     attr_reader :passed_tests
 
     # :call-seq:
-    #   include?(name) => boolean
-    #
-    # Returns true if the specified class name matches the inclusion/exclusion pattern. Used to determine
-    # which tests to execute.
-    def include?(name)
-      (@include.empty? || @include.any? { |pattern| File.fnmatch(pattern, name) }) &&
-        !@exclude.any? { |pattern| File.fnmatch(pattern, name) }
-    end
-
-    # :call-seq:
-    #   requires() => specs
-    #
-    # Returns the dependencies for the selected test frameworks. Necessary for compiling and running test cases.
-    def requires
-      framework ? Array(@framework.requires) : []
-    end
-
-    # :call-seq:
-    #   framework() => symbol
+    #   framework => symbol
     #
     # Returns the test framework, e.g. :junit, :testng.
     def framework
-      @framework ||= TestFramework.identify_from(@project)
-      @framework && @framework.name
+      unless @framework
+        frameworks = TestFramework.frameworks.select { |cls| cls.applies_to?(@project) }
+        candidate = @project.parent && frameworks.detect { |framework| framework.to_sym == @project.parent.test.framework } ||
+          frameworks.first
+        self.framework = candidate if candidate
+      end
+      @framework && @framework.class.to_sym
     end
 
     # :call-seq:
-    #   report_to() => file
+    #   report_to => file
     #
     # Test frameworks that can produce reports, will write them to this directory.
     #
@@ -359,23 +383,34 @@
       @project = project
     end
 
-    def select(name)
-      @framework = TestFramework.select(name)
+    def framework=(name)
+      cls = TestFramework.select(name) or raise ArgumentError, "No #{name} test framework available. Did you install it?"
+      #cls.inherit_options.reject { |name| options.has_key?(name) }.
+      #  each { |name| options[name] = @parent_task.options[name] } if @parent_task.respond_to?(:options)
+      @framework = cls.new(options)
+      # Test framework dependency.
+      with @framework.class.dependencies
     end
 
     # :call-seq:
-    #   run_tests()
+    #   include?(name) => boolean
     #
-    # Runs the test cases using the selected test framework. Executes as part of the task.
+    # Returns true if the specified test name matches the inclusion/exclusion pattern. Used to determine
+    # which tests to execute.
+    def include?(name)
+      (@include.empty? || @include.any? { |pattern| File.fnmatch(pattern, name) }) &&
+        !@exclude.any? { |pattern| File.fnmatch(pattern, name) }
+    end
+
+    # Runs the tests using the selected test framework.
     def run_tests
       rm_rf report_to.to_s
-      tests = self.tests
       if tests.empty?
         @passed_tests, @failed_tests = [], []
       else
         puts "Running tests in #{@project.name}" if verbose
-        @failed_tests = @framework.run(tests, self, @dependencies.compact.map(&:to_s))
-        @passed_tests = tests - @failed_tests
+        @passed_tests = @framework.run(tests, self, @dependencies.compact.map(&:to_s))
+        @failed_tests = tests - @passed_tests
         unless @failed_tests.empty?
           warn "The following tests failed:\n#{@failed_tests.join('\n')}" if verbose
           fail 'Tests failed!'
@@ -431,22 +466,21 @@
   end
 
 
-  # Methods added to Project to support compilation and running of test cases.
+  # Methods added to Project to support compilation and running of tests.
   module Test
 
     include Extension
 
     first_time do
-      desc 'Run all test cases'
+      desc 'Run all tests'
       task('test') { TestTask.run_local_tests false }
 
-      # This rule takes a suffix and runs that test case in the current project. For example;
+      # This rule takes a suffix and runs that tests in the current project. For example;
       #   buildr test:MyTest
-      # will run the test case class com.example.MyTest, if found in the current project.
+      # will run the test com.example.MyTest, if such a test exists for this project.
       #
-      # If you want to run multiple test cases, separate tham with a comma. You can also use glob
-      # (* and ?) patterns to match multiple tests, e.g. com.example.* to run all test cases in
-      # a given package. If you don't specify a glob pattern, asterisks are added for you.
+      # If you want to run multiple test, separate tham with a comma. You can also use glob
+      # (* and ?) patterns to match multiple tests, see the TestTask#include method.
       rule /^test:.*$/ do |task|
         TestTask.only_run task.name.scan(/test:(.*)/)[0][0].split(',')
         task('test').invoke
@@ -454,7 +488,7 @@
 
       task 'build' do |task|
         # Make sure this happens as the last action on the build, so all other enhancements
-        # are made to run before starting the test cases.
+        # are made to run before starting the tests.
         task.enhance do
           task('test').invoke unless Buildr.options.test == false
         end
@@ -496,11 +530,11 @@
       # Dependency on compiled code, its dependencies and resources.
       test.with project.compile.dependencies, Array(project.compile.target) if project.compile.target
       test.with Array(project.resources.target)
-      # Dependency on compiled test cases and resources.  Dependencies added using with.
+      # Dependency on compiled tests and resources.  Dependencies added using with.
       test.dependencies.concat Array(test.compile.target) if test.compile.target
       test.dependencies.concat Array(test.resources.target)
-      # Test framework dependency.
-      test.with test.requires
+      # Picking up the test frameworks adds further dependencies.
+      test.framework
 
       project.clean do
         verbose(false) do
@@ -519,26 +553,25 @@
     #
     # You can use the test task in three ways. You can access and configure specific
     # test tasks, e.g. enhance the compile task by calling test.compile, setup for
-    # the test cases by enhancing test.setup and so forth.
+    # the tests by enhancing test.setup and so forth.
     #
     # You can use convenient methods that handle the most common settings. For example,
-    # add dependencies using test.with, or include only specific test cases
-    # using test.include.
+    # add dependencies using test.with, or include only specific tests using test.include.
     #
     # You can also enhance this task directly. This method accepts a list of arguments
     # that are used as prerequisites and an optional block that will be executed by the
     # test task.
     #
-    # This task compiles the project and the test cases (in that order) before running any tests.
-    # It execute the setup task, runs all the test cases, any enhancements, and ends with the
+    # This task compiles the project and the tests (in that order) before running any tests.
+    # It execute the setup task, runs all the tests, any enhancements, and ends with the
     # teardown tasks.
     def test(*prereqs, &block)
       task('test').enhance prereqs, &block
     end
   
     # :call-seq:
-    #   integration() { |task| .... }
-    #   integration() => IntegrationTestTask
+    #   integration { |task| .... }
+    #   integration => IntegrationTestTask
     #
     # Use this method to return the integration tests task, or enhance it with a block to execute.
     #
@@ -547,7 +580,7 @@
     # :integration=>true, all other tests are considered unit tests and run by the test task before packaging.
     # So essentially: build=>test=>packaging=>integration=>install/deploy.
     #
-    # You add new test cases from projects that define integration tests using the regular test task,
+    # You add new tests from projects that define integration tests using the regular test task,
     # but with the following addition:
     #   test.using :integration
     #
@@ -561,8 +594,8 @@
 
 
   # :call-seq:
-  #   integration() { |task| .... }
-  #   integration() => IntegrationTestTask
+  #   integration { |task| .... }
+  #   integration => IntegrationTestTask
   #
   # Use this method to return the integration tests task.
   def integration(*deps, &block)
@@ -571,17 +604,17 @@
 
   class Options
 
-    # Runs test cases after the build when true (default). This forces test cases to execute
+    # Runs tests after the build when true (default). This forces tests to execute
     # after the build, including when running build related tasks like install, deploy and release.
     #
-    # Set to false to not run any test cases. Set to :all to run all test cases, ignoring failures.
+    # Set to false to not run any tests. Set to :all to run all tests, ignoring failures.
     #
     # This option is set from the environment variable 'test', so you can also do:
 
     # Returns the test option (environment variable TEST). Possible values are:
-    # * :false -- Do not run any test cases (also accepts 'no' and 'skip').
-    # * :true -- Run all test cases, stop on failure (default if not set).
-    # * :all -- Run all test cases, ignore failures.
+    # * :false -- Do not run any tests (also accepts 'no' and 'skip').
+    # * :true -- Run all tests, stop on failure (default if not set).
+    # * :all -- Run all tests, ignore failures.
     def test
       case value = ENV['TEST'] || ENV['test']
       when /^(no|off|false|skip)$/i
@@ -591,7 +624,7 @@
       when /^(yes|on|true)$/i, nil
         true
       else
-        warn "Expecting the environment variable test to be 'no' or 'all', not sure what to do with #{value}, so I'm just going to run all the test cases and stop at failure."
+        warn "Expecting the environment variable test to be 'no' or 'all', not sure what to do with #{value}, so I'm just going to run all the tests and stop at failure."
         true
       end
     end
@@ -615,9 +648,9 @@
   task('help') do
     puts <<-HELP
 
-To run a full build without running any test cases:
+To run a full build without running any tests:
   buildr test=no
-To run specific test case:
+To run specific test:
   buildr test:MyTest
 To run integration tests:
   buildr integration

Modified: incubator/buildr/trunk/lib/java/compilers.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/compilers.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/java/compilers.rb (original)
+++ incubator/buildr/trunk/lib/java/compilers.rb Fri Jan 11 16:48:12 2008
@@ -29,8 +29,10 @@
 
       def initialize(options) #:nodoc:
         super
-        { :warnings=>verbose, :deprecation=>false, :lint=>false, :debug=>Buildr.options.debug }.
-          each { |name, value| options[name] = value unless options.has_key?(name) }
+        options[:debug] = Buildr.options.debug if options[:debug].nil?
+        options[:warnings] = verbose if options[:warnings].nil?
+        options[:deprecation] ||= false
+        options[:lint] ||= false
       end
 
       def compile(sources, target, dependencies) #:nodoc:

Modified: incubator/buildr/trunk/lib/java/test_frameworks.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/test_frameworks.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/java/test_frameworks.rb (original)
+++ incubator/buildr/trunk/lib/java/test_frameworks.rb Fri Jan 11 16:48:12 2008
@@ -8,15 +8,14 @@
 
   # JMock is available when using JUnit and TestNG.
   module JMock
-    # JMock version..
+    # JMock version.
     VERSION = '1.2.0' unless const_defined?('VERSION')
     # JMock specification.
     REQUIRES = ["jmock:jmock:jar:#{VERSION}"]
   end
 
 
-  # JUnit test framework, the default test framework for Java.
-  #   test.using :junit
+  # JUnit test framework, the default test framework for Java tests.
   #
   # Support the following options:
   # * :fork        -- If true/:once (default), fork for each test class.  If :each, fork for each individual
@@ -92,7 +91,7 @@
     end
 
 
-    # Ant-JUnit requires for JUnit and JUnit reports tasks.
+    # Ant-JUnit requires for JUnit and JUnit reports tasks.  Also requires JUnitTestFilter.
     Java.classpath << "org.apache.ant:ant-junit:jar:#{Ant::VERSION}" << File.join(File.dirname(__FILE__))
 
     # JUnit version number.
@@ -100,27 +99,28 @@
     # JUnit specification.
     REQUIRES = ["junit:junit:jar:#{VERSION}"] + JMock::REQUIRES
 
-    def initialize #:nodoc:
-      super :requires=>REQUIRES
+    class << self
+
+      def applies_to?(project) #:nodoc:
+        project.test.compile.language == :java
+      end
+
     end
 
-    def tests(path) #:nodoc:
-      # Ignore anonymous classes.
-      base = Pathname.new(path)
-      candidates = super(path).map { |file| Pathname.new(file).relative_path_from(base).to_s.ext('').gsub(File::SEPARATOR, ',') }.
+    def tests(project) #:nodoc:
+      return [] unless project.test.compile.target
+      target = Pathname.new(project.test.compile.target.to_s)
+      candidates = Dir["#{target}/**/*.class"].
+        map { |file| Pathname.new(file).relative_path_from(target).to_s.ext('').gsub(File::SEPARATOR, '.') }.
         reject { |name| name =~ /\$/ }
-      classpath = [path + '/'] + Buildr.artifacts(REQUIRES).map(&:to_s)
+      classpath = [target.to_s + '/'] + Buildr.artifacts(dependencies).map(&:to_s)
       Java.org.apache.buildr.JUnitTestFilter.new(classpath).filter(candidates)
     end
 
-    def supports?(project) #:nodoc:
-      project.test.compile.language == :java
-    end
-
     def run(tests, task, dependencies) #:nodoc:
       # Use Ant to execute the Junit tasks, gives us performance and reporting.
       Buildr.ant('junit') do |ant|
-        case task.options[:fork]
+        case options[:fork]
         when false
           forking = {}
         when :each
@@ -131,11 +131,11 @@
           fail 'Option fork must be :once, :each or false.'
         end
         mkpath task.report_to.to_s
-        ant.junit forking.merge(:clonevm=>task.options[:clonevm] || false, :dir=>task.send(:project).path_to) do
+        ant.junit forking.merge(:clonevm=>options[:clonevm] || false, :dir=>task.send(:project).path_to) do
           ant.classpath :path=>dependencies.each { |path| file(path).invoke }.join(File::PATH_SEPARATOR)
-          (task.options[:properties] || []).each { |key, value| ant.sysproperty :key=>key, :value=>value }
-          (task.options[:environment] || []).each { |key, value| ant.env :key=>key, :value=>value }
-          java_args = task.options[:java_args] || Buildr.options.java_args
+          (options[:properties] || []).each { |key, value| ant.sysproperty :key=>key, :value=>value }
+          (options[:environment] || []).each { |key, value| ant.env :key=>key, :value=>value }
+          java_args = options[:java_args] || Buildr.options.java_args
           java_args = java_args.split(/\s+/) if String === java_args
           java_args.each { |value| ant.jvmarg :value=>value } if java_args
           ant.formatter :type=>'plain'
@@ -147,19 +147,19 @@
             end
           end
         end
-        return [] unless ant.project.getProperty('failed')
+        return tests unless ant.project.getProperty('failed')
       end
       # But Ant doesn't tell us what went kaput, so we'll have to parse the test files.
-      tests.inject([]) do |failed, test|
+      tests.inject([]) do |passed, test|
         report_file = File.join(task.report_to.to_s, "TEST-#{test}.txt")
         if File.exist?(report_file)
           report = File.read(report_file)
           # The second line (if exists) is the status line and we scan it for its values.
           status = (report.split("\n")[1] || '').scan(/(run|failures|errors):\s*(\d+)/i).
             inject(Hash.new(0)) { |hash, pair| hash[pair[0].downcase.to_sym] = pair[1].to_i ; hash }
-          failed << test if status[:failures] > 0 || status[:errors] > 0
+          passed << test if status[:failures] == 0 && status[:errors] == 0
         end
-        failed
+        passed
       end
     end
 
@@ -176,7 +176,7 @@
   end
 
 
-  # TestNG test framework.
+  # TestNG test framework.  To use in your project:
   #   test.using :testng
   #
   # Support the following options:
@@ -192,32 +192,34 @@
     # that match this pattern are used.
     TESTS_PATTERN = [ /^Test/, /Test$/, /TestCase$/ ]
 
-    def initialize #:nodoc:
-      super :requires=>REQUIRES
-    end
+    class << self
+
+      def applies_to?(project) #:nodoc:
+        project.test.compile.language == :java
+      end
 
-    def supports?(project) #:nodoc:
-      project.test.compile.language == :java
     end
 
-    def tests(path) #:nodoc:
-      # Ignore anonymous classes.
-      base = Pathname.new(path)
-      candidates = super(path).map { |file| Pathname.new(file).relative_path_from(base).to_s.ext('').gsub(File::SEPARATOR, ',') }.
-        reject { |name| name =~ /\$/ }.select { |name| TESTS_PATTERN.any? { |pattern| name =~ pattern } }
+    def tests(project) #:nodoc:
+      return [] unless project.test.compile.target
+      target = Pathname.new(project.test.compile.target.to_s)
+      Dir["#{target}/**/*.class"].
+        map { |file| Pathname.new(file).relative_path_from(target).to_s.ext('').gsub(File::SEPARATOR, '.') }.
+        reject { |name| name =~ /\$/ }.select { |name| cls_name = name.split('.').last
+                                                       TESTS_PATTERN.any? { |pattern| cls_name =~ pattern } }
     end
 
     def run(tests, task, dependencies) #:nodoc:
       cmd_args = [ 'org.testng.TestNG', '-sourcedir', task.compile.sources.join(';'), '-suitename', task.send(:project).name ]
       cmd_args << '-d' << task.report_to.to_s
-      cmd_options = { :properties=>task.options[:properties], :java_args=>task.options[:java_args],
+      cmd_options = { :properties=>options[:properties], :java_args=>options[:java_args],
                       :classpath=>dependencies }
-      tests.inject([]) do |failed, test|
+      tests.inject([]) do |passed, test|
         begin
           Buildr.java cmd_args, '-testclass', test, cmd_options.merge(:name=>test)
-          failed
+          passed << test
         rescue
-          failed << test
+          passed
         end
       end
     end

Modified: incubator/buildr/trunk/spec/compile_spec.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/compile_spec.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/compile_spec.rb (original)
+++ incubator/buildr/trunk/spec/compile_spec.rb Fri Jan 11 16:48:12 2008
@@ -93,7 +93,7 @@
 
   it 'should attempt to identify compiler if sources are specified' do
     define 'foo' do
-      Compiler.compilers.first.should_receive(:applies_to?)
+      Compiler.compilers.first.should_receive(:applies_to?).at_least(:once)
       compile.from('sources').compiler
     end
   end

Modified: incubator/buildr/trunk/spec/java_compilers.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/java_compilers.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/java_compilers.rb (original)
+++ incubator/buildr/trunk/spec/java_compilers.rb Fri Jan 11 16:48:12 2008
@@ -3,7 +3,7 @@
 
 describe 'javac compiler' do
   it 'should identify itself from source directories' do
-    write 'src/main/java/Test.java', 'class Test {}' 
+    write 'src/main/java/com/example/Test.java', 'package com.example; class Test {}' 
     define('foo').compile.compiler.should eql(:javac)
   end
 
@@ -192,17 +192,6 @@
         compile.options.deprecation.should be_true
         compile.options.source.should eql('1.5')
         compile.options.target.should eql('1.4')
-      end
-    end
-  end
-
-  it 'should only inherit options it knows' do
-    define 'foo' do
-      compile.using(:warnings=>true, :errors=>true)
-      define 'bar' do
-        compile.using(:javac)
-        compile.options.warnings.should be_true
-        compile.options.errors.should be_nil
       end
     end
   end

Modified: incubator/buildr/trunk/spec/java_test_frameworks.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/java_test_frameworks.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/java_test_frameworks.rb (original)
+++ incubator/buildr/trunk/spec/java_test_frameworks.rb Fri Jan 11 16:48:12 2008
@@ -2,7 +2,14 @@
 
 
 describe Buildr::JUnit do
-  it 'should be the default test framework when test cases are in java'
+  it 'should be the default test framework when test cases are in java' do
+    write 'src/test/java/com/exampe/FirstTest.java', <<-JAVA
+      package com.example;
+      public class FirstTest extends junit.framework.TestCase { }
+    JAVA
+    define 'foo'
+    project('foo').test.framework.should eql(:junit)
+  end
 
   it 'should be picked if the test language is Java' do
     define 'foo' do
@@ -24,14 +31,16 @@
   end
 
   it 'should include public classes extending junit.framework.TestCase' do
-    write 'src/test/java/FirstTest.java', <<-JAVA
+    write 'src/test/java/com/example/FirstTest.java', <<-JAVA
+      package com.example;
       public class FirstTest extends junit.framework.TestCase { }
     JAVA
-    write 'src/test/java/AnotherOne.java', <<-JAVA
+    write 'src/test/java/com/example/AnotherOne.java', <<-JAVA
+      package com.example;
       public class AnotherOne extends junit.framework.TestCase { }
     JAVA
     define('foo').test.compile.invoke
-    project('foo').test.tests.should include('FirstTest', 'AnotherOne')
+    project('foo').test.tests.should include('com.example.FirstTest', 'com.example.AnotherOne')
   end
 
   it 'should ignore classes not extending junit.framework.TestCase' do
@@ -55,21 +64,31 @@
 
   it 'should pass when JUnit test case passes' do
     write 'src/test/java/PassingTest.java', <<-JAVA
-      public class PassingTest extends junit.framework.TestCase { public void testNothing() {}  }
+      public class PassingTest extends junit.framework.TestCase {
+        public void testNothing() {}
+      }
     JAVA
     lambda { define('foo').test.invoke }.should_not raise_error
   end
 
   it 'should fail when JUnit test case fails' do
     write 'src/test/java/FailingTest.java', <<-JAVA
-      public class FailingTest extends junit.framework.TestCase { public void testFailure() { assertTrue(false); } }
+      public class FailingTest extends junit.framework.TestCase {
+        public void testFailure() {
+          assertTrue(false);
+        }
+      }
     JAVA
     lambda { define('foo').test.invoke }.should raise_error(RuntimeError, /Tests failed/) rescue nil
   end
 
   it 'should report failed test names' do
     write 'src/test/java/FailingTest.java', <<-JAVA
-      public class FailingTest extends junit.framework.TestCase { public void testFailure() { assertTrue(false); } }
+      public class FailingTest extends junit.framework.TestCase {
+        public void testFailure() {
+          assertTrue(false);
+        }
+      }
     JAVA
     define('foo').test.invoke rescue
     project('foo').test.failed_tests.should include('FailingTest')
@@ -77,7 +96,9 @@
 
   it 'should report to reports/junit' do
     write 'src/test/java/PassingTest.java', <<-JAVA
-      public class PassingTest extends junit.framework.TestCase { public void testNothing() {} }
+      public class PassingTest extends junit.framework.TestCase {
+        public void testNothing() {}
+      }
     JAVA
     define 'foo' do
       test.report_to.should be(file('reports/junit'))
@@ -124,12 +145,18 @@
     JAVA
     write 'src/test/java/TestCase1.java', <<-JAVA
       public class TestCase1 extends junit.framework.TestCase {
-        public void testSameVM() { assertFalse(Shared.flag); Shared.flag = true; }
+        public void testSameVM() {
+          assertFalse(Shared.flag);
+          Shared.flag = true;
+        }
       }
     JAVA
     write 'src/test/java/TestCase2.java', <<-JAVA
       public class TestCase2 extends junit.framework.TestCase {
-        public void testSameVM() { assertFalse(Shared.flag); Shared.flag = true; }
+        public void testSameVM() {
+          assertFalse(Shared.flag);
+          Shared.flag = true;
+        }
       }
     JAVA
     define 'foo' do
@@ -151,7 +178,6 @@
 
 
 describe Buildr::JUnit, 'report' do
-
   it 'should default to the target directory reports/junit' do
     JUnit.report.target.should eql('reports/junit')
   end
@@ -187,8 +213,11 @@
   end
 
   it 'should generate reports from all projects that ran test cases' do
-    write 'src/test/java/TestSomething.java',
-      'public class TestSomething extends junit.framework.TestCase { public void testNothing() {} }'
+    write 'src/test/java/TestSomething.java', <<-JAVA
+      public class TestSomething extends junit.framework.TestCase {
+        public void testNothing() {}
+      }
+    JAVA
     define 'foo'
     project('foo').test.invoke
     task('junit:report').invoke
@@ -202,65 +231,112 @@
 
 
 describe Buildr::TestNG do
-  before do
-    write 'src/test/java/PassingTest.java', 
-      'public class PassingTest { @org.testng.annotations.Test public void testNothing() {} }'
-    write 'src/test/java/FailingTest.java', 
-      'public class FailingTest { @org.testng.annotations.Test public void testNothing() { org.testng.AssertJUnit.assertTrue(false); } }'
-    define('foo') { test.using :testng }
+  it 'should be selectable in project' do
+    define 'foo' do
+      test.using(:testng)
+      test.framework.should eql(:testng)
+    end
   end
 
-
-  it 'should be selectable in parent project'
+  it 'should be selectable in parent project' do
+    write 'bar/src/test/java/TestCase.java'
+    define 'foo' do
+      test.using(:testng)
+      define 'bar'
+    end
+    project('foo:bar').test.framework.should eql(:testng)
+  end
 
   it 'should include TestNG dependencies' do
+    define('foo') { test.using :testng }
     project('foo').test.compile.dependencies.should include(*artifacts(TestNG::REQUIRES))
     project('foo').test.dependencies.should include(*artifacts(TestNG::REQUIRES))
   end
 
   it 'should include TestNG dependencies' do
+    define('foo') { test.using :testng }
     project('foo').test.compile.dependencies.should include(*artifacts(JMock::REQUIRES))
     project('foo').test.dependencies.should include(*artifacts(JMock::REQUIRES))
   end
 
   it 'should include classes starting with and ending with Test' do
-    ['TestThis', 'ThisTest', 'ThisThat'].each do |name|
-      write File.join(project('foo').test.compile.target.to_s, name).ext('class')
-    end
-    project('foo').test.tests.map { |file| File.basename(file) }.should == ['TestThis', 'ThisTest']
+    write 'src/test/java/com/example/TestThis.java', 'package com.example; public class TestThis {}'
+    write 'src/test/java/com/example/ThisTest.java', 'package com.example; public class ThisTest {}'
+    define('foo') { test.using(:testng) }
+    project('foo').test.compile.invoke
+    project('foo').test.tests.should include('com.example.TestThis', 'com.example.ThisTest')
+  end
+
+  it 'should ignore classes not using Test prefix or suffix' do
+    write 'src/test/java/NotATestClass.java', 'public class NotATestClass {}'
+    define('foo') { test.using(:testng) }
+    project('foo').test.compile.invoke
+    project('foo').test.tests.should be_empty
   end
 
   it 'should ignore inner classes' do
-    ['TestThis', 'TestThis$Innner'].each do |name|
-      write "target/test/classes/#{name}.class"
-    end
-    project('foo').test.tests.map { |file| File.basename(file) }.should == ['TestThis']
+    write 'src/test/java/InnerClassTest.java', <<-JAVA
+      public class InnerClassTest {
+        public class InnerTest {
+        }
+      }
+    JAVA
+    define('foo') { test.using(:testng) }
+    project('foo').test.compile.invoke
+    project('foo').test.tests.should eql(['InnerClassTest'])
   end
 
   it 'should pass when TestNG test case passes' do
-    project('foo').test.include 'PassingTest'
+    write 'src/test/java/PassingTest.java', <<-JAVA
+      public class PassingTest {
+        @org.testng.annotations.Test
+        public void testNothing() {}
+      }
+    JAVA
+    define('foo') { test.using(:testng) }
     lambda { project('foo').test.invoke }.should_not raise_error
   end
 
   it 'should fail when TestNG test case fails' do
-    project('foo').test.include 'FailingTest'
+    write 'src/test/java/FailingTest.java', <<-JAVA
+      public class FailingTest {
+        @org.testng.annotations.Test
+        public void testNothing() {
+          org.testng.AssertJUnit.assertTrue(false);
+        }
+      }
+    JAVA
+    define('foo') { test.using(:testng) }
     lambda { project('foo').test.invoke }.should raise_error(RuntimeError, /Tests failed/)
   end
 
   it 'should report failed test names' do
-    project('foo').test.include 'FailingTest'
-    project('foo').test.invoke rescue
-    project('foo').test.failed_tests.should eql(['FailingTest'])
+    write 'src/test/java/FailingTest.java', <<-JAVA
+      public class FailingTest {
+        @org.testng.annotations.Test
+        public void testNothing() {
+          org.testng.AssertJUnit.assertTrue(false);
+        }
+      }
+    JAVA
+    define('foo') { test.using(:testng) }
+    project('foo').test.invoke rescue nil
+    project('foo').test.failed_tests.should include('FailingTest')
   end
 
   it 'should report to reports/testng' do
+    define('foo') { test.using(:testng) }
     project('foo').test.report_to.should be(project('foo').file('reports/testng'))
   end
 
   it 'should generate reports' do
-    project('foo').test.include 'PassingTest'
-    lambda { project('foo').test.invoke }.should change { File.exist?(project('foo').test.report_to.to_s) }.to(true)
+    write 'src/test/java/PassingTest.java', <<-JAVA
+      public class PassingTest {
+        @org.testng.annotations.Test
+        public void testNothing() {}
+      }
+    JAVA
+    define('foo') { test.using(:testng) }
+    lambda { project('foo').test.invoke }.should change { File.exist?('reports/testng/foo/index.html') }.to(true)
   end
 end
-
-

Modified: incubator/buildr/trunk/spec/sandbox.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/sandbox.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/sandbox.rb (original)
+++ incubator/buildr/trunk/spec/sandbox.rb Fri Jan 11 16:48:12 2008
@@ -3,7 +3,7 @@
 # repository and cache these across test cases.
 repositories.remote << 'http://repo1.maven.org/maven2'
 Java.load # Anything added to the classpath.
-artifacts(TestFramework.frameworks.map(&:requires).flatten).each { |a| file(a).invoke }
+artifacts(TestFramework.frameworks.map(&:dependencies).flatten).each { |a| file(a).invoke }
 task('buildr:initialize').invoke
 
 # We need to run all tests inside a sandbox, tacking a snapshot of Rake/Buildr before the test,

Modified: incubator/buildr/trunk/spec/spec_helpers.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/spec_helpers.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/spec_helpers.rb (original)
+++ incubator/buildr/trunk/spec/spec_helpers.rb Fri Jan 11 16:48:12 2008
@@ -142,7 +142,7 @@
     # For example:
     #   lambda { task('build').invoke }.should run_task('test')
     def run_task(task)
-      InvokeMatcher.new task.to_a.first
+      InvokeMatcher.new [task]
     end
 
     class UriPathMatcher

Modified: incubator/buildr/trunk/spec/test_spec.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/test_spec.rb?rev=611339&r1=611338&r2=611339&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/test_spec.rb (original)
+++ incubator/buildr/trunk/spec/test_spec.rb Fri Jan 11 16:48:12 2008
@@ -189,11 +189,6 @@
     define('foo').test.dependencies.should include(project('foo').test.resources.target)
   end
 
-  it 'should include test framework dependencies' do
-    define('foo') {  test.using(:junit) }
-    project('foo').test.dependencies.should include(*artifacts(project('foo').test.requires))
-  end
-
   it 'should clean after itself (test files)' do
     define('foo') { test.compile.using(:javac) }
     mkpath project('foo').test.compile.target.to_s
@@ -218,17 +213,14 @@
   end
   
   it 'should return no failed tests' do
-    define('foo').test.invoke
+    define('foo') { test.using(:junit) }
+    project('foo').test.invoke
     project('foo').test.failed_tests.should be_empty
   end
 
   it 'should return no passing tests' do
-    define('foo').test.invoke
-    project('foo').test.passed_tests.should be_empty
-  end
-
-  it 'should report no passed tests' do
-    define('foo').test.invoke
+    define('foo') { test.using(:junit) }
+    project('foo').test.invoke
     project('foo').test.passed_tests.should be_empty
   end
 
@@ -239,84 +231,95 @@
 
 
 describe Buildr::TestTask, 'with passing tests' do
-  before do
-    @tests = ['PassingTest1', 'PassingTest2']
-    define 'foo'
-    project('foo').test.stub!(:tests).and_return @tests
-    project('foo').test.instance_eval do
-      @framework.stub!(:run).and_return []
+  def tests
+    @tests ||= ['PassingTest1', 'PassingTest2']
+  end
+
+  def test_task
+    @test_task ||= begin
+      tests = self.tests
+      define 'foo' do
+        test.using(:junit)
+        test.stub!(:tests).and_return(tests.clone)
+        test.instance_eval { @framework.stub!(:run).and_return(tests.clone) }
+      end
+      project('foo').test
     end
   end
 
   it 'should pass' do
-    lambda { project('foo').test.invoke }.should_not raise_error
+    lambda { test_task.invoke }.should_not raise_error
   end
 
   it 'should report no failed tests' do
-    lambda { verbose(true) { project('foo').test.invoke } }.should_not warn_that(/fail/i)
+    lambda { verbose(true) { test_task.invoke } }.should_not warn_that(/fail/i)
   end
   
   it 'should return passed tests' do
-    project('foo').test.invoke
-    project('foo').test.passed_tests.should == @tests
+    test_task.invoke
+    test_task.passed_tests.should == tests
   end
 
   it 'should return no failed tests' do
-    project('foo').test.invoke
-    project('foo').test.failed_tests.should be_empty
+    test_task.invoke
+    test_task.failed_tests.should be_empty
   end
 
   it 'should execute teardown task' do
-    lambda { project('foo').test.invoke }.should run_task('foo:test:teardown')
+    lambda { test_task.invoke }.should run_task('foo:test:teardown')
   end
 end
 
 
 describe Buildr::TestTask, 'with failed test' do
-  before do
-    @tests = ['FailingTest1', 'FailingTest2']
-    define 'foo'
-    project('foo').test.stub!(:tests).and_return @tests
-    project('foo').test.instance_eval do
-      @framework.stub!(:run).and_return ['FailingTest1']
+  def test_task
+    @test_task ||= begin
+      define 'foo' do
+        test.using(:junit)
+        test.instance_eval do
+          @framework.stub!(:tests).and_return(['FailingTest', 'PassingTest'])
+          @framework.stub!(:run).and_return(['PassingTest'])
+        end
+      end
+      project('foo').test
     end
   end
 
   it 'should fail' do
-    lambda { project('foo').test.invoke }.should raise_error(RuntimeError, /Tests failed/)
+    lambda { test_task.invoke }.should raise_error(RuntimeError, /Tests failed/)
   end
 
   it 'should report failed tests' do
-    lambda { verbose(true) { project('foo').test.invoke rescue nil } }.should warn_that(/FailingTest1/)
+    lambda { verbose(true) { test_task.invoke rescue nil } }.should warn_that(/FailingTest/)
   end
 
   it 'should return failed tests' do
-    project('foo').test.invoke rescue nil
-    project('foo').test.failed_tests.should == ['FailingTest1']
+    test_task.invoke rescue nil
+    test_task.failed_tests.should == ['FailingTest']
   end
 
   it 'should return passing tests as well' do
-    project('foo').test.invoke rescue nil
-    project('foo').test.passed_tests.should == ['FailingTest2']
+    test_task.invoke rescue nil
+    test_task.passed_tests.should == ['PassingTest']
   end
 
   it 'should not fail if fail_on_failure is false' do
-    project('foo').test.using(:fail_on_failure=>false).invoke
-    lambda { project('foo').test.invoke }.should_not raise_error
+    test_task.using(:fail_on_failure=>false).invoke
+    lambda { test_task.invoke }.should_not raise_error
   end
 
   it 'should report failed tests even if fail_on_failure is false' do
-    project('foo').test.using(:fail_on_failure=>false)
-    lambda { verbose(true) { project('foo').test.invoke } }.should warn_that(/FailingTest1/)
+    test_task.using(:fail_on_failure=>false)
+    lambda { verbose(true) { test_task.invoke } }.should warn_that(/FailingTest/)
   end
 
   it 'should return failed tests even if fail_on_failure is false' do
-    project('foo').test.using(:fail_on_failure=>false).invoke
-    project('foo').test.failed_tests.should == ['FailingTest1']
+    test_task.using(:fail_on_failure=>false).invoke
+    test_task.failed_tests.should == ['FailingTest']
   end
 
   it 'should execute teardown task' do
-    lambda { project('foo').test.invoke rescue nil }.should run_task('foo:test:teardown')
+    lambda { test_task.invoke rescue nil }.should run_task('foo:test:teardown')
   end
 end
 
@@ -379,7 +382,7 @@
 
 describe Buildr::Project, '#test.compile' do
   it 'should identify compiler from project' do
-    write 'src/test/java/Test.java'
+    write 'src/test/java/com/example/Test.java'
     define('foo') do
       test.compile.compiler.should eql(:javac)
     end
@@ -418,8 +421,9 @@
   it 'should include the test framework dependencies' do
     define 'foo' do
       test.compile.using(:javac)
+      test.using(:junit)
     end
-    project('foo').test.compile.dependencies.should include(*artifacts(project('foo').test.requires))
+    project('foo').test.compile.dependencies.should include(*artifacts(JUnit.dependencies))
   end
 
   it 'should clean after itself' do
@@ -525,35 +529,49 @@
   end
 
   it 'should reset tasks to specific pattern' do
-    define('foo') { define 'bar' }
+    define 'foo' do
+      test.using(:junit)
+      test.instance_eval { @framework.stub!(:tests).and_return(['something', 'nothing']) }
+      define 'bar' do
+        test.using(:junit)
+        test.instance_eval { @framework.stub!(:tests).and_return(['something', 'nothing']) }
+      end
+    end
     task('test:something').invoke
     ['foo', 'foo:bar'].map { |name| project(name) }.each do |project|
-      project.test.include?('something').should be_true
-      project.test.include?('nothing').should be_false
-      project.test.include?('SomeTest').should be_false
+      project.test.tests.should include('something')
+      project.test.tests.should_not include('nothing')
     end
   end
 
   it 'should apply *name* pattern' do
-    define 'foo'
+    define 'foo' do
+      test.using(:junit)
+      test.instance_eval { @framework.stub!(:tests).and_return(['prefix-something-suffix']) }
+    end
     task('test:something').invoke
-    project('foo').test.include?('prefix-something-suffix').should be_true
-    project('foo').test.include?('prefix-nothing-suffix').should be_false
+    project('foo').test.tests.should include('prefix-something-suffix')
   end
 
   it 'should not apply *name* pattern if asterisks used' do
-    define 'foo'
+    define 'foo' do
+      test.using(:junit)
+      test.instance_eval { @framework.stub!(:tests).and_return(['prefix-something', 'prefix-something-suffix']) }
+    end
     task('test:*something').invoke
-    project('foo').test.include?('prefix-something').should be_true
-    project('foo').test.include?('prefix-something-suffix').should be_false
+    project('foo').test.tests.should include('prefix-something')
+    project('foo').test.tests.should_not include('prefix-something-suffix')
   end
 
   it 'should accept multiple tasks separated by commas' do
-    define 'foo'
+    define 'foo' do
+      test.using(:junit)
+      test.instance_eval { @framework.stub!(:tests).and_return(['foo', 'bar', 'baz']) }
+    end
     task('test:foo,bar').invoke
-    project('foo').test.include?('foo').should be_true
-    project('foo').test.include?('bar').should be_true
-    project('foo').test.include?('baz').should be_false
+    project('foo').test.tests.should include('foo')
+    project('foo').test.tests.should include('bar')
+    project('foo').test.tests.should_not include('baz')
   end
 
   it 'should execute only the named tasts' do
@@ -727,11 +745,11 @@
   it 'should run test actions marked for integration' do
     task 'action'
     define 'foo' do
-      test.using :integration
-      test { task('action').invoke }
+      test.using :integration, :junit
     end
-    lambda { task('test').invoke }.should run_tasks().but_not('action')
-    lambda { task('integration').invoke }.should run_task('action')
+    lambda { task('test').invoke }.should_not change { project('foo').test.passed_tests }
+    lambda { task('integration').invoke }.should change { project('foo').test.passed_tests }
+    project('foo').test.passed_tests.should be_empty
   end
 
   it 'should not fail if test=all' do
@@ -772,43 +790,58 @@
 
 
 describe 'integration rule' do
-  before do
+  it 'should execute integration tests on local project' do
     define 'foo' do
-      test.using :integration
+      test.using :junit, :integration
       define 'bar'
     end
-  end
-
-  it 'should execute integration tests on local project' do
     lambda { task('integration:something').invoke }.should run_task('foo:test')
   end
 
   it 'should reset tasks to specific pattern' do
+    define 'foo' do
+      test.using :junit, :integration
+      test.instance_eval { @framework.stub!(:tests).and_return(['something', 'nothing']) }
+      define 'bar' do
+        test.using :junit, :integration
+        test.instance_eval { @framework.stub!(:tests).and_return(['something', 'nothing']) }
+      end
+    end
     task('integration:something').invoke
     ['foo', 'foo:bar'].map { |name| project(name) }.each do |project|
-      project.test.include?('something').should be_true
-      project.test.include?('nothing').should be_false
-      project.test.include?('SomeTest').should be_false
+      project.test.tests.should include('something')
+      project.test.tests.should_not include('nothing')
     end
   end
 
   it 'should apply *name* pattern' do
+    define 'foo' do
+      test.using :junit, :integration
+      test.instance_eval { @framework.stub!(:tests).and_return(['prefix-something-suffix']) }
+    end
     task('integration:something').invoke
-    project('foo').test.include?('prefix-something-suffix').should be_true
-    project('foo').test.include?('prefix-nothing-suffix').should be_false
+    project('foo').test.tests.should include('prefix-something-suffix')
   end
 
   it 'should not apply *name* pattern if asterisks used' do
+    define 'foo' do
+      test.using :junit, :integration
+      test.instance_eval { @framework.stub!(:tests).and_return(['prefix-something', 'prefix-something-suffix']) }
+    end
     task('integration:*something').invoke
-    project('foo').test.include?('prefix-something').should be_true
-    project('foo').test.include?('prefix-something-suffix').should be_false
+    project('foo').test.tests.should include('prefix-something')
+    project('foo').test.tests.should_not include('prefix-something-suffix')
   end
 
   it 'should accept multiple tasks separated by commas' do
+    define 'foo' do
+      test.using :junit, :integration
+      test.instance_eval { @framework.stub!(:tests).and_return(['foo', 'bar', 'baz']) }
+    end
     task('integration:foo,bar').invoke
-    project('foo').test.include?('foo').should be_true
-    project('foo').test.include?('bar').should be_true
-    project('foo').test.include?('baz').should be_false
+    project('foo').test.tests.should include('foo')
+    project('foo').test.tests.should include('bar')
+    project('foo').test.tests.should_not include('baz')
   end
 
   it 'should execute only the named tasts' do