Modified: incubator/buildr/trunk/lib/java/test.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/test.rb?rev=606399&r1=606398&r2=606399&view=diff ============================================================================== --- incubator/buildr/trunk/lib/java/test.rb (original) +++ incubator/buildr/trunk/lib/java/test.rb Fri Dec 21 23:12:32 2007 @@ -1,387 +1,19 @@ -require "core/build" -require "java/compile" -require "java/ant" -require "core/help" +require 'core/build' +require 'java/compile' +require 'java/ant' +require 'core/help' module Buildr module Java - # *Deprecated:* Use the test task directly instead of calling test.junit. - class JUnitTask < Rake::Task #:nodoc: - - # The classpath used for running the tests. Includes the compile classpath, - # compiled classes (target). For everything else, add by calling #with. - attr_accessor :classpath - - def initialize(*args) #:nodoc: - super - @parent = Rake::Task["#{name.split(":")[0...-1].join(":")}"] - end - - # :call-seq: - # include(*classes) => 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 classes. 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. - def include(*classes) - @parent.include *classes - self - end - - # :call-seq: - # exclude(*classes) => self - # - # Exclude the specified test cases. This method accepts multiple arguments and returns self. - # See #include for the type of arguments you can use. - def exclude(*classes) - @parent.exclude *classes - self - end - - # :call-seq: - # from(*paths) => self - # - # Specify one or more directories that include test cases. - def from(*files) - self - end - - # :call-seq: - # with(*specs) => self - # - # Specify artifacts (specs, tasks, files, etc) to include in the classpath when running - # the test cases. - def with(*files) - (@parent.options[:classpath] ||= []).concat files.flatten - self - end - - # Returns the JUnit options. - def options() - @parent.options - end - - # :call-seq: - # using(options) => self - # - # Sets the JUnit options from a hash and returns self. Right now supports passing :properties to JUnit, - # and :java_args to the JVM. - # - # For example: - # test.junit.using :properties=>{ "root"=>base_dir } - def using(options) - @parent.using options - self - end - - end - - - # The test task controls the entire test lifecycle. - # - # 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 classpath - # dependencies using #with, or include only specific test cases 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 - class TestTask < Rake::Task - - class << self - - # Used by the local test and integration tasks to - # a) Find the local project(s), - # b) Find all its sub-projects and narrow down to those that have either unit or integration tests, - # c) Run all the (either unit or integration) tests, and - # d) Ignore failure if necessary. - def run_local_tests(integration) #:nodoc: - Project.local_projects do |project| - # !(foo ^ bar) tests for equality and accepts nil as false (and select is less obfuscated than reject on ^). - projects = ([project] + project.projects).select { |project| !(project.test.options[:integration] ^ integration) } - projects.each do |project| - puts "Testing #{project.name}" if verbose - begin - project.test.invoke - rescue - raise unless Buildr.options.test == :all - end - end - end - end - - # 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 - # all sub-projects, but only invoke test on the local project. - Project.projects.each { |project| project.test.instance_eval { @include = tests ; @exclude.clear } } - end - end - - # List of supported test framework, first one being a default. Test frameworks are added by - # including them in TestTask (e.g. JUnit, TestNG). - TEST_FRAMEWORKS = [] - - # Default options already set on each test task. - DEFAULT_OPTIONS = { :fail_on_failure=>true, :fork=>:once, :properties=>{}, :environment=>{} } - + module JMock # JMock version.. - JMOCK_VERSION = "1.2.0" + JMOCK_VERSION = '1.2.0' # JMock specification. - JMOCK_REQUIRES = "jmock:jmock:jar:#{JMOCK_VERSION}" - - # The classpath used for running the tests. Includes the compiled classes (compile.target) and - # their classpath dependencies. Will also include anything you pass to #with, shared between the - # testing compile and run classpath dependencies. - attr_reader :classpath - - def initialize(*args) #:nodoc: - super - @classpath = [] - @include = [] - @exclude = [] - parent = Project.task_in_parent_project(name) - @options = parent && parent.respond_to?(:options) ? parent.options.clone : DEFAULT_OPTIONS.clone - enhance { run_tests } - end - - def execute(args) #:nodoc: - setup.invoke - begin - super - @project.task("test:junit").invoke # In case someone enhanced it - rescue RuntimeError - raise if options[:fail_on_failure] - ensure - teardown.invoke - end - end - - # *Deprecated* Add a prerequisite to the compile task instead. - def prepare(*prereqs, &block) - warn_deprecated "Add a prerequisite to the compile task instead of using the prepare task." - @project.task("test:prepare").enhance prereqs, &block - end - - # :call-seq: - # compile(*sources) => CompileTask - # compile(*sources) { |task| .. } => CompileTask - # - # The compile task is similar to the Project's compile task. However, it compiles all - # files found in the src/java/test directory into the target/test-classes directory. - # This task is executed by the test task before running any test cases. - # - # Once the project definition is complete, all classpath dependencies from the regular - # compile task are copied over, so you only need to specify classpath dependencies - # specific to your test cases. You can do so by calling #with on the test task. - # The classpath dependencies used here are also copied over to the junit task. - def compile(*sources, &block) - @project.task("test:compile").from(sources).enhance &block - end - - # :call-seq: - # resources(*prereqs) => ResourcesTask - # resources(*prereqs) { |task| .. } => ResourcesTask - # - # Executes by the #compile task to copy resource files over. See Project#resources. - def resources(*prereqs, &block) - @project.task("test:resources").enhance prereqs, &block - end - - # *Deprecated* Use the test task directly instead of calling test.junit. - def junit() - warn_deprecated "Use the test task directly instead of calling test.junit." - @project.task("test:junit") - end - - # :call-seq: - # setup(*prereqs) => task - # setup(*prereqs) { |task| .. } => task - # - # Returns the setup task. The setup task is executed at the beginning of the test task, - # after compiling the test files. - def setup(*prereqs, &block) - @project.task("test:setup").enhance prereqs, &block - end - - # :call-seq: - # teardown(*prereqs) => task - # teardown(*prereqs) { |task| .. } => task - # - # Returns the teardown task. The teardown task is executed at the end of the test task. - def teardown(*prereqs, &block) - @project.task("test:teardown").enhance prereqs, &block - end - - # :call-seq: - # with(*specs) => self - # - # Specify artifacts (specs, tasks, files, etc) to include in the classpath when compiling - # and running test cases. - def with(*artifacts) - @classpath |= Buildr.artifacts(artifacts.flatten).uniq - compile.with artifacts - self - end - - # Returns various test options. - attr_reader :options - - # :call-seq: - # using(options) => self - # - # Sets various test options and returns self. Accepts a hash of options, or symbols (a symbol sets that - # option to true). 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). - # * :java_args -- Java arguments when forking a new JVM. - # * :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. - def using(*args) - args.pop.each { |key, value| options[key.to_sym] = value } if Hash === args.last - args.each { |key| options[key.to_sym] = true } - self - end - - # :call-seq: - # include(*classes) => 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 classes. 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. - def include(*classes) - @include += classes - self - end - - # :call-seq: - # exclude(*classes) => self - # - # Exclude the specified test cases. This method accepts multiple arguments and returns self. - # See #include for the type of arguments you can use. - def exclude(*classes) - @exclude += classes - self - end - - # :call-seq: - # classes() => strings - # - # List of test classes to run. Determined by finding all the test classes in the target directory, - # and reducing based on the include/exclude patterns. - def classes() - base = Pathname.new(compile.target.to_s) - patterns = self.class.const_get("#{framework.to_s.upcase}_TESTS_PATTERN").to_a - FileList[patterns.map { |pattern| "#{base}/**/#{pattern}.class" }]. - map { |file| Pathname.new(file).relative_path_from(base).to_s.ext("").gsub(File::SEPARATOR, ".") }. - select { |name| include?(name) }.reject { |name| name =~ /\$/ }.sort - end - - # List of failed test classes. Set after running the tests. - attr_reader :failed_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) }) && - [EMAIL PROTECTED] { |pattern| File.fnmatch(pattern, name) } - end - - # :call-seq: - # requires() => classpath - # - # Returns the classpath for the selected test frameworks. Necessary for compiling and running test cases. - def requires() - self.class.const_get("#{framework.to_s.upcase}_REQUIRES").to_a + [JMOCK_REQUIRES] - end - - # :call-seq: - # framework() => symbol - # - # Returns the test framework, e.g. :junit, :testng. - def framework() - @framework ||= TEST_FRAMEWORKS.detect { |name| options[name] } || TEST_FRAMEWORKS.first - end - - # :call-seq: - # report_to() => file - # - # Test frameworks that can produce reports, will write them to this directory. - # - # This is framework dependent, so unless you use the default test framework, call this method - # after setting the test framework. - def report_to() - @report_to ||= file(@project.path_to(:reports, "#{framework}")=>self) - end - - protected - - # :call-seq: - # run_tests() - # - # Runs the test cases using the selected test framework. Executes as part of the task. - def run_tests() - classes = self.classes - if classes.empty? - @failed_tests = [] - else - puts "Running tests in [EMAIL PROTECTED]" if verbose - @failed_tests = send("#{framework}_run", - :classes => classes, - :classpath => @classpath + [compile.target], - :properties => { 'baseDir' => compile.target.to_s }.merge(options[:properties] || {}), - :environment=> options[:environment] || {}, - :java_args => options[:java_args] || Buildr.options.java_args) - unless @failed_tests.empty? - warn "The following tests failed:[EMAIL PROTECTED]("\n")}" if verbose - fail "Tests failed!" - end - end - end - + JMOCK_REQUIRES = ["jmock:jmock:jar:#{JMOCK_VERSION}"] end - # The JUnit test framework. This is the default test framework, but you can force it by # adding the following to your project: # test.using :testng @@ -389,6 +21,8 @@ # You can use the report method to control the junit:report task. module JUnit + include JMock + # Used by the junit:report task. Access through JUnit#report if you want to set various # options for that task, for example: # JUnit.report.frames = false @@ -406,10 +40,10 @@ # Target directory for generated report. attr_accessor :target - def initialize() + def initialize @params = {} @frames = true - @target = "reports/junit" + @target = 'reports/junit' end # :call-seq: @@ -419,15 +53,15 @@ # target directory. You can specify a target, or let it pick the default one from the # target attribute. def generate(projects, target = @target.to_s) - html_in = File.join(target, "html") + html_in = File.join(target, 'html') rm_rf html_in ; mkpath html_in - Buildr.ant("junit-report") do |ant| + Buildr.ant('junit-report') do |ant| ant.junitreport :todir=>target do projects.select { |project| project.test.framework == :junit }. map { |project| project.test.report_to.to_s }.select { |path| File.exist?(path) }. - each { |path| ant.fileset(:dir=>path) { ant.include :name=>"TEST-*.xml" } } - options = { :format=>frames ? "frames" : "noframes" } + each { |path| ant.fileset(:dir=>path) { ant.include :name=>'TEST-*.xml' } } + options = { :format=>frames ? 'frames' : 'noframes' } options[:styledir] = style_dir if style_dir ant.report options.merge(:todir=>html_in) do params.each { |key, value| ant.param :name=>key, :expression=>value } @@ -439,12 +73,12 @@ end # JUnit version number. - JUNIT_VERSION = "4.3.1" + JUNIT_VERSION = '4.3.1' # JUnit specification. - JUNIT_REQUIRES = "junit:junit:jar:#{JUNIT_VERSION}" + JUNIT_REQUIRES = ["junit:junit:jar:#{JUNIT_VERSION}"] + JMOCK_REQUIRES # Pattern for selecting JUnit test classes. Regardless of include/exclude patterns, only classes # that match this pattern are used. - JUNIT_TESTS_PATTERN = [ "Test*", "*Test" ] + JUNIT_TESTS_PATTERN = [ 'Test*.class', '*Test.class' ] # Ant-JUnit requires for JUnit and JUnit reports tasks. Java.wrapper.setup { |jw| jw.classpath << "org.apache.ant:ant-junit:jar:#{Ant::VERSION}" } @@ -457,8 +91,8 @@ # Returns the Report object used by the junit:report task. You can use this object to set # various options that affect your report, for example: # JUnit.report.frames = false - # JUnit.report.params["title"] = "My App" - def report() + # JUnit.report.params['title'] = 'My App' + def report @report ||= Report.new end @@ -474,41 +108,41 @@ def junit_run(args) rm_rf report_to.to_s ; mkpath report_to.to_s # Use Ant to execute the Junit tasks, gives us performance and reporting. - Buildr.ant("junit") do |ant| + Buildr.ant('junit') do |ant| case options[:fork] when false forking = {} when :each - forking = { :fork=>true, :forkmode=>"perTest" } + forking = { :fork=>true, :forkmode=>'perTest' } when true, :once - forking = { :fork=>true, :forkmode=>"once" } + forking = { :fork=>true, :forkmode=>'once' } else - fail "Option fork must be :once, :each or false." + fail 'Option fork must be :once, :each or false.' end ant.junit forking.merge(:clonevm=>options[:clonevm] || false, :dir=>@project.path_to) do - ant.classpath :path=>args[:classpath].map(&:to_s).each { |path| file(path).invoke }.join(File::PATH_SEPARATOR) + ant.classpath :path=>args[:dependencies].map(&:to_s).each { |path| file(path).invoke }.join(File::PATH_SEPARATOR) args[:properties].each { |key, value| ant.sysproperty :key=>key, :value=>value } args[:environment].each { |key, value| ant.env :key=>key, :value=>value } java_args = args[:java_args] - java_args = java_args.split(" ") if String === java_args + java_args = java_args.split(' ') if String === java_args java_args.each { |value| ant.jvmarg :value=>value } if java_args - ant.formatter :type=>"plain" - ant.formatter :type=>"xml" - ant.formatter :type=>"plain", :usefile=>false # log test - ant.formatter :type=>"xml" - ant.batchtest :todir=>report_to.to_s, :failureproperty=>"failed" do + ant.formatter :type=>'plain' + ant.formatter :type=>'xml' + ant.formatter :type=>'plain', :usefile=>false # log test + ant.formatter :type=>'xml' + ant.batchtest :todir=>report_to.to_s, :failureproperty=>'failed' do ant.fileset :dir=>compile.target.to_s do - args[:classes].each { |cls| ant.include :name=>cls.gsub(".", "/").ext("class") } + args[:files].each { |cls| ant.include :name=>cls.gsub('.', '/').ext('class') } end end end - return [] unless ant.project.getProperty("failed") + return [] unless ant.project.getProperty('failed') end # But Ant doesn't tell us what went kaput, so we'll have to parse the test files. - args[:classes].inject([]) do |failed, name| + args[:files].inject([]) do |failed, name| if report = File.read(File.join(report_to.to_s, "TEST-#{name}.txt")) rescue nil # 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). + 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 << name if status[:failures] > 0 || status[:errors] > 0 end @@ -516,15 +150,15 @@ end end - namespace "junit" do + namespace 'junit' do desc "Generate JUnit tests report in #{report.target}" - task("report") do |task| + task('report') do |task| report.generate Project.projects puts "Generated JUnit tests report in #{report.target}" end end - task("clean") { rm_rf report.target.to_s } + task('clean') { rm_rf report.target.to_s } end @@ -533,13 +167,15 @@ # test.using :testng module TestNG + include JMock + # TestNG version number. - TESTNG_VERSION = "5.5" + TESTNG_VERSION = '5.5' # TestNG specification. - TESTNG_REQUIRES = "org.testng:testng:jar:jdk15:#{TESTNG_VERSION}" + TESTNG_REQUIRES = ["org.testng:testng:jar:jdk15:#{TESTNG_VERSION}"] + JMOCK_REQUIRES # Pattern for selecting TestNG test classes. Regardless of include/exclude patterns, only classes # that match this pattern are used. - TESTNG_TESTS_PATTERN = [ "Test*", "*Test", "*TestCase" ] + TESTNG_TESTS_PATTERN = [ 'Test*.class', '*Test.class', '*TestCase.class' ] class << self @@ -553,12 +189,13 @@ private def testng_run(args) - cmd_args = [ "org.testng.TestNG", "-sourcedir", compile.sources.join(";"), "-suitename", @project.name ] - cmd_args << "-d" << report_to.to_s - cmd_options = args.only(:classpath, :properties, :java_args) - args[:classes].inject([]) do |failed, test| + cmd_args = [ 'org.testng.TestNG', '-sourcedir', compile.sources.join(';'), '-suitename', @project.name ] + cmd_args << '-d' << report_to.to_s + cmd_options = args.only(:properties, :java_args) + cmd_options[:classpath] = args[:dependencies] + args[:files].inject([]) do |failed, test| begin - Buildr.java cmd_args, "-testclass", test, cmd_options.merge(:name=>test) + Buildr.java cmd_args, '-testclass', test, cmd_options.merge(:name=>test) failed rescue failed << test @@ -568,251 +205,11 @@ end - class TestTask - include JUnit - include TestNG - end - - end - - - # The integration tests task. Buildr has one such task (see Buildr#integration) that runs - # all tests marked with :integration=>true, and has a setup/teardown tasks separate from - # the unit tests. - class IntegrationTestsTask < Rake::Task - - def initialize(*args) #:nodoc: - super - @setup = task("#{name}:setup") - @teardown = task("#{name}:teardown") - enhance do - puts "Running integration tests..." if verbose - TestTask.run_local_tests true - end - end - - def execute(args) #:nodoc: - setup.invoke - begin - super - ensure - teardown.invoke - end - end - - # :call-seq: - # setup(*prereqs) => task - # setup(*prereqs) { |task| .. } => task - # - # Returns the setup task. The setup task is executed before running the integration tests. - def setup(*prereqs, &block) - @setup.enhance prereqs, &block - end - - # :call-seq: - # teardown(*prereqs) => task - # teardown(*prereqs) { |task| .. } => task - # - # Returns the teardown task. The teardown task is executed after running the integration tests. - def teardown(*prereqs, &block) - @teardown.enhance prereqs, &block - end - - end - - - # Methods added to Project to support compilation and running of test cases. - module Test - - include Extension - - first_time do - desc "Run all test cases" - task("test") { TestTask.run_local_tests false } - - # This rule takes a suffix and runs that test case in the current project. For example; - # buildr test:MyTest - # will run the test case class com.example.MyTest, if found in the current 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. - rule /^test:.*$/ do |task| - TestTask.only_run task.name.scan(/test:(.*)/)[0][0].split(",") - task("test").invoke - end - - 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. - task.enhance do - task("test").invoke unless Buildr.options.test == false - end - end - - IntegrationTestsTask.define_task("integration") - - # Similar to test:[pattern] but for integration tests. - rule /^integration:.*$/ do |task| - unless task.name.split(':')[1] =~ /^(setup|teardown)$/ - TestTask.only_run task.name.scan(/integration:(.*)/)[0][0].split(",") - task("integration").invoke - end - end - - # Anything that comes after local packaging (install, deploy) executes the integration tests, - # which do not conflict with integration invoking the project's own packaging (package=> - # integration=>foo:package is not circular, just confusing to debug.) - task "package" do - task("integration").invoke if Buildr.options.test && Rake.application.original_dir == Dir.pwd - end - end - - before_define do |project| - # Define a recursive test task, and pass it a reference to the project so it can discover all other tasks. - Java::TestTask.define_task("test") - project.test.instance_eval { instance_variable_set :@project, project } - #project.recursive_task("test") - # Similar to the regular resources task but using different paths. - resources = ResourcesTask.define_task("test:resources") - project.path_to("src/test/resources").tap { |dir| resources.from dir if File.exist?(dir) } - # Similar to the regular compile task but using different paths. - compile = Java::CompileTask.define_task("test:compile"=>[project.compile, task("test:prepare"), project.test.resources]) - project.path_to("src/test/java").tap { |dir| compile.from dir if File.exist?(dir) } - compile.into project.path_to(:target, "test-classes") - resources.filter.into project.path_to(:target, "test-resources") - project.test.enhance [compile] - # Define the JUnit task here, otherwise we get a normal task. - Java::JUnitTask.define_task("test:junit") - # Define these tasks once, otherwise we may get a namespace error. - project.test.setup ; project.test.teardown - end - - after_define do |project| - # Copy the regular compile classpath over, and also include the generated classes, both of which - # can be used in the test cases. And don't forget the classpath required by the test framework (e.g. JUnit). - project.test.with project.compile.classpath, project.compile.target, project.test.requires - project.clean do - verbose(false) do - rm_rf project.test.compile.target.to_s - rm_rf project.test.report_to.to_s - end - end - end - - - # :call-seq: - # test(*prereqs) => TestTask - # test(*prereqs) { |task| .. } => TestTask - # - # Returns the test task. The test task controls the entire test lifecycle. - # - # 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. - # - # You can use convenient methods that handle the most common settings. For example, - # add classpath dependencies using test.with, or include only specific test cases - # 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 - # teardown tasks. - def test(*prereqs, &block) - task("test").enhance prereqs, &block - end - - # :call-seq: - # integration() { |task| .... } - # integration() => IntegrationTestTask - # - # Use this method to return the integration tests task, or enhance it with a block to execute. - # - # There is one integration tests task you can execute directly, or as a result of running the package - # task (or tasks that depend on it, like install and deploy). It contains all the tests marked with - # :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, - # but with the following addition: - # test.using :integration - # - # Use this method to enhance the setup and teardown tasks that are executed before (and after) all - # integration tests are run, for example, to start a Web server or create a database. - def integration(*deps, &block) - Rake::Task["rake:integration"].enhance deps, &block - end - - end - - # :call-seq: - # integration() { |task| .... } - # integration() => IntegrationTestTask - # - # Use this method to return the integration tests task. - def integration(*deps, &block) - Rake::Task["rake:integration"].enhance deps, &block - end - - - class Options - - # Runs test cases after the build when true (default). This forces test cases 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. - # - # 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. - def test() - case value = ENV["TEST"] || ENV["test"] - when /^(no|off|false|skip)$/i - false - when /^all$/i - :all - 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." - true - end - end - - # Sets the test option (environment variable TEST). Possible values are true, false or :all. - # - # You can also set this from the environment variable, e.g.: - # - # buildr # With tests - # buildr test=no # Without tests - # buildr test=all # Ignore failures - # set TEST=no - # buildr # Without tests - def test=(flag) - ENV["test"] = nil - ENV["TEST"] = flag.to_s - end - end - - - - task("help") do - puts - puts "To run a full build without running any test cases:" - puts " buildr test=no" - puts "To run specific test case:" - puts " buildr test:MyTest" - puts "To run integration tests:" - puts " buildr integration" + class TestTask + include Java::JUnit + include Java::TestNG end end
Modified: incubator/buildr/trunk/spec/compile_spec.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/compile_spec.rb?rev=606399&r1=606398&r2=606399&view=diff ============================================================================== --- incubator/buildr/trunk/spec/compile_spec.rb (original) +++ incubator/buildr/trunk/spec/compile_spec.rb Fri Dec 21 23:12:32 2007 @@ -3,13 +3,13 @@ describe Buildr::CompileTask do before do - @compile = define('foo').compile.using(:java) # Test files to compile and target directory to compile into. @src_dir = 'src/java' @sources = ['Test1.java', 'Test2.java'].map { |f| File.join(@src_dir, f) }. each { |src| write src, "class #{src.pathmap('%n')} {}" } # You can supply a relative path, but a full path is used everywhere else. @target = File.expand_path('classes') + @compile = define('foo').compile.using(:javac) end it 'should respond to from() and return self' do @@ -73,12 +73,62 @@ end +describe Buildr::CompileTask, 'compiler' do + it 'should be nil if not identified' do + define('foo').compile.compiler.should be_nil + end + + it 'should be set by calling using' do + define('foo') { compile.using(:javac) } + project('foo').compile.compiler.should eql(:javac) + end + + it 'should only support existing compiler' do + lambda { define('foo') { compile.using(:unknown) } }.should raise_error(ArgumentError, /unknown compiler/i) + end + + it 'should only allow setting the compiler once' do + lambda { define('foo') { compile.using(:javac).using(:scalac) } }.should raise_error(RuntimeError, /already selected/i) + end + + it 'should identify itself from source directories' do + write 'src/main/java/Test.java', 'class Test {}' + define('foo').compile.compiler.should eql(:javac) + end + + it 'should identify itself form project paths' do + write 'bar/Test.java', 'class Test {}' + define('foo').compile.compiler.should be_nil + define('bar') { compile.from 'bar' }.compile.compiler.should eql(:javac) + end + + it 'should have no source/target mapping unless selected' do + define('foo') + project('foo').compile.sources.should be_empty + project('foo').compile.target.should be_nil + end + + it 'should set target directory' do + define('foo') { compile.using(:javac) } + project('foo').compile.sources.should be_empty + project('foo').compile.target.to_s.should eql(File.expand_path('target/classes')) + end + + it 'should not over-ride exisitng source and target directories' do + define('foo') { compile.from('foo/java').into('classes').using(:javac) } + project('foo').compile.sources.should eql(['foo/java']) + project('foo').compile.target.to_s.should eql(File.expand_path('classes')) + end + +end + + describe Buildr::CompileTask, 'sources' do before do @src_dir = 'src/java' @sources = ['Test1.java', 'Test2.java'].map { |f| File.join(@src_dir, f) }. each { |src| write src, "class #{src.pathmap('%n')} {}" } - @compile = define('foo').compile.using(:java) + @compile = define('foo').compile.using(:javac) # Test files to compile and target directory to compile into. end @@ -145,10 +195,10 @@ describe Buildr::CompileTask, 'dependencies' do before do - @compile = define('foo').compile.using(:java) + @compile = define('foo').compile.using(:javac) @sources = ['Test1.java', 'Test2.java']. each { |src| write src, "class #{src.pathmap('%n')} {}" } - define('to_jar').compile.using(:java).from(@sources).into(Dir.pwd).invoke + define('to_jar').compile.using(:javac).from(@sources).into(Dir.pwd).invoke @jars = [ 'test1.jar', 'test2.jar' ]. # javac can't cope with empty jars each { |jar| zip(jar).include(@sources.map { |src| src.ext('class') }).invoke } end @@ -219,7 +269,7 @@ describe Buildr::CompileTask, 'target' do before do - @compile = define('foo').compile.using(:java) + @compile = define('foo').compile.using(:javac) write 'Test.java', 'class Test {}' end @@ -400,23 +450,6 @@ end -describe Project, '#prepare' do - accessor_task_spec :prepare - - it 'should accept prerequisites' do - tasks = ['task1', 'task2'].each { |name| task(name) } - define('foo') { prepare *tasks } - lambda { project('foo').prepare.invoke }.should run_tasks(*tasks) - end - - it 'should accept block' do - task 'action' - define('foo') { prepare { task('action').invoke } } - lambda { project('foo').prepare.invoke }.should run_task('action') - end -end - - describe Project, '#compile' do accessor_task_spec :compile @@ -478,11 +511,6 @@ project('foo').compile.sources.should be_empty end - it 'should always set target directory' do - define 'foo' - project('foo').compile.target.should_not be_nil - end - it 'should set target directory to target/classes' do make_sources define 'foo' @@ -495,11 +523,6 @@ file(File.expand_path('target/classes')).prerequisites.should include(project('foo').compile) end - it 'should execute prepare task as pre-requisite' do - define('foo') { prepare } - lambda { project('foo').compile.invoke }.should run_task('foo:prepare') - end - it 'should execute resources task if compiling' do write 'src/main/java/Test.java', 'class Test {}' write 'src/main/resources/resource', 'resource' @@ -594,7 +617,7 @@ def run() ; task('filtering').invoke ; end end end - lambda { file(File.expand_path('target/classes')).invoke }.should run_task('filtering') + lambda { file(File.expand_path('target/resources')).invoke }.should run_task('filtering') end it 'should include all files in the resources directory' do @@ -624,6 +647,8 @@ project('foo').resources.invoke FileList['target/resources/**'].should include('target/resources/special') end + + it 'should use current profile for filtering' end @@ -775,4 +800,6 @@ define('foo') { define 'bar' } lambda { suppress_stdout { task('javadoc').invoke } }.should run_task('foo:javadoc').but_not('foo:bar:javadoc') end + + it 'should include prerequisites from compile task' end Modified: incubator/buildr/trunk/spec/project_spec.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/project_spec.rb?rev=606399&r1=606398&r2=606399&view=diff ============================================================================== --- incubator/buildr/trunk/spec/project_spec.rb (original) +++ incubator/buildr/trunk/spec/project_spec.rb Fri Dec 21 23:12:32 2007 @@ -55,13 +55,11 @@ lambda { project("foo") }.should_not raise_error end -=begin it "should detect circular dependency" do Buildr.define("baz") { define("bar") { project("foo:bar") } } Buildr.define("foo") { define("bar") { project("baz:bar") } } lambda { project("foo") }.should raise_error(RuntimeError, /Circular dependency/) end -=end end @@ -320,7 +318,6 @@ ordered.should eql(["foo", "foo:baz", "foo:bar"]) end -=begin it "should warn of circular dependency" do lambda do define "foo" do @@ -329,7 +326,6 @@ end end.should raise_error(RuntimeError, /Circular dependency/) end -=end end Modified: incubator/buildr/trunk/spec/sandbox.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/sandbox.rb?rev=606399&r1=606398&r2=606399&view=diff ============================================================================== --- incubator/buildr/trunk/spec/sandbox.rb (original) +++ incubator/buildr/trunk/spec/sandbox.rb Fri Dec 21 23:12:32 2007 @@ -12,7 +12,7 @@ # repository and cache these across test cases. repositories.remote << "http://repo1.maven.org/maven2" Java.wrapper.load # Anything added to the classpath. - artifacts(TestTask::JUNIT_REQUIRES, TestTask::TESTNG_REQUIRES, TestTask::JMOCK_REQUIRES).each { |a| file(a).invoke } + artifacts(TestTask::JUNIT_REQUIRES, TestTask::TESTNG_REQUIRES, Java::JMock::JMOCK_REQUIRES).each { |a| file(a).invoke } task("buildr:initialize").invoke @@ -265,6 +265,7 @@ Dir.chdir @test_dir @sandbox[:original_dir] = Rake.application.original_dir Rake.application.instance_eval { @original_dir = Dir.pwd } + Rake.application.instance_eval { @rakefile = File.join(Dir.pwd, 'buildfile') } # Later on we'll want to lose all the on_define created during the test. @sandbox[:on_define] = Project.class_eval { (@on_define || []).dup } @@ -314,8 +315,6 @@ # Restore options. Buildr.options.test = nil (ENV.keys - @sandbox[:env_keys]).each { |key| ENV.delete key } - - Rake.application.instance_eval { @rakefile = nil } end end Modified: incubator/buildr/trunk/spec/test_spec.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/test_spec.rb?rev=606399&r1=606398&r2=606399&view=diff ============================================================================== --- incubator/buildr/trunk/spec/test_spec.rb (original) +++ incubator/buildr/trunk/spec/test_spec.rb Fri Dec 21 23:12:32 2007 @@ -2,25 +2,10 @@ describe Buildr::TestTask do - it "should respond to :prepare and return prepare task" do - define("foo") { test.prepare.should be(task("test:prepare")) } - end - - it "should respond to :prepare and add prerequisites to test:prepare" do - define("foo") { test.prepare "prereq" } - project("foo").task("test:prepare").prerequisites.should include("prereq") - end - - it "should respond to :prepare and add action for test:prepare" do - task "action" - define("foo") { test.prepare { task("action").invoke } } - lambda { project("foo").test.prepare.invoke }.should run_tasks("action") - end - it "should respond to :compile and return compile task" do define "foo" do test.compile.should be(task("test:compile")) - test.compile.should be_kind_of(Buildr::Java::CompileTask) + test.compile.should be_kind_of(Buildr::CompileTask) end end @@ -88,16 +73,16 @@ define("foo") { test.with.should be(test) } end - it "should respond to :with and add artifacfs to compile task classpath" do + it "should respond to :with and add artifacfs to compile task dependencies" do define("foo") { test.with "test.jar", "acme:example:jar:1.0" } - project("foo").test.compile.classpath.should include(File.expand_path("test.jar")) - project("foo").test.compile.classpath.should include(artifact("acme:example:jar:1.0")) + project("foo").test.compile.dependencies.should include(File.expand_path("test.jar")) + project("foo").test.compile.dependencies.should include(artifact("acme:example:jar:1.0")) end - it "should respond to :with and add artifacfs to task classpath" do + it "should respond to :with and add artifacfs to task dependencies" do define("foo") { test.with "test.jar", "acme:example:jar:1.0" } - project("foo").test.classpath.should include(File.expand_path("test.jar")) - project("foo").test.classpath.should include(artifact("acme:example:jar:1.0")) + project("foo").test.dependencies.should include(File.expand_path("test.jar")) + project("foo").test.dependencies.should include(artifact("acme:example:jar:1.0")) end it "should respond to :using and return self" do @@ -147,18 +132,18 @@ project("foo").test.framework.should eql(:testng) end - it "should use the compile classpath" do + it "should use the compile dependencies" do define("foo") { compile.with "group:id:jar:1.0" } - project("foo").test.classpath.should include(artifact("group:id:jar:1.0")) + project("foo").test.dependencies.should include(artifact("group:id:jar:1.0")) end - it "should include the compile target in its classpath" do - define("foo") - project("foo").test.classpath.should include(project("foo").compile.target) + it "should include the compile target in its dependencies" do + define("foo") { compile.using(:javac) } + project("foo").test.dependencies.should include(project("foo").compile.target) end - it "should clean after itself (test classes)" do - define "foo" + it "should clean after itself (test files)" do + define("foo") { test.compile.using(:javac) } mkpath project("foo").test.compile.target.to_s lambda { task("clean").invoke }.should change { File.exist?(project("foo").test.compile.target.to_s) }.to(false) end @@ -171,7 +156,7 @@ it "should pass baseDir property to test case" do define "foo", :base_dir=>"somewhere" - project("foo").test.stub!(:classes).and_return ["TestThis"] + project("foo").test.stub!(:files).and_return ["TestThis"] project("foo").test.should_receive(:junit_run) do |arg| arg[:properties]["baseDir"].should eql(project("foo").test.compile.target.to_s) [] @@ -183,7 +168,7 @@ define "foo" do test.using :environment=>{ "foo"=>"bar" } end - project("foo").test.stub!(:classes).and_return ["TestThis"] + project("foo").test.stub!(:files).and_return ["TestThis"] project("foo").test.should_receive(:junit_run) do |arg| arg[:environment]["foo"].should eql("bar") [] @@ -209,7 +194,7 @@ it "should report no passed tests" do project("foo").test.invoke - project("foo").test.classes.should be_empty + project("foo").test.files.should be_empty end it "should execute teardown task" do @@ -222,7 +207,7 @@ before do @tests = ["PassingTest1", "PassingTest2"] define "foo" - project("foo").test.stub!(:classes).and_return @tests + project("foo").test.stub!(:files).and_return @tests project("foo").test.stub!(:junit_run).and_return [] end @@ -250,7 +235,7 @@ before do @tests = ["FailingTest1", "FailingTest2"] define "foo" - project("foo").test.stub!(:classes).and_return @tests + project("foo").test.stub!(:files).and_return @tests project("foo").test.stub!(:junit_run).and_return @tests end @@ -285,29 +270,29 @@ end it "should include JUnit requirements" do - project("foo").test.requires.should include(TestTask::JUNIT_REQUIRES) - project("foo").test.compile.classpath.should include(artifact(TestTask::JUNIT_REQUIRES)) - project("foo").test.classpath.should include(artifact(TestTask::JUNIT_REQUIRES)) + project("foo").test.requires.should include(*TestTask::JUNIT_REQUIRES) + project("foo").test.compile.dependencies.should include(*artifacts(TestTask::JUNIT_REQUIRES)) + project("foo").test.dependencies.should include(*artifacts(TestTask::JUNIT_REQUIRES)) end it "should include JMock requirements" do - project("foo").test.requires.should include(TestTask::JMOCK_REQUIRES) - project("foo").test.compile.classpath.should include(artifact(TestTask::JMOCK_REQUIRES)) - project("foo").test.classpath.should include(artifact(TestTask::JMOCK_REQUIRES)) + project("foo").test.requires.should include(*TestTask::JMOCK_REQUIRES) + project("foo").test.compile.dependencies.should include(*artifacts(TestTask::JMOCK_REQUIRES)) + project("foo").test.dependencies.should include(*artifacts(TestTask::JMOCK_REQUIRES)) end it "should include classes starting with and ending with Test" do ["TestThis", "ThisTest", "ThisThat"].each do |name| - write "target/test-classes/#{name}.class" + write "target/test/classes/#{name}.class" end - project("foo").test.classes.map { |file| File.basename(file) }.should == ["TestThis", "ThisTest"] + project("foo").test.files.map { |file| File.basename(file) }.should == ["TestThis", "ThisTest"] end it "should ignore inner classes" do ["TestThis", "TestThis$Innner"].each do |name| - write "target/test-classes/#{name}.class" + write "target/test/classes/#{name}.class" end - project("foo").test.classes.map { |file| File.basename(file) }.should == ["TestThis"] + project("foo").test.files.map { |file| File.basename(file) }.should == ["TestThis"] end it "should pass when JUnit test case passes" do @@ -369,29 +354,29 @@ end it "should include TestNG requirements" do - project("foo").test.requires.should include(TestTask::TESTNG_REQUIRES) - project("foo").test.compile.classpath.should include(artifact(TestTask::TESTNG_REQUIRES)) - project("foo").test.classpath.should include(artifact(TestTask::TESTNG_REQUIRES)) + project("foo").test.requires.should include(*TestTask::TESTNG_REQUIRES) + project("foo").test.compile.dependencies.should include(*artifacts(TestTask::TESTNG_REQUIRES)) + project("foo").test.dependencies.should include(*artifacts(TestTask::TESTNG_REQUIRES)) end it "should include TestNG requirements" do - project("foo").test.requires.should include(TestTask::JMOCK_REQUIRES) - project("foo").test.compile.classpath.should include(artifact(TestTask::JMOCK_REQUIRES)) - project("foo").test.classpath.should include(artifact(TestTask::JMOCK_REQUIRES)) + project("foo").test.requires.should include(*TestTask::JMOCK_REQUIRES) + project("foo").test.compile.dependencies.should include(*artifacts(TestTask::JMOCK_REQUIRES)) + project("foo").test.dependencies.should include(*artifacts(TestTask::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.classes.map { |file| File.basename(file) }.should == ["TestThis", "ThisTest"] + project("foo").test.files.map { |file| File.basename(file) }.should == ["TestThis", "ThisTest"] end it "should ignore inner classes" do ["TestThis", "TestThis$Innner"].each do |name| - write "target/test-classes/#{name}.class" + write "target/test/classes/#{name}.class" end - project("foo").test.classes.map { |file| File.basename(file) }.should == ["TestThis"] + project("foo").test.files.map { |file| File.basename(file) }.should == ["TestThis"] end it "should pass when TestNG test case passes" do @@ -513,10 +498,6 @@ lambda { task("test").invoke }.should run_tasks("foo:test", "foo:bar:test") end - it "should warn when calling junit" do - verbose(true) { lambda { define("foo") { test.junit } }.should warn_that(/deprecated/i) } - end - it "should not execute teardown if setup task failed" do define("foo") { test.setup { fail } } lambda { project("foo").test.invoke rescue nil }.should_not run_task("foo:test:teardown") @@ -534,40 +515,40 @@ it "should pick sources from src/test/java if found" do mkpath "src/test/java" - define("foo") { test.compile.sources.should eql([_("src/test/java")]) } + define("foo") do + test.compile.using(:javac) + test.compile.sources.should eql([_("src/test/java")]) + end end it "should ignore sources unless they exist" do define("foo") { test.compile.sources.should be_empty } end - it "should compile to :target/test-classes" do - define("foo", :target=>"targeted") { test.compile.target.should eql(file("targeted/test-classes")) } + it "should compile to :target/test/classes" do + define("foo", :target=>"targeted") do + test.compile.using(:javac) + test.compile.target.should eql(file("targeted/test/classes")) + end end - it "should use the compile classpath" do + it "should use compile dependencies" do define("foo") { compile.with "group:id:jar:1.0" } - project("foo").test.compile.classpath.should include(artifact("group:id:jar:1.0")) + project("foo").test.compile.dependencies.should include(artifact("group:id:jar:1.0")) end - it "should include the compiled target in its classpath" do + it "should include the compiled target in its dependencies" do define("foo") { compile.into "odd" } - project("foo").test.compile.classpath.should include(project("foo").file("odd")) + project("foo").test.compile.dependencies.should include(project("foo").file("odd")) end - it "should include the test framework artifacts in its classpath" do + it "should include the test framework artifacts in its dependencies" do define "foo" - project("foo").test.compile.classpath.select { |path| path.respond_to?(:to_spec) }.map(&:to_spec).tap do |specs| + project("foo").test.compile.dependencies.select { |path| path.respond_to?(:to_spec) }.map(&:to_spec).tap do |specs| project("foo").test.requires.each { |spec| specs.should include(spec) } end end - it "should execute prepare task first" do - write "src/test/java/Nothing.java", "class Nothing {}" - define "foo" - lambda { project("foo").test.compile.invoke }.should run_tasks(["foo:test:prepare", "foo:test:compile"]) - end - it "should clean after itself" do write "src/test/java/Nothing.java", "class Nothing {}" define("foo") { test.compile.into "test-compiled" } @@ -588,7 +569,7 @@ end it "should copy to the resources target directory" do - define("foo", :target=>"targeted") { test.resources.target.should eql(file("targeted/test-resources")) } + define("foo", :target=>"targeted") { test.resources.target.should eql(file("targeted/test/resources")) } end it "should execute alongside compile task" do
