diff --git a/Gemfile b/Gemfile index 3a1cb4dcdc..bd814396c2 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,9 @@ gem "syntax" gem "rspec-core", :path => "." gem "rspec-expectations", :path => "../rspec-expectations" gem "rspec-mocks", :path => "../rspec-mocks" +gem "relish" unless RUBY_PLATFORM == "java" + gem "ruby-prof" case RUBY_VERSION when /^1.9.2/ gem "ruby-debug19" diff --git a/History.markdown b/History.markdown index f00fb6268b..b15f47d3b8 100644 --- a/History.markdown +++ b/History.markdown @@ -1,5 +1,16 @@ ## rspec-core release history (incomplete) +### 2.0.0 / 2010-10-10 + +[full changelog](http://github.com/rspec/rspec-core/compare/v2.0.0.rc...v2.0.0) + +* RSpec-1 compatibility + * Rake task uses ENV["SPEC"] as file list if present + +* Bug fixes + * Bug Fix: optparse --out foo.txt (Leonardo Bessa) + * Suppress color codes for non-tty output (except autotest) + ### 2.0.0.rc / 2010-10-05 [full changelog](http://github.com/rspec/rspec-core/compare/v2.0.0.beta.22...v2.0.0.rc) diff --git a/README.markdown b/README.markdown index 07f1d93f10..6a5e0e31aa 100644 --- a/README.markdown +++ b/README.markdown @@ -8,7 +8,7 @@ See [Upgrade.markdown](http://github.com/rspec/rspec-core/blob/master/Upgrade.ma ## Install - gem install rspec --prerelease + gem install rspec -v 2.0.0 This will install the rspec, rspec-core, rspec-expectations and rspec-mocks gems. diff --git a/Rakefile b/Rakefile index a8b8b8bcfd..bbd4904d04 100644 --- a/Rakefile +++ b/Rakefile @@ -10,48 +10,57 @@ require "rspec/core/rake_task" require "rspec/core/version" require "cucumber/rake/task" -RSpec::Core::RakeTask.new(:spec) - -desc "Run all examples using rcov" -RSpec::Core::RakeTask.new :rcov => :cleanup_rcov_files do |t| - t.rcov = true - t.rcov_opts = %[-Ilib -Ispec --exclude "mocks,expectations,gems/*,spec/resources,spec/lib,spec/spec_helper.rb,db/*,/Library/Ruby/*,config/*"] - t.rcov_opts << %[--no-html --aggregate coverage.data] +class Cucumber::Rake::Task::ForkedCucumberRunner + # When cucumber shells out, we still need it to run in the context of our + # bundle. + def run + sh "bundle exec #{RUBY} " + args.join(" ") + end end task :cleanup_rcov_files do rm_rf 'coverage.data' end -task :clobber do - rm_rf 'pkg' - rm_rf 'tmp' - rm_rf 'coverage' +desc "Run all examples" +RSpec::Core::RakeTask.new(:spec) do |t| + t.rspec_path = 'bin/rspec' + t.rspec_opts = %w[--color] end -class Cucumber::Rake::Task::ForkedCucumberRunner - # When cucumber shells out, we still need it to run in the context of our - # bundle. - def run - sh "bundle exec #{RUBY} " + args.join(" ") +Cucumber::Rake::Task.new(:cucumber) + +namespace :spec do + desc "Run all examples using rcov" + RSpec::Core::RakeTask.new :rcov => :cleanup_rcov_files do |t| + t.rcov = true + t.rcov_opts = %[-Ilib -Ispec --exclude "gems/*,features"] + t.rcov_opts << %[--text-report --sort coverage --no-html --aggregate coverage.data] end end -if RUBY_VERSION.to_f >= 1.9 - Cucumber::Rake::Task.new(:cucumber) do |t| +namespace :cucumber do + desc "Run cucumber features using rcov" + Cucumber::Rake::Task.new :rcov => :cleanup_rcov_files do |t| t.cucumber_opts = %w{--format progress} - end - - task :default => [:spec, :cucumber] -else - Cucumber::Rake::Task.new(:cucumber) do |t| t.rcov = true - t.rcov_opts = %[-Ilib -Ispec --exclude "mocks,expectations,gems/*,features,spec/ruby_forker,spec/rspec,spec/resources,spec/lib,spec/spec_helper.rb,db/*,/Library/Ruby/*,config/*"] + t.rcov_opts = %[-Ilib -Ispec --exclude "gems/*,features"] t.rcov_opts << %[--text-report --sort coverage --aggregate coverage.data] - t.cucumber_opts = %w{--format progress} end +end + +task :default => [:spec, :cucumber] + +task :clobber do + rm_rf 'pkg' + rm_rf 'tmp' + rm_rf 'coverage' +end - task :default => [:rcov, :cucumber] +desc "Push cukes to relishapp using the relish-client-gem" +task :relish, :version do |t, args| + raise "rake relish[VERSION]" unless args[:version] + sh "bundle exec relish --organization rspec --project rspec-core -v #{args[:version]} push" end Rake::RDocTask.new do |rdoc| diff --git a/Upgrade.markdown b/Upgrade.markdown index 7726675ba4..c61d24fa41 100644 --- a/Upgrade.markdown +++ b/Upgrade.markdown @@ -1,6 +1,6 @@ # Upgrade to rspec-core-2.0 -## What's changed since rspec-1 +## What's changed since RSpec-1 ### rspec command @@ -8,6 +8,27 @@ The command to run specs is now `rspec` instead of `spec`. rspec ./spec +#### Co-habitation of rspec-1 and rspec-2 + +Early beta versions of RSpec-2 included a `spec` command, which conflicted with +the RSpec-1 `spec` command because RSpec-1's was installed by the rspec gem, +while RSpec-2's is installed by the rspec-core gem. + +If you installed one of these early versions, the safest bet is to uninstall +rspec-1 and rspec-core-2, and then reinstall both. After you do this, you will +be able to run rspec-2 like this: + + `rspec ./spec` + +... and rspec-1 like this: + + `spec _1.3.1_ ./spec` + +Rubygems inspects the first argument to any gem executable to see if it's +formatted like a version number surrounded by underscores. If so, it uses that +version (e.g. `1.3.1`). If not, it uses the most recent version (e.g. +`2.0.0`). + ### rake task The RSpec rake task has moved to: @@ -43,7 +64,7 @@ Or, if you're using bundler: The `autospec` command is a thing of the past. -### RSpec +### RSpec is the new Spec The root namespace (top level module) is now `RSpec` instead of `Spec`, and the root directory under `lib` within all of the `rspec` gems is `rspec` instead of `spec`. @@ -66,6 +87,37 @@ options. Precedence is: ./.rspec ~/.rspec +### Bones + +Bones produces a handy little Rakefile to provide several services including +running specs. The current version (3.4.7) still assumes RSpec-1. To bring its +Rakefile into conformance with RSpec-2 a few changes are necessary. + +1. The require line has changed to `require 'spec/rake/spectask'` + +2. The `spec_opts` accessor has been deprecated in favor of `rspec_opts`. Also, + the `rspec` command no longer supports the `--options` command line option + so the options must be embedded directly in the Rakefile, or stored in the + `.rspec` files mentioned above. + +3. The `spec_files` accessor has been replaced by `pattern`. + +Here is a complete example: + + # rspec-1 + Spec::Rake::SpecTask.new do |t| + t.spec_opts = ['--options', "\"spec/spec.opts\""] + t.spec_files = FileList['spec/**/*.rb'] + end + +becomes: + + # rspec-2 + RSpec::Core::RakeTask.new do |t| + t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"] + t.pattern = 'spec/**/*_spec.rb' + end + ### `context` is no longer a top-level method We removed `context` from the main object because it was creating conflicts with diff --git a/features/README.markdown b/features/README.markdown index f9951a0c3f..7c82245962 100644 --- a/features/README.markdown +++ b/features/README.markdown @@ -1,12 +1,19 @@ -# Cucumber features +rspec-core provides the structure for RSpec code examples: -RSpec is specified using both RSpec and -[Cucumber](http://github.com/aslakhellesoy/cucumber). Cucumber provides -_executable documentation_. This means that the _.feature_ files below this -directory serve as specification, documentation _and_ regression tests of the -behaviour. + describe Account do + it "has a balance of zero when first opened" do + # example code goes here - for more on the + # code inside the examples, see rspec-expectations + # and rspec-mocks + end + end ## Issues -If you find this documentation incomplete or confusing, please [submit an -issue](http://github.com/rspec/rspec-core/issues). +The documentation for rspec-core is a work in progress. We'll be adding +Cucumber features over time, and clarifying existing ones. If you have +specific features you'd like to see added, find the existing documentation +incomplete or confusing, or, better yet, wish to write a missing Cucumber +feature yourself, please [submit an +issue](http://github.com/rspec/rspec-core/issues) or a [pull +request](http://github.com/rspec/rspec-core). diff --git a/features/command_line/configure.feature b/features/command_line/configure.feature index 1d2f300cca..56c8849239 100644 --- a/features/command_line/configure.feature +++ b/features/command_line/configure.feature @@ -1,6 +1,7 @@ Feature: configure - Use --configure to generate configuration files. + Use the --configure option on the command line to generate configuration + files. The only supported argument, so far, is "autotest", which creates an autotest/discover.rb file in your project root directory. diff --git a/features/configuration/read_options_from_file.feature b/features/configuration/read_options_from_file.feature index b9d796eee9..332c152af0 100644 --- a/features/configuration/read_options_from_file.feature +++ b/features/configuration/read_options_from_file.feature @@ -18,6 +18,12 @@ Feature: read command line configuration options from files """ describe "color_enabled" do context "when set with RSpec.configure" do + before do + # color is disabled for non-tty output, so stub the output stream + # to say it is tty, even though we're running this with cucumber + RSpec.configuration.output_stream.stub(:tty?) { true } + end + it "is true" do RSpec.configuration.should be_color_enabled end diff --git a/features/hooks/before_and_after_hooks.feature b/features/hooks/before_and_after_hooks.feature index 453c00b220..0500ab5126 100644 --- a/features/hooks/before_and_after_hooks.feature +++ b/features/hooks/before_and_after_hooks.feature @@ -155,6 +155,29 @@ Feature: before and after hooks after all ran """ + Scenario: failure in after(:all) block + Given a file named "after_all_spec.rb" with: + """ + describe "an error in after(:all)" do + after(:all) do + raise StandardError.new("Boom!") + end + + it "passes this example" do + end + + it "passes this example, too" do + end + end + """ + When I run "rspec after_all_spec.rb" + Then the output should contain "2 examples, 0 failures" + And the output should contain: + """ + An error occurred in an after(:all) hook. + StandardError: Boom! + """ + Scenario: define before and after blocks in configuration Given a file named "befores_in_configuration_spec.rb" with: """ diff --git a/features/hooks/described_class.feature b/features/metadata/described_class.feature similarity index 100% rename from features/hooks/described_class.feature rename to features/metadata/described_class.feature diff --git a/lib/autotest/rspec2.rb b/lib/autotest/rspec2.rb index 6a2defab28..8c8728d1b5 100644 --- a/lib/autotest/rspec2.rb +++ b/lib/autotest/rspec2.rb @@ -10,7 +10,10 @@ def initialize super clear_mappings setup_rspec_project_mappings - self.failed_results_re = /^\s*\d\)\s(.*?$\n.*?$).*?#\s(.*?):/m + + # Example for Ruby 1.8: http://rubular.com/r/AOXNVDrZpx + # Example for Ruby 1.9: http://rubular.com/r/85ag5AZ2jP + self.failed_results_re = /^\s*\d+\).*\n\s+Failure.*(\n\s+#\s(.*)?:\d+(?::.*)?)+$/m self.completed_re = /\n(?:\e\[\d*m)?\d* examples?/m end @@ -38,11 +41,15 @@ def consolidate_failures(failed) def make_test_cmd(files_to_test) files_to_test.empty? ? '' : - "#{ruby} #{require_rubygems}#{SPEC_PROGRAM} #{normalize(files_to_test).keys.flatten.map { |f| "'#{f}'"}.join(' ')}" + "#{bundle_exec}#{ruby} #{require_rubygems}-S #{SPEC_PROGRAM} --autotest #{normalize(files_to_test).keys.flatten.map { |f| "'#{f}'"}.join(' ')}" + end + + def bundle_exec + using_bundler? ? "bundle exec " : "" end def require_rubygems - using_bundler? ? "" : defined?(:Gem) ? "-rrubygems " : "" + using_bundler? ? "" : defined?(:Gem) ? "-rrubygems " : " " end def normalize(files_to_test) @@ -52,10 +59,6 @@ def normalize(files_to_test) end end - def ruby - using_bundler? ? "bundle exec" : super - end - def using_bundler? File.exists?('./Gemfile') end diff --git a/lib/rspec/core/command_line.rb b/lib/rspec/core/command_line.rb index c1ec687241..8c4d38d1c3 100644 --- a/lib/rspec/core/command_line.rb +++ b/lib/rspec/core/command_line.rb @@ -12,44 +12,22 @@ def initialize(options, configuration=RSpec::configuration, world=RSpec::world) end def run(err, out) - @options.configure(@configuration) @configuration.error_stream = err @configuration.output_stream ||= out + @options.configure(@configuration) @configuration.load_spec_files @configuration.configure_mock_framework @world.announce_inclusion_filter @world.announce_exclusion_filter - @configuration.reporter.report(example_count) do |reporter| + @configuration.reporter.report(@world.example_count) do |reporter| begin @configuration.run_hook(:before, :suite) - example_groups.run_examples(reporter) + @world.example_groups.map {|g| g.run(reporter)}.all? ensure @configuration.run_hook(:after, :suite) end end - - example_groups.success? - end - - private - - def example_count - @world.example_count - end - - module ExampleGroups - def run_examples(reporter) - @success = self.inject(true) {|success, group| success &= group.run(reporter)} - end - - def success? - @success ||= false - end - end - - def example_groups - @world.example_groups.extend(ExampleGroups) end end end diff --git a/lib/rspec/core/configuration.rb b/lib/rspec/core/configuration.rb index 6ed6682361..6ec27256e0 100644 --- a/lib/rspec/core/configuration.rb +++ b/lib/rspec/core/configuration.rb @@ -23,7 +23,6 @@ def self.add_setting(name, opts={}) add_setting :out, :alias => :output_stream add_setting :drb add_setting :drb_port - add_setting :color_enabled add_setting :profile_examples add_setting :fail_fast, :default => false add_setting :run_all_when_everything_filtered @@ -34,16 +33,17 @@ def self.add_setting(name, opts={}) add_setting :files_to_run add_setting :include_or_extend_modules add_setting :backtrace_clean_patterns + add_setting :autotest def initialize + @color_enabled = false self.include_or_extend_modules = [] self.files_to_run = [] self.backtrace_clean_patterns = [ /\/lib\d*\/ruby\//, - /bin\/rcov:/, - /vendor\/rails/, - /bin\/rspec/, - /bin\/spec/, + /bin\//, + /gems/, + /spec\/spec_helper\.rb/, /lib\/rspec\/(core|expectations|matchers|mocks)/ ] end @@ -129,20 +129,27 @@ def full_backtrace=(bool) settings[:backtrace_clean_patterns] = [] end - remove_method :color_enabled= + def color_enabled + @color_enabled && (output_to_tty? || autotest?) + end + + def color_enabled? + !!color_enabled + end def color_enabled=(bool) return unless bool - settings[:color_enabled] = true + @color_enabled = true if bool && ::RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ - orig_output_stream = settings[:output_stream] + using_stdout = settings[:output_stream] == $stdout + using_stderr = settings[:error_stream] == $stderr begin require 'Win32/Console/ANSI' + settings[:output_stream] = $stdout if using_stdout + settings[:error_stream] = $stderr if using_stderr rescue LoadError warn "You must 'gem install win32console' to use colour on Windows" - settings[:color_enabled] = false - ensure - settings[:output_stream] = orig_output_stream + @color_enabled = false end end end @@ -301,6 +308,14 @@ def load_spec_files private + def output_to_tty? + begin + settings[:output_stream].tty? + rescue NoMethodError + false + end + end + def built_in_formatter(key) case key.to_s when 'd', 'doc', 'documentation', 's', 'n', 'spec', 'nested' diff --git a/lib/rspec/core/example.rb b/lib/rspec/core/example.rb index 8524c1b761..5768790b79 100644 --- a/lib/rspec/core/example.rb +++ b/lib/rspec/core/example.rb @@ -16,7 +16,7 @@ def initialize(example_group_class, desc, options, example_block=nil) @example_group_class, @options, @example_block = example_group_class, options, example_block @metadata = @example_group_class.metadata.for_example(desc, options) @exception = nil - @pending_declared_in_example = @in_block = false + @pending_declared_in_example = false end def example_group @@ -28,10 +28,6 @@ def behaviour example_group end - def in_block? - @in_block - end - def pending? !!pending end @@ -48,12 +44,10 @@ def run(example_group_instance, reporter) with_around_hooks do begin run_before_each - @in_block = true @example_group_instance.instance_eval(&@example_block) rescue Exception => e set_exception(e) ensure - @in_block = false run_after_each end end diff --git a/lib/rspec/core/example_group.rb b/lib/rspec/core/example_group.rb index 87cb00dd49..c872630929 100644 --- a/lib/rspec/core/example_group.rb +++ b/lib/rspec/core/example_group.rb @@ -159,12 +159,14 @@ def self.before_all_ivars end def self.store_before_all_ivars(example_group_instance) + return if example_group_instance.instance_variables.empty? example_group_instance.instance_variables.each { |ivar| before_all_ivars[ivar] = example_group_instance.instance_variable_get(ivar) } end def self.assign_before_all_ivars(ivars, example_group_instance) + return if ivars.empty? ivars.each { |ivar, val| example_group_instance.instance_variable_set(ivar, val) } end @@ -196,7 +198,20 @@ def self.eval_after_eachs(example_group_instance) def self.eval_after_alls(example_group_instance) return if descendant_filtered_examples.empty? assign_before_all_ivars(before_all_ivars, example_group_instance) - run_hook!(:after, :all, example_group_instance) + + begin + run_hook!(:after, :all, example_group_instance) + rescue => e + # TODO: come up with a better solution for this. + RSpec.configuration.reporter.message <<-EOS + +An error occurred in an after(:all) hook. + #{e.class}: #{e.message} + occurred at #{e.backtrace.first} + + EOS + end + world.run_hook_filtered(:after, :all, self, example_group_instance) if top_level? end @@ -209,7 +224,6 @@ def self.run(reporter) RSpec.clear_remaining_example_groups if top_level? return end - @reporter = reporter example_group_instance = new reporter.example_group_started(self) @@ -289,6 +303,7 @@ def instance_eval_with_rescue(&hook) begin instance_eval(&hook) rescue Exception => e + raise unless example example.set_exception(e) end end diff --git a/lib/rspec/core/hooks.rb b/lib/rspec/core/hooks.rb index 2a7b9d8532..1ed36389d5 100644 --- a/lib/rspec/core/hooks.rb +++ b/lib/rspec/core/hooks.rb @@ -5,7 +5,7 @@ module Hooks class Hook attr_reader :options - def initialize(options, block) + def initialize(options, &block) @options = options @block = block end @@ -85,16 +85,19 @@ def hooks } end - def before(scope=:each, options={}, &block) - hooks[:before][scope] << BeforeHook.new(options, block) + def before(*args, &block) + scope, options = scope_and_options_from(*args) + hooks[:before][scope] << BeforeHook.new(options, &block) end - def after(scope=:each, options={}, &block) - hooks[:after][scope] << AfterHook.new(options, block) + def after(*args, &block) + scope, options = scope_and_options_from(*args) + hooks[:after][scope] << AfterHook.new(options, &block) end - def around(scope=:each, options={}, &block) - hooks[:around][scope] << AroundHook.new(options, block) + def around(*args, &block) + scope, options = scope_and_options_from(*args) + hooks[:around][scope] << AroundHook.new(options, &block) end # Runs all of the blocks stored with the hook in the context of the @@ -116,6 +119,16 @@ def run_hook_filtered(hook, scope, group, example_group_instance) def find_hook(hook, scope, example_group_class) hooks[hook][scope].find_hooks_for(example_group_class) end + + private + + def scope_and_options_from(scope=:each, options={}) + if Hash === scope + options = scope + scope = :each + end + return scope, options + end end end end diff --git a/lib/rspec/core/option_parser.rb b/lib/rspec/core/option_parser.rb index f135ab0248..b664bb5e6a 100644 --- a/lib/rspec/core/option_parser.rb +++ b/lib/rspec/core/option_parser.rb @@ -52,7 +52,7 @@ def parser(options) end parser.on('-o', '--out FILE', 'output to a file instead of STDOUT') do |o| - options[:output_stream] = o + options[:output_stream] = File.open(o,'w') end parser.on_tail('-h', '--help', "You're looking at it.") do @@ -95,6 +95,10 @@ def parser(options) parser.on('--drb-port [PORT]', 'Port to connect to on the DRb server') do |o| options[:drb_port] = o.to_i end + + parser.on('--autotest') do |o| + options[:autotest] = true + end end end end diff --git a/lib/rspec/core/rake_task.rb b/lib/rspec/core/rake_task.rb index 645cdbe5d1..d1f46b1869 100644 --- a/lib/rspec/core/rake_task.rb +++ b/lib/rspec/core/rake_task.rb @@ -73,6 +73,12 @@ def warning=(true_or_false) # nil attr_accessor :ruby_opts + # Path to rspec + # + # default: + # 'rspec' + attr_accessor :rspec_path + # Command line options to pass to rspec. # # default: @@ -93,8 +99,9 @@ def initialize(*args) yield self if block_given? - @rcov_path ||= 'rcov' - @pattern ||= './spec/**/*_spec.rb' + @rcov_path ||= 'rcov' + @rspec_path ||= 'rspec' + @pattern ||= './spec/**/*_spec.rb' desc("Run RSpec code examples") unless ::Rake.application.last_comment @@ -117,7 +124,11 @@ def initialize(*args) private def files_to_run # :nodoc: - FileList[ pattern ].map { |f| %["#{f}"] } + if ENV['SPEC'] + FileList[ ENV['SPEC'] ] + else + FileList[ pattern ].map { |f| %["#{f}"] } + end end def spec_command @@ -127,8 +138,15 @@ def spec_command cmd_parts << "-S" cmd_parts << "bundle exec" if bundler? cmd_parts << runner - cmd_parts << runner_options + if rcov + cmd_parts << ["-Ispec", rcov_opts] + else + cmd_parts << rspec_opts + end cmd_parts << files_to_run + if rcov && rspec_opts + cmd_parts << ["--", rspec_opts] + end cmd_parts.flatten.compact.reject(&blank).join(" ") end end @@ -136,11 +154,7 @@ def spec_command private def runner - rcov ? rcov_path : 'rspec' - end - - def runner_options - rcov ? [rcov_opts] : [rspec_opts] + rcov ? rcov_path : rspec_path end def bundler? diff --git a/lib/rspec/core/version.rb b/lib/rspec/core/version.rb index 13a1ce5f30..b18d34718a 100644 --- a/lib/rspec/core/version.rb +++ b/lib/rspec/core/version.rb @@ -1,7 +1,7 @@ module RSpec # :nodoc: module Core # :nodoc: module Version # :nodoc: - STRING = '2.0.0.rc' + STRING = '2.0.0' end end end diff --git a/spec/autotest/failed_results_re_spec.rb b/spec/autotest/failed_results_re_spec.rb index 52c7ffa29d..ec8a933dd5 100644 --- a/spec/autotest/failed_results_re_spec.rb +++ b/spec/autotest/failed_results_re_spec.rb @@ -5,17 +5,16 @@ let(:formatter) { RSpec::Core::Formatters::BaseTextFormatter.new(output) } let(:example_output) do group = RSpec::Core::ExampleGroup.describe("group name") - example = group.example("example name") { "this".should eq("that") } + group.example("example name") { "this".should eq("that") } group.run(formatter) RSpec.configuration.stub(:color_enabled?) { false } formatter.dump_failures output.string end - - it "should match a failure" do + + it "matches a failure" do re = Autotest::Rspec2.new.failed_results_re - re =~ example_output - $1.should == "group name example name\n Failure/Error: example = group.example(\"example name\") { \"this\".should eq(\"that\") }" - $2.should == __FILE__.sub(File.expand_path('.'),'.') + example_output.should =~ re + example_output[re, 2].should == __FILE__.sub(File.expand_path('.'),'.') end end diff --git a/spec/autotest/rspec_spec.rb b/spec/autotest/rspec_spec.rb index acd58447d5..5d542453d8 100644 --- a/spec/autotest/rspec_spec.rb +++ b/spec/autotest/rspec_spec.rb @@ -66,39 +66,32 @@ end describe "consolidating failures" do - before do - @spec_file = "spec/autotest/some_spec.rb" - rspec_autotest.instance_variable_set("@files", {@spec_file => Time.now}) - rspec_autotest.stub!(:find_files_to_test).and_return true - end + let(:subject_file) { "lib/autotest/some.rb" } + let(:spec_file) { "spec/autotest/some_spec.rb" } it "returns no failures if no failures were given in the output" do rspec_autotest.consolidate_failures([[]]).should == {} end it "returns a hash with the spec filename => spec name for each failure or error" do - rspec_autotest.stub!(:test_files_for).and_return "spec/autotest/some_spec.rb" - failures = [ - [ - "false should be false", - "#{@spec_file}" - ] - ] + failures = [ [ "false should be false", spec_file ] ] rspec_autotest.consolidate_failures(failures).should == { - @spec_file => ["false should be false"] + spec_file => ["false should be false"] } end - it "does not include the subject file" do - subject_file = "lib/autotest/some.rb" - rspec_autotest.stub!(:test_files_for).and_return "spec/autotest/some_spec.rb" - failures = [ - [ - "false should be false", - "expected: true,\n got: false (using ==)\n#{subject_file}:143:\n#{@spec_file}:203:" - ] - ] - rspec_autotest.consolidate_failures(failures).keys.should_not include(subject_file) + context "when subject file appears before the spec file in the backtrace" do + let(:failures) do + [ [ "false should be false", "#{subject_file}:143:\n#{spec_file}:203:" ] ] + end + + it "excludes the subject file" do + rspec_autotest.consolidate_failures(failures).keys.should_not include(subject_file) + end + + it "includes the spec file" do + rspec_autotest.consolidate_failures(failures).keys.should include(spec_file) + end end end @@ -116,16 +109,14 @@ context "using bundler" do it "returns 'bundle exec'" do File.stub(:exists?).with("./Gemfile") { true } - rspec_autotest.ruby.should eq("bundle exec") + rspec_autotest.make_test_cmd({'a' => 'b'}).should =~ /bundle exec .*ruby/ end end context "not using bundler" do it "returns the ruby command generated by Autotest" do - autotest = Autotest.new - autotest_ruby_command = autotest.ruby File.stub(:exists?).with("./Gemfile") { false } - rspec_autotest.ruby.should eq(autotest_ruby_command) + rspec_autotest.make_test_cmd({'a' => 'b'}).should_not =~ /bundle exec/ end end end diff --git a/spec/rspec/core/command_line_spec.rb b/spec/rspec/core/command_line_spec.rb index 0a421d92f3..14af53130e 100644 --- a/spec/rspec/core/command_line_spec.rb +++ b/spec/rspec/core/command_line_spec.rb @@ -39,20 +39,29 @@ module RSpec::Core RSpec::Core::Configuration.new end + let(:err) { ::StringIO.new } let(:out) { ::StringIO.new } before do config.stub(:run_hook) end + it "configures streams before command line options" do + # this is necessary to ensure that color works correctly on windows + config.should_receive(:error_stream=).ordered + config.should_receive(:output_stream=).ordered + config.should_receive(:color_enabled=).ordered + command_line.run(err, out) rescue nil + end + it "runs before suite hooks" do config.should_receive(:run_hook).with(:before, :suite) - command_line.run(out, out) + command_line.run(err, out) end it "runs after suite hooks" do config.should_receive(:run_hook).with(:after, :suite) - command_line.run(out, out) + command_line.run(err, out) end it "runs after suite hooks even after an error" do @@ -66,10 +75,11 @@ module RSpec::Core end end expect do - command_line.run(out, out) + command_line.run(err, out) end.to raise_error after_suite_called.should be_true end + end describe "#run with custom output" do diff --git a/spec/rspec/core/configuration_spec.rb b/spec/rspec/core/configuration_spec.rb index 9b80f000cc..d92c8a7d83 100644 --- a/spec/rspec/core/configuration_spec.rb +++ b/spec/rspec/core/configuration_spec.rb @@ -204,9 +204,41 @@ def that_thing describe "#color_enabled=" do context "given true" do + context "with non-tty output and no autotest" do + it "does not set color_enabled" do + config.output_stream = StringIO.new + config.output_stream.stub(:tty?) { false } + config.autotest = false + config.color_enabled = true + config.color_enabled.should be_false + end + end + + context "with tty output" do + it "does not set color_enabled" do + config.output_stream = StringIO.new + config.output_stream.stub(:tty?) { true } + config.autotest = false + config.color_enabled = true + config.color_enabled.should be_true + end + end + + context "with autotest output" do + it "does not set color_enabled" do + config.output_stream = StringIO.new + config.output_stream.stub(:tty?) { false } + config.autotest = true + config.color_enabled = true + config.color_enabled.should be_true + end + end + context "on windows" do before do @original_host = RbConfig::CONFIG['host_os'] + @original_stdout = $stdout + @original_stderr = $stderr RbConfig::CONFIG['host_os'] = 'mswin' config.stub(:require) config.stub(:warn) @@ -214,6 +246,8 @@ def that_thing after do RbConfig::CONFIG['host_os'] = @original_host + $stdout = @original_stdout + $stderr = @original_stderr end context "with win32console available" do @@ -223,14 +257,48 @@ def that_thing config.color_enabled = true end - it "leaves output stream intact" do - config.output_stream = $stdout - config.stub(:require) do |what| - config.output_stream = 'foo' if what =~ /Win32/ + context "with $stdout/err assigned to config.output/error_stream" do + it "reassigns new $stdout to output_stream" do + config.output_stream = $stdout + substitute_stdout = StringIO.new + config.stub(:require) do |what| + $stdout = substitute_stdout if what =~ /Win32/ + end + config.color_enabled = true + config.output_stream.should eq(substitute_stdout) + end + + it "reassigns new $stderr to error_stream" do + config.error_stream = $stderr + substitute_stderr = StringIO.new + config.stub(:require) do |what| + $stderr = substitute_stderr if what =~ /Win32/ + end + config.color_enabled = true + config.error_stream.should eq(substitute_stderr) end - config.color_enabled = true - config.output_stream.should eq($stdout) end + + context "without $stdout/err assigned to config.output/error_stream" do + it "leaves output stream intact" do + config.output_stream = output_stream = StringIO.new + config.stub(:require) do |what| + $stdout = StringIO.new if what =~ /Win32/ + end + config.color_enabled = true + config.output_stream.should eq(output_stream) + end + + it "leaves error stream intact" do + config.error_stream = error_stream = StringIO.new + config.stub(:require) do |what| + $stderr = StringIO.new if what =~ /Win32/ + end + config.color_enabled = true + config.error_stream.should eq(error_stream) + end + end + end context "with win32console NOT available" do diff --git a/spec/rspec/core/example_group_spec.rb b/spec/rspec/core/example_group_spec.rb index a80c676eb2..a4e3c1407e 100644 --- a/spec/rspec/core/example_group_spec.rb +++ b/spec/rspec/core/example_group_spec.rb @@ -384,6 +384,32 @@ module RSpec::Core example.metadata[:execution_result][:exception_encountered].message.should == "error in before all" end + context "when an error occurs in an after(:all) hook" do + before(:each) do + RSpec.configuration.reporter.stub(:message) + end + + let(:group) do + ExampleGroup.describe do + after(:all) { raise "error in after all" } + it("equality") { 1.should == 1 } + end + end + + it "allows the example to pass" do + group.run + example = group.examples.first + example.metadata.should_not be_nil + example.metadata[:execution_result].should_not be_nil + example.metadata[:execution_result][:status].should == "passed" + end + + it "rescues the error and prints it out" do + RSpec.configuration.reporter.should_receive(:message).with(/error in after all/) + group.run + end + end + it "has no 'running example' within before(:all)" do group = ExampleGroup.describe running_example = :none diff --git a/spec/rspec/core/example_spec.rb b/spec/rspec/core/example_spec.rb index 686f9bef17..67c541c081 100644 --- a/spec/rspec/core/example_spec.rb +++ b/spec/rspec/core/example_spec.rb @@ -117,18 +117,6 @@ end end - describe "#in_block?" do - before do - example.should_not be_in_block - end - it "is only true during the example (but not before or after)" do - example.should be_in_block - end - after do - example.should_not be_in_block - end - end - describe "#pending" do context "in the example" do it "sets the example to pending" do diff --git a/spec/rspec/core/hooks_filtering_spec.rb b/spec/rspec/core/hooks_filtering_spec.rb index 8ac578a934..d353190ff4 100644 --- a/spec/rspec/core/hooks_filtering_spec.rb +++ b/spec/rspec/core/hooks_filtering_spec.rb @@ -26,6 +26,26 @@ module RSpec::Core end describe "hooks with single filters" do + + context "with no scope specified" do + it "should be ran around|before|after :each if the filter matches the example group's filter" do + filters = [] + RSpec.configure do |c| + c.around(:match => true) {|example| filters << "around each in config"; example.run} + c.before(:match => true) { filters << "before each in config"} + c.after(:match => true) { filters << "after each in config"} + end + group = ExampleGroup.describe(:match => true) + group.example("example") {} + group.run + filters.should == [ + "around each in config", + "before each in config", + "after each in config" + ] + end + end + it "should be ran if the filter matches the example group's filter" do filters = [] RSpec.configure do |c| diff --git a/spec/rspec/core/option_parser_spec.rb b/spec/rspec/core/option_parser_spec.rb index 4959ba994d..c4e61acd0a 100644 --- a/spec/rspec/core/option_parser_spec.rb +++ b/spec/rspec/core/option_parser_spec.rb @@ -6,6 +6,8 @@ module RSpec::Core RSpec.stub(:deprecate) end + let(:output_file){ mock File } + it "deprecates the --formatter option" do RSpec.should_receive(:deprecate) Parser.parse!(%w[--formatter doc]) @@ -23,13 +25,15 @@ module RSpec::Core end it "parses output stream from --out" do + File.should_receive(:open).with("foo.txt",'w').and_return(output_file) options = Parser.parse!(%w[--out foo.txt]) - options.should eq( {:output_stream=>"foo.txt"} ) + options.should eq( {:output_stream=>output_file} ) end it "parses output stream from -o" do + File.should_receive(:open).with("foo.txt",'w').and_return(output_file) options = Parser.parse!(%w[-o foo.txt]) - options.should eq( {:output_stream=>"foo.txt"} ) + options.should eq( {:output_stream=>output_file} ) end end -end +end \ No newline at end of file diff --git a/spec/rspec/core/rake_task_spec.rb b/spec/rspec/core/rake_task_spec.rb index cf700d0cfd..392e9d3387 100644 --- a/spec/rspec/core/rake_task_spec.rb +++ b/spec/rspec/core/rake_task_spec.rb @@ -88,17 +88,24 @@ def spec_command it "renders them after rcov" do task.rcov = true task.rcov_opts = '--exclude "mocks"' - spec_command.should =~ /^-S rcov --exclude "mocks"/ + spec_command.should =~ /rcov.*--exclude "mocks"/ + end + + it "ensures that -Ispec is in the resulting command" do + task.rcov = true + task.rcov_opts = '--exclude "mocks"' + spec_command.should =~ /rcov.*-Ispec/ end end end context "with rspec_opts" do context "with rcov=true" do - it "does not add the rspec_opts" do + it "adds the rspec_opts after the rcov_opts and files" do + task.stub(:files_to_run) { "this.rb that.rb" } task.rcov = true task.rspec_opts = "-Ifoo" - spec_command.should_not =~ /-Ifoo/ + spec_command.should =~ /this.rb that.rb -- -Ifoo/ end end context "with rcov=false (default)" do @@ -123,5 +130,19 @@ def spec_command end end + context "with SPEC=path/to/file" do + before do + @orig_spec = ENV["SPEC"] + ENV["SPEC"] = "path/to/file" + end + + after do + ENV["SPEC"] = @orig_spec + end + + it "sets files to run" do + task.__send__(:files_to_run).should eq(["path/to/file"]) + end + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 732a097544..a994baad09 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -23,18 +23,6 @@ def method_missing(method, *args, &block) end end -module RSpec::Core - class SandboxedExampleGroup < ExampleGroup - def self.run(reporter=nil) - @orig_mock_space = RSpec::Mocks::space - RSpec::Mocks::space = RSpec::Mocks::Space.new - super(reporter || NullObject.new) - ensure - RSpec::Mocks::space = @orig_mock_space - end - end -end - def sandboxed(&block) begin @orig_config = RSpec.configuration @@ -48,13 +36,25 @@ def sandboxed(&block) object.extend(RSpec::Core::ObjectExtensions) object.extend(RSpec::Core::SharedExampleGroup) - @orig_example_group_class = RSpec::Core::const_get(:ExampleGroup) - RSpec::Core::__send__ :remove_const, :ExampleGroup - RSpec::Core::const_set(:ExampleGroup, RSpec::Core::SandboxedExampleGroup) + (class << RSpec::Core::ExampleGroup; self; end).class_eval do + alias_method :orig_run, :run + def run(reporter=nil) + @orig_mock_space = RSpec::Mocks::space + RSpec::Mocks::space = RSpec::Mocks::Space.new + orig_run(reporter || NullObject.new) + ensure + RSpec::Mocks::space = @orig_mock_space + end + end + object.instance_eval(&block) ensure - RSpec::Core::__send__ :remove_const, :ExampleGroup - RSpec::Core::const_set(:ExampleGroup, @orig_example_group_class) + (class << RSpec::Core::ExampleGroup; self; end).class_eval do + remove_method :run + alias_method :run, :orig_run + remove_method :orig_run + end + RSpec.instance_variable_set(:@configuration, @orig_config) RSpec.instance_variable_set(:@world, @orig_world) end diff --git a/specs.watchr b/specs.watchr index 3ece8415da..4234f4c464 100644 --- a/specs.watchr +++ b/specs.watchr @@ -34,12 +34,11 @@ end watch('^spec/(.*)_spec\.rb') { |m| run_spec_matching(m[1]) } watch('^lib/(.*)\.rb') { |m| run_spec_matching(m[1]) } watch('^spec/spec_helper\.rb') { run_all_specs } -watch('^spec/support/.*\.rb') { run_all_specs } +watch('^spec/support/.*\.rb') { run_all_specs } # -------------------------------------------------- # Signal Handling # -------------------------------------------------- - def no_int_for_you @sent_an_int = nil end