Author: boisvert
Date: Mon Jun  9 20:53:14 2008
New Revision: 665967

URL: http://svn.apache.org/viewvc?rev=665967&view=rev
Log:
BUILDR-85: Add support for ScalaTest, ScalaCheck and Specs testing frameworks

Added:
    incubator/buildr/trunk/spec/scala_test_frameworks_spec.rb
Modified:
    incubator/buildr/trunk/lib/buildr/java/compilers.rb
    incubator/buildr/trunk/lib/buildr/java/test_frameworks.rb

Modified: incubator/buildr/trunk/lib/buildr/java/compilers.rb
URL: 
http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/java/compilers.rb?rev=665967&r1=665966&r2=665967&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/buildr/java/compilers.rb (original)
+++ incubator/buildr/trunk/lib/buildr/java/compilers.rb Mon Jun  9 20:53:14 2008
@@ -119,7 +119,7 @@
       end
 
       OPTIONS = [:warnings, :deprecation, :optimise, :target, :debug, :other]
-      Java.classpath << dependencies unless Scalac.use_fsc
+      Java.classpath << dependencies
 
       specify :language=>:scala, :target=>'classes', :target_ext=>'class', 
:packaging=>:jar
 

Modified: incubator/buildr/trunk/lib/buildr/java/test_frameworks.rb
URL: 
http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/java/test_frameworks.rb?rev=665967&r1=665966&r2=665967&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/buildr/java/test_frameworks.rb (original)
+++ incubator/buildr/trunk/lib/buildr/java/test_frameworks.rb Mon Jun  9 
20:53:14 2008
@@ -90,7 +90,22 @@
     REQUIRES = ["jmock:jmock:jar:#{VERSION}"]
   end
 
+  # Specs is available when using ScalaTest
+  module ScalaSpecs
+    # Specs version number.
+    VERSION = '1.2.9' unless const_defined?('VERSION')
+    # Specs artifact(s)
+    REQUIRES = ["org.specs:specs:jar:#{VERSION}"]
+  end
 
+  # ScalaCheck is available when using ScalaTest
+  module ScalaCheck
+    # ScalaCheck version number.
+    VERSION = '1.3' unless const_defined?('VERSION')
+    # ScalaCheck artifact(s)
+    REQUIRES = ["org.scalacheck:scalacheck:jar:#{VERSION}"]
+  end
+  
   # JUnit test framework, the default test framework for Java tests.
   #
   # Support the following options:
@@ -249,7 +264,7 @@
   class TestNG < TestFramework::Base
 
     # TestNG version number.
-    VERSION = '5.5' unless const_defined?('VERSION')
+    VERSION = '5.7' unless const_defined?('VERSION')
     # TestNG specification.
     REQUIRES = ["org.testng:testng:jar:jdk15:#{VERSION}"] + JMock::REQUIRES
 
@@ -278,11 +293,131 @@
 
   end
 
-end
+  # ScalaTest framework, the default test framework for Scala tests.
+  #
+  # Support the following options:
+  # * :properties  -- Hash of system properties available to the test case.
+  # * :environment -- Hash of environment variables available to the test case.
+  # * :java_args   -- Arguments passed as is to the JVM.
+  class ScalaTest < TestFramework::Base
+    
+    # ScalaTest version number.
+    VERSION = '0.9.3' unless const_defined?('VERSION')
+    
+    # ScalaTest dependencies
+    REQUIRES = ["org.scalatest:scalatest:jar:#{VERSION}"] + 
+               JMock::REQUIRES + 
+               ScalaSpecs::REQUIRES + 
+               ScalaCheck::REQUIRES
+
+    # ScalaTest ant task
+    Java.classpath << "org.apache.ant:ant-junit:jar:#{Ant::VERSION}"
+    Java.classpath << "org.scalatest:scalatest:jar:#{VERSION}"
+    #Java.classpath << REQUIRES
+
+    include TestFramework::JavaTest
+
+    # annotation-based group inclusion
+    attr_accessor :group_includes
+    
+    # annotation-based gropu exclusion
+    attr_accessor :group_excludes
+    
+    def initialize(test_task, options)
+      super
+      @group_includes = []
+      @group_excludes = []
+    end
+
+    def tests(dependencies) #:nodoc:
+      suites = filter_classes(dependencies, :interfaces => 
%w{org.scalatest.Suite})
+      # we should really filter using :class => %w{org.specs.Specification} 
instead of naming convention
+      specs = filter_classes(dependencies, :class_names => [/Specs?$/])
+      [suites, specs].flatten
+    end
+
+    def run(tests, dependencies) #:nodoc:
+      mkpath task.report_to.to_s
+      success = []
+      scalatest = tests.select { |t| t !~ /Specs?$/ }
+      specs = tests.select { |t| t =~ /Specs?$/ }
+
+      # Specs
+      #options = { :nostacktrace => false }.merge(options)
+      nostacktrace = (options[:nostacktrace]) ? "-ns" : ""
+      cmd_options = { :properties => options[:properties],
+                      :java_args => options[:java_args],
+                      :classpath => dependencies}
+      specs.each do |spec|
+        Java.load
+        begin
+          Java::Commands.java(spec, {:classpath => dependencies})
+        rescue => e
+          print e.message
+        else
+          success << spec
+        end
+      end
+
+      # ScalaTest
+      reporter_options = 'TFGBSAR' # testSucceeded, testFailed, testIgnored, 
suiteAborted, runStopped, runAborted, runCompleted
+      scalatest.each do |suite|
+        puts "ScalaTest #{suite.inspect}" if verbose
+        # Use Ant to execute the ScalaTest task, gives us performance and 
reporting.
+        reportFile = File.join(task.report_to.to_s, "TEST-#{suite}.txt")
+        Buildr.ant('scalatest') do |ant|
+          ant.taskdef :name=>'scalatest', 
:classname=>'org.scalatest.tools.ScalaTestTask'
+          ant.scalatest :runpath=>dependencies.join(File::PATH_SEPARATOR) do
+            ant.suite    :classname=>suite
+            ant.reporter :type=>'stdout', :config=>reporter_options
+            ant.reporter :type=>'file', :filename=> reportFile, 
:config=>reporter_options
+            ant.includes group_includes.join(" ") if group_includes
+            ant.excludes group_excludes.join(" ") if group_excludes
+            (options[:properties] || []).each { |name, value| ant.property 
:name=>name, :value=>value }
+          end
+        end
+        
+        # Parse for failures, errors, etc.
+        # This is a bit of a pain right now because ScalaTest doesn't flush its
+        # output synchronously before the Ant test finishes so we have to loop 
+        # and wait for an indication that the test run was completed. 
+        failed = false
+        completed = false
+        wait = 0
+        while (!completed) do
+          File.open(reportFile, "r") do |input|
+            while (line = input.gets) do
+              failed = (line =~ /(TEST FAILED -)|(RUN STOPPED)|(RUN ABORTED)/) 
unless failed
+              completed |= (line =~ /Run completed\./)
+              break if (failed || completed)
+            end
+          end
+          wait += 1
+          break if (failed || wait > 10) 
+          unless completed
+            sleep(1)
+          end
+        end
+        success << suite if (completed && !failed)
+      end
+      
+      success
+    end # run
+
+    class << self
+      def applies_to?(project) #:nodoc:
+        project.test.compile.language == :scala
+      end        
+    end
+
+  end # ScalaTest
+
+end # Buildr
 
 
 Buildr::TestFramework << Buildr::JUnit
 Buildr::TestFramework << Buildr::TestNG
+Buildr::TestFramework << Buildr::ScalaTest
 
 # Backward compatibility crap.
 Buildr::JUnit::JUNIT_REQUIRES = Buildr::JUnit::REQUIRES

Added: incubator/buildr/trunk/spec/scala_test_frameworks_spec.rb
URL: 
http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/scala_test_frameworks_spec.rb?rev=665967&view=auto
==============================================================================
--- incubator/buildr/trunk/spec/scala_test_frameworks_spec.rb (added)
+++ incubator/buildr/trunk/spec/scala_test_frameworks_spec.rb Mon Jun  9 
20:53:14 2008
@@ -0,0 +1,216 @@
+# 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')
+
+
+# TODO's
+#  -test w/ Specs
+#  -test w/ ScalaCheck
+#  -failing test
+#  -test passing System props
+#  -test passing ENV variables
+#  -test exclude group
+#  -test include Suite's
+#  -test exclude Suite's
+
+
+describe Buildr::ScalaTest do
+  it 'should be the default test framework when test cases are in Scala' do
+    write 'src/test/scala/com/example/MySuite.scala', <<-SCALA
+      package com.example
+      import org.scalatest.FunSuite
+      class MySuite extends FunSuite {
+        test("addition") {
+          val sum = 1 + 1
+          assert(sum === 2)
+        }
+      }
+    SCALA
+    define 'foo'
+    project('foo').test.framework.should eql(:scalatest)
+  end
+
+  it 'should be picked if the test language is Scala' do
+    define 'foo' do
+      test.compile.using(:scalac)
+      test.framework.should eql(:scalatest)
+    end
+  end
+
+  it 'should include Scalatest dependencies' do
+    define('foo') { test.using(:scalatest) }
+    project('foo').test.compile.dependencies.should 
include(*artifacts(ScalaTest::REQUIRES))
+    project('foo').test.dependencies.should 
include(*artifacts(ScalaTest::REQUIRES))
+  end
+
+  it 'should include JMock dependencies' do
+    define('foo') { test.using(:scalatest) }
+    project('foo').test.compile.dependencies.should 
include(*artifacts(JMock::REQUIRES))
+    project('foo').test.dependencies.should 
include(*artifacts(JMock::REQUIRES))
+  end
+
+  it 'should include Specs dependencies' do
+    define('foo') { test.using(:scalatest) }
+    project('foo').test.compile.dependencies.should 
include(*artifacts(ScalaSpecs::REQUIRES))
+    project('foo').test.dependencies.should 
include(*artifacts(ScalaSpecs::REQUIRES))
+  end
+
+  it 'should include ScalaCheck dependencies' do
+    define('foo') { test.using(:scalatest) }
+    project('foo').test.compile.dependencies.should 
include(*artifacts(ScalaCheck::REQUIRES))
+    project('foo').test.dependencies.should 
include(*artifacts(ScalaCheck::REQUIRES))
+  end
+
+  it 'should include public classes extending org.scalatest.FunSuite' do
+    write 'src/test/scala/com/example/MySuite.scala', <<-SCALA
+      package com.example
+      import org.scalatest.FunSuite
+      class MySuite extends FunSuite {
+        test("addition") {
+          val sum = 1 + 1
+          assert(sum === 2)
+        }
+      }
+    SCALA
+    define('foo').test.invoke
+    project('foo').test.tests.should include('com.example.MySuite')
+  end
+
+  it 'should ignore classes not extending org.scalatest.FunSuite' do
+    write 'src/test/scala/com/example/NotASuite.scala', <<-SCALA
+      package com.example
+      class Another {
+      }
+    SCALA
+    define('foo').test.invoke
+    project('foo').test.tests.should be_empty
+  end
+
+  it 'should ignore inner classes' do
+    write 'src/test/scala/com/example/InnerClassTest.scala', <<-SCALA
+      package com.example
+      import org.scalatest.FunSuite
+      class InnerClassTest extends FunSuite {
+        test("addition") {
+          val sum = 1 + 1
+          assert(sum === 2)
+        }
+        
+        class InnerSuite extends FunSuite {
+          test("addition") {
+            val sum = 1 + 1
+            assert(sum === 2)
+          }
+        }
+      }
+    SCALA
+    define('foo').test.invoke
+    project('foo').test.tests.should eql(['com.example.InnerClassTest'])
+  end
+
+  it 'should pass when ScalaTest test case passes' do
+    write 'src/test/scala/PassingSuite.scala', <<-SCALA
+      class PassingSuite extends org.scalatest.FunSuite {
+        test("addition") {
+          val sum = 1 + 1
+          assert(sum === 2)
+        }
+      }
+    SCALA
+    lambda { define('foo').test.invoke }.should_not raise_error
+  end
+
+  it 'should fail when ScalaTest test case fails' do
+    write 'src/test/scala/FailingSuite.scala', <<-SCALA
+      class FailingSuite extends org.scalatest.FunSuite {
+        test("failing") {
+          assert(false)
+        }
+      }
+    SCALA
+    lambda { define('foo').test.invoke }.should raise_error(RuntimeError, 
/Tests failed/) rescue nil
+  end
+
+  it 'should report failed test names' do
+    write 'src/test/scala/FailingSuite.scala', <<-SCALA
+      class FailingSuite extends org.scalatest.FunSuite {
+        test("failing") {
+          assert(false)
+        }
+      }
+    SCALA
+    define('foo').test.invoke rescue
+    project('foo').test.failed_tests.should include('FailingSuite')
+  end
+
+  it 'should report to reports/scalatest/TEST-TestSuiteName.txt' do
+    write 'src/test/scala/PassingSuite.scala', <<-SCALA
+      class PassingSuite extends org.scalatest.FunSuite {
+        test("passing") {
+          assert(true)
+        }
+      }
+    SCALA
+    define 'foo' do
+      test.report_to.should be(file('reports/scalatest'))
+    end
+    project('foo').test.invoke
+    project('foo').file('reports/scalatest/TEST-PassingSuite.txt').should exist
+  end
+
+  it 'should pass properties to Suite' do
+    write 'src/test/scala/PropertyTestSuite.scala', <<-SCALA
+      import org.scalatest._
+      class PropertyTestSuite extends FunSuite {
+        var properties = Map[String, Any]()
+        test("testProperty") {
+          assert(properties("name") === "value")
+        }
+        
+        protected override def runTests(testName: Option[String], reporter: 
Reporter, stopper: Stopper,
+                                        includes: Set[String], excludes: 
Set[String], properties: Map[String, Any]) {
+          this.properties = properties;                              
+          super.runTests(testName, reporter, stopper, includes, excludes, 
properties)
+        }
+      }
+    SCALA
+    define('foo').test.using :properties=>{ 'name'=>'value' }
+    project('foo').test.invoke
+  end
+
+  it 'should set current directory' do
+    mkpath 'baz'
+    expected = File.expand_path('baz')
+    expected.gsub!('/', '\\') if expected =~ /^[A-Z]:/ # Java returns back 
slashed paths for windows
+    write 'baz/src/test/scala/CurrentDirectoryTestSuite.scala', <<-SCALA
+      class CurrentDirectoryTestSuite extends org.scalatest.FunSuite {
+        test("testCurrentDirectory") {
+          assert("value" === System.getenv("NAME"))
+          assert(#{expected.inspect} === new 
java.io.File(".").getCanonicalPath())
+        }
+      }
+    SCALA
+    define 'bar' do
+      define 'baz' do
+        test.include 'CurrentDirectoryTest'
+      end
+    end
+    project('bar:baz').test.invoke
+  end
+
+end
+


Reply via email to