diff --git a/.gitignore b/.gitignore index d127824c7e..103edbc792 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ bin .yardoc vendor Gemfile-custom +.idea +bundle diff --git a/.travis.yml b/.travis.yml index 0c51876e69..392ec1ce66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,13 @@ before_install: - if [[ `gem -v` != 1.8.* ]]; then gem update --system; fi -script: "bin/rake --trace 2>&1" +script: "script/test_all 2>&1 && bin/rake cucumber --backtrace 2>&1" bundler_args: "--binstubs" rvm: - 1.8.7 - 1.9.2 - 1.9.3 - ree - - jruby + - jruby-18mode + - jruby-19mode + - rbx-18mode + - rbx-19mode diff --git a/Changelog.md b/Changelog.md index d48db17ae9..6b0d15da62 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,62 @@ +### 2.12.0 / 2012-11-12 +[full changelog](http://github.com/rspec/rspec-core/compare/v2.11.1...2.12.0) + +Enhancements + +* Add support for custom ordering strategies for groups and examples. + (Myron Marston) +* JSON Formatter (Alex Chaffee) +* Refactor rake task internals (Sam Phippen) +* Refactor HtmlFormatter (Pete Hodgson) +* Autotest supports a path to Ruby that contains spaces (dsisnero) +* Provide a helpful warning when a shared example group is redefined. + (Mark Burns). +* `--default_path` can be specified as `--default-line`. `--line_number` can be + specified as `--line-number`. Hyphens are more idiomatic command line argument + separators (Sam Phippen). +* A more useful error message is shown when an invalid command line option is + used (Jordi Polo). +* Add `format_docstrings { |str| }` config option. It can be used to + apply formatting rules to example group and example docstrings. + (Alex Tan) +* Add support for an `.rspec-local` options file. This is intended to + allow individual developers to set options in a git-ignored file that + override the common project options in `.rspec`. (Sam Phippen) +* Support for mocha 0.13.0. (Andy Lindeman) + +Bug fixes + +* Remove override of `ExampleGroup#ancestors`. This is a core ruby method that + RSpec shouldn't override. Instead, define `ExampleGroup#parent_groups`. (Myron + Marston) +* Limit monkey patching of shared example/context declaration methods + (`shared_examples_for`, etc.) to just the objects that need it rather than + every object in the system (Myron Marston). +* Fix Metadata#fetch to support computed values (Sam Goldman). +* Named subject can now be referred to from within subject block in a nested + group (tomykaira). +* Fix `fail_fast` so that it properly exits when an error occurs in a + `before(:all) hook` (Bradley Schaefer). +* Make the order spec files are loaded consistent, regardless of the + order of the files returned by the OS or the order passed at + the command line (Jo Liss and Sam Phippen). +* Ensure instance variables from `before(:all)` are always exposed + from `after(:all)`, even if an error occurs in `before(:all)` + (Sam Phippen). +* `rspec --init` no longer generates an incorrect warning about `--configure` + being deprecated (Sam Phippen). +* Fix pluralization of `1 seconds` (Odin Dutton) +* Fix ANSICON url (Jarmo Pertman) +* Use dup of Time so reporting isn't clobbered by examples that modify Time + without properly restoring it. (David Chelimsky) + +Deprecations + +* `share_as` is no longer needed. `shared_context` and/or + `RSpec::SharedContext` provide better mechanisms (Sam Phippen). +* Deprecate `RSpec.configuration` with a block (use `RSpec.configure`). + + ### 2.11.1 / 2012-07-18 [full changelog](http://github.com/rspec/rspec-core/compare/v2.11.0...v2.11.1) diff --git a/Gemfile b/Gemfile index 0288d0d8c8..bd984ca04e 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,7 @@ source "http://rubygems.org" gemspec -%w[rspec rspec-core rspec-expectations rspec-mocks].each do |lib| +%w[rspec rspec-expectations rspec-mocks].each do |lib| library_path = File.expand_path("../../#{lib}", __FILE__) if File.exist?(library_path) gem lib, :path => library_path diff --git a/Gemfile-custom.sample b/Gemfile-custom.sample index cf0bca45c1..a5017674b5 100644 --- a/Gemfile-custom.sample +++ b/Gemfile-custom.sample @@ -1,34 +1,19 @@ group :development do gem 'interactive_rspec' - gem 'relish', '~> 0.5.0' - gem 'guard-rspec', '0.5.0' + gem 'relish', '~> 0.6.0' + gem 'guard-rspec', '~> 1.2.1' gem 'growl', '1.0.3' gem 'spork', '0.9.0' platform :mri do - gem 'rb-fsevent', '~> 0.4.3.1' + gem 'rb-fsevent', '~> 0.9.0' gem 'ruby-prof', '~> 0.10.0' case RUBY_VERSION when /^1.8/ gem 'ruby-debug' - when '1.9.2' - gem 'ruby-debug19', '0.11.6' - gem 'ruby-debug-base19', '0.11.25' - gem 'linecache19', '0.5.12' - when '1.9.3' - gem 'ruby-debug19', '0.11.6' - # NOTE - as of 2012-03-17 the following two gems have not been released, - # so if you see either of these errors when trying to install the bundle: - # - # Could not find gem 'ruby-debug-base19 (= 0.11.26) ruby' in the gems available on this machine. - # Could not find gem 'linecache19 (= 0.5.13) ruby' in the gems available on this machine. - # - # ... run 'script/download-ruby-debug-19-dependencies' and try again - # - # See http://blog.wyeworks.com/2011/11/1/ruby-1-9-3-and-ruby-debug for more info. - gem 'ruby-debug-base19', '0.11.26' - gem 'linecache19', '0.5.13' + when /^1.9/ + gem 'debugger' end end end diff --git a/README.md b/README.md index 4daa27b927..fba05db32c 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,28 @@ the command line. rspec-core ships with an Autotest extension, which is loaded automatically if there is a `.rspec` file in the project's root directory. +## rcov integration + +rcov is best integrated via the [rcov rake +task](http://www.rubydoc.info/github/relevance/rcov/master/Rcov/RcovTask). + +rcov can also be integrated via the rspec rake task, but it requires a bit +more setup: + +```ruby +# Rakefile +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) do |config| + config.rcov = true +end + +task :default => :spec + +# spec/spec_helper.rb +require 'rspec/autorun' # **add this** +``` + ## get started Start with a simple example of behavior you expect from your system. Do diff --git a/Rakefile b/Rakefile index 544db88090..7d5b9a1a8c 100644 --- a/Rakefile +++ b/Rakefile @@ -22,6 +22,11 @@ namespace :spec do t.ruby_opts = %w[-w] t.rspec_opts = %w[--tag ui] end + + desc "Runs all specs together and then file-by-file" + task :ci do + sh "script/test_all" + end end if RUBY_VERSION.to_f == 1.8 @@ -64,8 +69,13 @@ desc "Push docs/cukes to relishapp using the relish-client-gem" task :relish, :version do |t, args| raise "rake relish[VERSION]" unless args[:version] sh "cp Changelog.md features/" + if `relish versions rspec/rspec-core`.split.map(&:strip).include? args[:version] + puts "Version #{args[:version]} already exists" + else + sh "relish versions:add rspec/rspec-core:#{args[:version]}" + end sh "relish push rspec/rspec-core:#{args[:version]}" sh "rm features/Changelog.md" end -task :default => [:spec, "spec:ui", :cucumber] +task :default => ["spec:ci", :cucumber] diff --git a/features/command_line/example_name_option.feature b/features/command_line/example_name_option.feature index 1ae4eead8f..1d2bbbc424 100644 --- a/features/command_line/example_name_option.feature +++ b/features/command_line/example_name_option.feature @@ -13,21 +13,21 @@ Feature: --example option Background: Given a file named "first_spec.rb" with: - """ + """ruby describe "first group" do it "first example in first group" do; end it "second example in first group" do; end end """ And a file named "second_spec.rb" with: - """ + """ruby describe "second group" do it "first example in second group" do; end it "second example in second group" do; end end """ And a file named "third_spec.rb" with: - """ + """ruby describe "third group" do it "first example in third group" do; end context "nested group" do @@ -37,7 +37,7 @@ Feature: --example option end """ And a file named "fourth_spec.rb" with: - """ + """ruby describe Array do describe "#length" do it "is the number of items" do @@ -98,4 +98,4 @@ Feature: --example option And the output should not contain any of these: |first example in third group| |nested group first example in nested group| - |nested group second example in nested group| \ No newline at end of file + |nested group second example in nested group| diff --git a/features/command_line/exit_status.feature b/features/command_line/exit_status.feature index d6392973d4..7f77f434f8 100644 --- a/features/command_line/exit_status.feature +++ b/features/command_line/exit_status.feature @@ -6,7 +6,7 @@ Feature: exit status Scenario: exit with 0 when all examples pass Given a file named "ok_spec.rb" with: - """ + """ruby describe "ok" do it "passes" do end @@ -18,7 +18,7 @@ Feature: exit status Scenario: exit with 1 when one example fails Given a file named "ko_spec.rb" with: - """ + """ruby describe "KO" do it "fails" do raise "KO" @@ -31,7 +31,7 @@ Feature: exit status Scenario: exit with 1 when a nested examples fails Given a file named "nested_ko_spec.rb" with: - """ + """ruby describe "KO" do describe "nested" do it "fails" do @@ -46,7 +46,7 @@ Feature: exit status Scenario: exit with 0 when no examples are run Given a file named "a_no_examples_spec.rb" with: - """ + """ruby """ When I run `rspec a_no_examples_spec.rb` Then the exit status should be 0 @@ -54,7 +54,7 @@ Feature: exit status Scenario: exit with 2 when one example fails and --failure-exit-code is 2 Given a file named "ko_spec.rb" with: - """ + """ruby describe "KO" do it "fails" do raise "KO" @@ -68,7 +68,7 @@ Feature: exit status @wip Scenario: exit with rspec's exit code when an at_exit hook is added upstream Given a file named "exit_at_spec.rb" with: - """ + """ruby require 'rspec/autorun' describe "exit 0 at_exit" do diff --git a/features/command_line/format_option.feature b/features/command_line/format_option.feature index 71a2afa044..89b15beeb2 100644 --- a/features/command_line/format_option.feature +++ b/features/command_line/format_option.feature @@ -17,7 +17,7 @@ Feature: --format option You can also specify an output target (STDOUT by default) by appending a filename to the argument: - $ rspec spec --format documentation:rspec.output.txt + $ rspec spec --format documentation --out rspec.txt `rspec --help` lists available formatters: @@ -29,7 +29,7 @@ Feature: --format option Background: Given a file named "example_spec.rb" with: - """ + """ruby describe "something" do it "does something that passes" do 5.should eq(5) diff --git a/features/command_line/line_number_appended_to_path.feature b/features/command_line/line_number_appended_to_path.feature index 84a05089d6..9790e61e06 100644 --- a/features/command_line/line_number_appended_to_path.feature +++ b/features/command_line/line_number_appended_to_path.feature @@ -6,7 +6,7 @@ Feature: line number appended to file path Background: Given a file named "example_spec.rb" with: - """ + """ruby describe "outer group" do it "first example in outer group" do @@ -28,7 +28,7 @@ Feature: line number appended to file path end """ And a file named "example2_spec.rb" with: - """ + """ruby describe "yet another group" do it "first example in second file" do end diff --git a/features/command_line/line_number_option.feature b/features/command_line/line_number_option.feature index 85d7d443d7..fd64d1974d 100644 --- a/features/command_line/line_number_option.feature +++ b/features/command_line/line_number_option.feature @@ -8,7 +8,7 @@ Feature: --line_number option Scenario: standard examples Given a file named "example_spec.rb" with: - """ + """ruby require "rspec/expectations" describe 9 do @@ -41,7 +41,7 @@ Feature: --line_number option Scenario: one liner Given a file named "example_spec.rb" with: - """ + """ruby require "rspec/expectations" describe 9 do diff --git a/features/command_line/pattern_option.feature b/features/command_line/pattern_option.feature index dfb6fa3d54..cc0b54491e 100644 --- a/features/command_line/pattern_option.feature +++ b/features/command_line/pattern_option.feature @@ -8,7 +8,7 @@ Feature: pattern option Scenario: default pattern Given a file named "spec/example_spec.rb" with: - """ + """ruby describe "addition" do it "adds things" do (1 + 2).should eq(3) @@ -20,7 +20,7 @@ Feature: pattern option Scenario: override the default pattern on the command line Given a file named "spec/example.spec" with: - """ + """ruby describe "addition" do it "adds things" do (1 + 2).should eq(3) diff --git a/features/command_line/rake_task.feature b/features/command_line/rake_task.feature index 0934894c5e..c56e658bae 100644 --- a/features/command_line/rake_task.feature +++ b/features/command_line/rake_task.feature @@ -4,7 +4,7 @@ Feature: rake task Scenario: default options with passing spec (prints command and exit status is 0) Given a file named "Rakefile" with: - """ + """ruby require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) @@ -12,7 +12,7 @@ Feature: rake task task :default => :spec """ And a file named "spec/thing_spec.rb" with: - """ + """ruby describe "something" do it "does something" do # pass @@ -20,12 +20,12 @@ Feature: rake task end """ When I run `rake` - Then the output should contain "ruby -S rspec" + Then the output should match /(ruby|rbx) -S rspec/ Then the exit status should be 0 Scenario: default options with failing spec (exit status is 1) Given a file named "Rakefile" with: - """ + """ruby require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) @@ -33,7 +33,7 @@ Feature: rake task task :default => :spec """ And a file named "spec/thing_spec.rb" with: - """ + """ruby describe "something" do it "does something" do fail @@ -45,7 +45,7 @@ Feature: rake task Scenario: fail_on_error = false with failing spec (exit status is 0) Given a file named "Rakefile" with: - """ + """ruby require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) do |t| @@ -55,7 +55,7 @@ Feature: rake task task :default => :spec """ And a file named "spec/thing_spec.rb" with: - """ + """ruby describe "something" do it "does something" do fail @@ -64,5 +64,59 @@ Feature: rake task """ When I run `rake` Then the exit status should be 0 - + Scenario: rspec_opts is specified in order to pass args to the rspec command + Given a file named "Rakefile" with: + """ruby + require 'rspec/core/rake_task' + + RSpec::Core::RakeTask.new(:spec) do |t| + t.rspec_opts = "--tag fast" + end + """ + And a file named "spec/thing_spec.rb" with: + """ruby + describe "something" do + it "has a tag", :fast => true do + # pass + end + + it "does not have a tag" do + fail + end + end + """ + When I run `rake spec` + Then the exit status should be 0 + Then the output should match: + """ + (ruby|rbx) -S rspec ./spec/thing_spec.rb --tag fast + """ + + Scenario: rspec_opts is specified using arguments to the rake task + Given a file named "Rakefile" with: + """ruby + require 'rspec/core/rake_task' + + RSpec::Core::RakeTask.new(:spec, :tag) do |t, task_args| + t.rspec_opts = "--tag #{task_args[:tag]}" + end + """ + And a file named "spec/thing_spec.rb" with: + """ruby + describe "something" do + it "has a tag", :fast => true do + # pass + end + + it "does not have a tag" do + fail + end + end + """ + When I run `rake spec[fast]` + Then the exit status should be 0 + Then the output should match: + """ + (ruby|rbx) -S rspec ./spec/thing_spec.rb --tag fast + """ diff --git a/features/command_line/ruby.feature b/features/command_line/ruby.feature index e9c31db254..65ea033269 100644 --- a/features/command_line/ruby.feature +++ b/features/command_line/ruby.feature @@ -9,7 +9,7 @@ Feature: run with ruby command Scenario: Given a file named "example_spec.rb" with: - """ + """ruby require 'rspec/autorun' describe 1 do diff --git a/features/command_line/tag.feature b/features/command_line/tag.feature index cb910ca1d7..34cd3b3297 100644 --- a/features/command_line/tag.feature +++ b/features/command_line/tag.feature @@ -16,7 +16,7 @@ Feature: --tag option Background: Given a file named "tagged_spec.rb" with: - """ + """ruby describe "group with tagged specs" do it "example I'm working now", :focus => true do; end it "special example with string", :type => 'special' do; end diff --git a/features/configuration/alias_example_to.feature b/features/configuration/alias_example_to.feature index 5fe274f07d..c488eeb638 100644 --- a/features/configuration/alias_example_to.feature +++ b/features/configuration/alias_example_to.feature @@ -8,7 +8,7 @@ Feature: alias_example_to Scenario: Use alias_example_to to define focused example Given a file named "alias_example_to_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.alias_example_to :fit, :focused => true c.filter_run :focused => true @@ -28,7 +28,7 @@ Feature: alias_example_to Scenario: use symbols as metadata Given a file named "use_symbols_as_metadata_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.treat_symbols_as_metadata_keys_with_true_values = true c.alias_example_to :fit, :focused diff --git a/features/configuration/custom_settings.feature b/features/configuration/custom_settings.feature index d3ad97812b..23772fc592 100644 --- a/features/configuration/custom_settings.feature +++ b/features/configuration/custom_settings.feature @@ -4,7 +4,7 @@ Feature: custom settings Scenario: simple setting (with defaults) Given a file named "additional_setting_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.add_setting :custom_setting end @@ -34,7 +34,7 @@ Feature: custom settings Scenario: default to true Given a file named "additional_setting_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.add_setting :custom_setting, :default => true end @@ -60,7 +60,7 @@ Feature: custom settings Scenario: overridden in a subsequent RSpec.configure block Given a file named "additional_setting_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.add_setting :custom_setting end diff --git a/features/configuration/default_path.feature b/features/configuration/default_path.feature index 6e6284cfed..4f2ae8451f 100644 --- a/features/configuration/default_path.feature +++ b/features/configuration/default_path.feature @@ -13,7 +13,7 @@ Feature: default_path Scenario: run `rspec` with default default_path (`spec` directory) Given a file named "spec/example_spec.rb" with: - """ + """ruby describe "an example" do it "passes" do end @@ -21,14 +21,14 @@ Feature: default_path """ When I run `rspec` Then the output should contain "1 example, 0 failures" - + Scenario: run `rspec` with customized default_path Given a file named ".rspec" with: """ --default_path behavior """ Given a file named "behavior/example_spec.rb" with: - """ + """ruby describe "an example" do it "passes" do end diff --git a/features/configuration/fail_fast.feature b/features/configuration/fail_fast.feature index a0deff28a1..c0cd1ec57d 100644 --- a/features/configuration/fail_fast.feature +++ b/features/configuration/fail_fast.feature @@ -6,13 +6,13 @@ Feature: fail fast Background: Given a file named "spec/spec_helper.rb" with: - """ + """ruby RSpec.configure {|c| c.fail_fast = true} """ Scenario: fail_fast with no failures (runs all examples) Given a file named "spec/example_spec.rb" with: - """ + """ruby describe "something" do it "passes" do end @@ -26,7 +26,7 @@ Feature: fail fast Scenario: fail_fast with first example failing (only runs the one example) Given a file named "spec/example_spec.rb" with: - """ + """ruby require "spec_helper" describe "something" do it "fails" do @@ -42,7 +42,7 @@ Feature: fail fast Scenario: fail_fast with multiple files, second example failing (only runs the first two examples) Given a file named "spec/example_1_spec.rb" with: - """ + """ruby require "spec_helper" describe "something" do it "passes" do @@ -60,7 +60,7 @@ Feature: fail fast end """ And a file named "spec/example_2_spec.rb" with: - """ + """ruby require "spec_helper" describe "something" do it "passes" do diff --git a/features/configuration/read_options_from_file.feature b/features/configuration/read_options_from_file.feature index 08211e239b..9ea4fd92b7 100644 --- a/features/configuration/read_options_from_file.feature +++ b/features/configuration/read_options_from_file.feature @@ -15,7 +15,7 @@ Feature: read command line configuration options from files --color """ And a file named "spec/example_spec.rb" with: - """ + """ruby describe "color_enabled" do context "when set with RSpec.configure" do before do @@ -39,7 +39,7 @@ Feature: read command line configuration options from files --format documentation """ And a file named "spec/example_spec.rb" with: - """ + """ruby describe "formatter set in custom options file" do it "sets formatter" do RSpec.configuration.formatters.first. @@ -60,7 +60,7 @@ Feature: read command line configuration options from files --color """ And a file named "spec/example_spec.rb" with: - """ + """ruby describe "custom options file" do it "causes .rspec to be ignored" do RSpec.configuration.color_enabled.should be_false @@ -76,7 +76,7 @@ Feature: read command line configuration options from files --format <%= true ? 'documentation' : 'progress' %> """ And a file named "spec/example_spec.rb" with: - """ + """ruby describe "formatter" do it "is set to documentation" do RSpec.configuration.formatters.first.should be_an(RSpec::Core::Formatters::DocumentationFormatter) diff --git a/features/example_groups/basic_structure.feature b/features/example_groups/basic_structure.feature index 3d3ca65d46..ad155ef19d 100644 --- a/features/example_groups/basic_structure.feature +++ b/features/example_groups/basic_structure.feature @@ -17,7 +17,7 @@ Feature: basic structure (describe/it) Scenario: one group, one example Given a file named "sample_spec.rb" with: - """ + """ruby describe "something" do it "does something" do end @@ -32,7 +32,7 @@ Feature: basic structure (describe/it) Scenario: nested example groups (using context) Given a file named "nested_example_groups_spec.rb" with: - """ + """ruby describe "something" do context "in one context" do it "does one thing" do diff --git a/features/example_groups/shared_context.feature b/features/example_groups/shared_context.feature index 476583b6c4..491faa8693 100644 --- a/features/example_groups/shared_context.feature +++ b/features/example_groups/shared_context.feature @@ -6,7 +6,7 @@ Feature: shared context Background: Given a file named "shared_stuff.rb" with: - """ + """ruby shared_context "shared stuff", :a => :b do before { @some_var = :some_value } def shared_method @@ -21,7 +21,7 @@ Feature: shared context Scenario: declare shared context and include it with include_context Given a file named "shared_context_example.rb" with: - """ + """ruby require "./shared_stuff.rb" describe "group that includes a shared context using 'include_context'" do @@ -49,7 +49,7 @@ Feature: shared context Scenario: declare shared context and include it with metadata Given a file named "shared_context_example.rb" with: - """ + """ruby require "./shared_stuff.rb" describe "group that includes a shared context using metadata", :a => :b do diff --git a/features/example_groups/shared_examples.feature b/features/example_groups/shared_examples.feature index 10c36bfafe..3ce834bcf2 100644 --- a/features/example_groups/shared_examples.feature +++ b/features/example_groups/shared_examples.feature @@ -6,10 +6,11 @@ Feature: shared examples needs to run. A shared group is included in another group using any of: - + include_examples "name" # include the examples in the current context it_behaves_like "name" # include the examples in a nested context it_should_behave_like "name" # include the examples in a nested context + matching metadata # include the examples in the current context WARNING: Files containing shared groups must be loaded before the files that use them. While there are conventions to handle this, RSpec does _not_ do @@ -27,7 +28,7 @@ Feature: shared examples 2. Put files containing shared examples in `spec/support/` and require files in that directory from `spec/spec_helper.rb`: - Dir["./spec/support/**/*.rb"].each {|f| require f} + Dir["./spec/support/**/*.rb"].sort.each {|f| require f} This is included in the generated `spec/spec_helper.rb` file in `rspec-rails` @@ -37,7 +38,7 @@ Feature: shared examples Scenario: shared examples group included in two groups in one file Given a file named "collection_spec.rb" with: - """ + """ruby require "set" shared_examples "a collection" do @@ -99,7 +100,7 @@ Feature: shared examples Scenario: Providing context to a shared group using a block Given a file named "shared_example_group_spec.rb" with: - """ + """ruby require "set" shared_examples "a collection object" do @@ -107,7 +108,7 @@ Feature: shared examples it "adds objects to the end of the collection" do collection << 1 collection << 2 - collection.to_a.should eq([1,2]) + expect(collection.to_a).to match_array([1, 2]) end end end @@ -141,7 +142,7 @@ Feature: shared examples Scenario: Passing parameters to a shared example group Given a file named "shared_example_group_params_spec.rb" with: - """ + """ruby shared_examples "a measurable object" do |measurement, measurement_methods| measurement_methods.each do |measurement_method| it "should return #{measurement} from ##{measurement_method}" do @@ -177,7 +178,7 @@ Feature: shared examples Scenario: Aliasing "it_should_behave_like" to "it_has_behavior" Given a file named "shared_example_group_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:' end @@ -202,3 +203,20 @@ Feature: shared examples has behavior: sortability responds to <=> """ + + Scenario: Sharing metadata automatically includes shared example groups + Given a file named "shared_example_metadata_spec.rb" with: + """ruby + shared_examples "shared stuff", :a => :b do + it 'runs wherever the metadata is shared' do + end + end + + describe String, :a => :b do + end + """ + When I run `rspec shared_example_metadata_spec.rb` + Then the output should contain: + """ + 1 example, 0 failures + """ diff --git a/features/expectation_framework_integration/configure_expectation_framework.feature b/features/expectation_framework_integration/configure_expectation_framework.feature index ba3d520897..d0d6cbe810 100644 --- a/features/expectation_framework_integration/configure_expectation_framework.feature +++ b/features/expectation_framework_integration/configure_expectation_framework.feature @@ -7,7 +7,7 @@ Feature: configure expectation framework * stdlib assertions * test/unit assertions in ruby 1.8 * minitest assertions in ruby 1.9 - * rspec/expecations _and_ stlib assertions + * rspec/expectations _and_ stlib assertions Note that when you do not use rspec-expectations, you must explicitly provide a description to every example. You cannot rely on the generated @@ -15,7 +15,7 @@ Feature: configure expectation framework Scenario: rspec-expectations can be used by default if nothing is configured Given a file named "example_spec.rb" with: - """ + """ruby RSpec::Matchers.define :be_a_multiple_of do |factor| match do |actual| actual % factor == 0 @@ -31,7 +31,7 @@ Feature: configure expectation framework Scenario: configure rspec-expectations (explicitly) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.expect_with :rspec end @@ -47,7 +47,7 @@ Feature: configure expectation framework Scenario: configure test/unit assertions (passing examples) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.expect_with :stdlib end @@ -65,7 +65,7 @@ Feature: configure expectation framework Scenario: configure test/unit assertions (failing examples) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.expect_with :stdlib end @@ -83,7 +83,7 @@ Feature: configure expectation framework Scenario: configure rspec/expecations AND test/unit assertions Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.expect_with :rspec, :stdlib end diff --git a/features/filtering/exclusion_filters.feature b/features/filtering/exclusion_filters.feature index 6ebfd40ed8..d79ca65658 100644 --- a/features/filtering/exclusion_filters.feature +++ b/features/filtering/exclusion_filters.feature @@ -8,7 +8,7 @@ Feature: exclusion filters Scenario: exclude an example Given a file named "spec/sample_spec.rb" with: - """ + """ruby RSpec.configure do |c| # declare an exclusion filter c.filter_run_excluding :broken => true @@ -29,7 +29,7 @@ Feature: exclusion filters Scenario: exclude a group Given a file named "spec/sample_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.filter_run_excluding :broken => true end @@ -54,7 +54,7 @@ Feature: exclusion filters Scenario: exclude multiple groups Given a file named "spec/sample_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.filter_run_excluding :broken => true end @@ -88,7 +88,7 @@ Feature: exclusion filters Scenario: before/after(:all) hooks in excluded example group are not run Given a file named "spec/before_after_all_exclusion_filter_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.filter_run_excluding :broken => true end @@ -119,7 +119,7 @@ Feature: exclusion filters Scenario: Use symbols as metadata Given a file named "symbols_as_metadata_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.treat_symbols_as_metadata_keys_with_true_values = true c.filter_run_excluding :broken diff --git a/features/filtering/if_and_unless.feature b/features/filtering/if_and_unless.feature index fd55667aa6..154a2b4bc5 100644 --- a/features/filtering/if_and_unless.feature +++ b/features/filtering/if_and_unless.feature @@ -5,7 +5,7 @@ Feature: :if and :unless Scenario: implicit :if filter Given a file named "implicit_if_filter_spec.rb" with: - """ + """ruby describe ":if => true group", :if => true do it(":if => true group :if => true example", :if => true) { } it(":if => true group :if => false example", :if => false) { } @@ -39,7 +39,7 @@ Feature: :if and :unless Scenario: implicit :unless filter Given a file named "implicit_unless_filter_spec.rb" with: - """ + """ruby describe ":unless => true group", :unless => true do it(":unless => true group :unless => true example", :unless => true) { } it(":unless => true group :unless => false example", :unless => false) { } @@ -73,7 +73,7 @@ Feature: :if and :unless Scenario: combining implicit filter with explicit inclusion filter Given a file named "explicit_inclusion_filter_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.filter_run :focus => true end @@ -106,7 +106,7 @@ Feature: :if and :unless Scenario: combining implicit filter with explicit exclusion filter Given a file named "explicit_exclusion_filter_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.filter_run_excluding :broken => true end @@ -139,7 +139,7 @@ Feature: :if and :unless Scenario: override implicit :if and :unless exclusion filters Given a file named "override_implicit_filters_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.filter_run_excluding :if => :exclude_me, :unless => :exclude_me_for_unless end diff --git a/features/filtering/inclusion_filters.feature b/features/filtering/inclusion_filters.feature index 2aca9ce5d8..4bef6ee0f8 100644 --- a/features/filtering/inclusion_filters.feature +++ b/features/filtering/inclusion_filters.feature @@ -9,7 +9,7 @@ Feature: inclusion filters Background: Given a file named "spec/spec_helper.rb" with: - """ + """ruby RSpec.configure do |c| c.filter_run_including :focus => true end @@ -17,7 +17,7 @@ Feature: inclusion filters Scenario: focus on an example Given a file named "spec/sample_spec.rb" with: - """ + """ruby require "spec_helper" describe "something" do @@ -34,7 +34,7 @@ Feature: inclusion filters Scenario: focus on a group Given a file named "spec/sample_spec.rb" with: - """ + """ruby require "spec_helper" describe "group 1", :focus => true do @@ -57,7 +57,7 @@ Feature: inclusion filters Scenario: before/after(:all) hooks in unmatched example group are not run Given a file named "spec/before_after_all_inclusion_filter_spec.rb" with: - """ + """ruby require "spec_helper" describe "group 1", :focus => true do @@ -86,7 +86,7 @@ Feature: inclusion filters Scenario: Use symbols as metadata Given a file named "symbols_as_metadata_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.treat_symbols_as_metadata_keys_with_true_values = true c.filter_run :current_example diff --git a/features/filtering/run_all_when_everything_filtered.feature b/features/filtering/run_all_when_everything_filtered.feature index f6a1008f61..e22263bc9c 100644 --- a/features/filtering/run_all_when_everything_filtered.feature +++ b/features/filtering/run_all_when_everything_filtered.feature @@ -1,12 +1,12 @@ Feature: run all when everything filtered - Use the run_all_when_everything_filtered configuration option to do just + Use the `run_all_when_everything_filtered` configuration option to do just that. This works well when paired with an inclusion filter like ":focus => true", as it will run all the examples when none match the inclusion filter. Background: Given a file named "spec/spec_helper.rb" with: - """ + """ruby RSpec.configure do |c| c.filter_run :focus => true c.run_all_when_everything_filtered = true @@ -15,7 +15,7 @@ Feature: run all when everything filtered Scenario: no examples match filter (runs all examples) Given a file named "spec/sample_spec.rb" with: - """ + """ruby require "spec_helper" describe "group 1" do diff --git a/features/formatters/custom_formatter.feature b/features/formatters/custom_formatter.feature index a9157443f0..a95a852f6c 100644 --- a/features/formatters/custom_formatter.feature +++ b/features/formatters/custom_formatter.feature @@ -11,7 +11,7 @@ Feature: custom formatters Scenario: custom formatter Given a file named "custom_formatter.rb" with: - """ + """ruby require "rspec/core/formatters/base_text_formatter" class CustomFormatter < RSpec::Core::Formatters::BaseTextFormatter @@ -25,7 +25,7 @@ Feature: custom formatters end """ And a file named "example_spec.rb" with: - """ + """ruby describe "my group" do specify "my example" do end diff --git a/features/formatters/json_formatter.feature b/features/formatters/json_formatter.feature new file mode 100644 index 0000000000..9bac429976 --- /dev/null +++ b/features/formatters/json_formatter.feature @@ -0,0 +1,30 @@ +Feature: JSON formatter + + Scenario: Formatting example names for retry + Given a file named "various_spec.rb" with: + """ruby + describe "Various" do + it "fails" do + "fail".should eq("succeed") + end + + it "succeeds" do + "succeed".should eq("succeed") + end + + it "pends" + end + """ + When I run `rspec various_spec.rb --format j` + Then the output should contain all of these: + |"summary_line":"3 examples, 1 failure, 1 pending"| + |"examples":[ | + |"description":"fails" | + |"full_description":"Various fails" | + |"status":"failed" | + |"file_path":"./various_spec.rb" | + |"line_number":2 | + |"exception":{ | + |"class":"RSpec::Expectations::ExpectationNotMetError"| + + And the exit status should be 1 diff --git a/features/formatters/text_formatter.feature b/features/formatters/text_formatter.feature index e94390e43c..6ae1fb7e34 100644 --- a/features/formatters/text_formatter.feature +++ b/features/formatters/text_formatter.feature @@ -6,7 +6,7 @@ Feature: text formatter Scenario: Backtrace formatting for failing specs in multiple files Given a file named "string_spec.rb" with: - """ + """ruby describe String do it "has a failing example" do "foo".reverse.should eq("ofo") @@ -14,7 +14,7 @@ Feature: text formatter end """ And a file named "integer_spec.rb" with: - """ + """ruby describe Integer do it "has a failing example" do (7 + 5).should eq(11) @@ -24,8 +24,6 @@ Feature: text formatter When I run `rspec integer_spec.rb string_spec.rb` Then the backtrace-normalized output should contain: """ - Failures: - 1) Integer has a failing example Failure/Error: (7 + 5).should eq(11) @@ -34,7 +32,9 @@ Feature: text formatter (compared using ==) # ./integer_spec.rb:3 - + """ + And the backtrace-normalized output should contain: + """ 2) String has a failing example Failure/Error: "foo".reverse.should eq("ofo") diff --git a/features/helper_methods/arbitrary_methods.feature b/features/helper_methods/arbitrary_methods.feature index 1b6105e7c8..26968b4fe0 100644 --- a/features/helper_methods/arbitrary_methods.feature +++ b/features/helper_methods/arbitrary_methods.feature @@ -7,7 +7,7 @@ Feature: arbitrary helper methods Scenario: use a method defined in the same group Given a file named "example_spec.rb" with: - """ + """ruby describe "an example" do def help :available @@ -23,7 +23,7 @@ Feature: arbitrary helper methods Scenario: use a method defined in a parent group Given a file named "example_spec.rb" with: - """ + """ruby describe "an example" do def help :available diff --git a/features/helper_methods/let.feature b/features/helper_methods/let.feature index f5a58c9e28..26f5f7cb0f 100644 --- a/features/helper_methods/let.feature +++ b/features/helper_methods/let.feature @@ -9,7 +9,7 @@ Feature: let and let! Scenario: use let to define memoized helper method Given a file named "let_spec.rb" with: - """ + """ruby $count = 0 describe "let" do let(:count) { $count += 1 } @@ -29,7 +29,7 @@ Feature: let and let! Scenario: use let! to define a memoized helper method that is called in a before hook Given a file named "let_bang_spec.rb" with: - """ + """ruby $count = 0 describe "let!" do invocation_order = [] diff --git a/features/helper_methods/modules.feature b/features/helper_methods/modules.feature index f56ecc8546..ce7294a9bd 100644 --- a/features/helper_methods/modules.feature +++ b/features/helper_methods/modules.feature @@ -15,7 +15,7 @@ Feature: Define helper methods in a module Background: Given a file named "helpers.rb" with: - """ + """ruby module Helpers def help :available @@ -25,7 +25,7 @@ Feature: Define helper methods in a module Scenario: include a module in all example groups Given a file named "include_module_spec.rb" with: - """ + """ruby require './helpers' RSpec.configure do |c| @@ -43,7 +43,7 @@ Feature: Define helper methods in a module Scenario: extend a module in all example groups Given a file named "extend_module_spec.rb" with: - """ + """ruby require './helpers' RSpec.configure do |c| @@ -64,7 +64,7 @@ Feature: Define helper methods in a module Scenario: include a module in only some example groups Given a file named "include_module_in_some_groups_spec.rb" with: - """ + """ruby require './helpers' RSpec.configure do |c| @@ -88,7 +88,7 @@ Feature: Define helper methods in a module Scenario: extend a module in only some example groups Given a file named "extend_module_in_only_some_groups_spec.rb" with: - """ + """ruby require './helpers' RSpec.configure do |c| @@ -118,7 +118,7 @@ Feature: Define helper methods in a module Scenario: use symbols as metadata Given a file named "symbols_as_metadata_spec.rb" with: - """ + """ruby require './helpers' RSpec.configure do |c| diff --git a/features/hooks/around_hooks.feature b/features/hooks/around_hooks.feature index 97cac2f283..d367e77d0f 100644 --- a/features/hooks/around_hooks.feature +++ b/features/hooks/around_hooks.feature @@ -18,7 +18,7 @@ Feature: around hooks Scenario: use the example as a proc within the block passed to around() Given a file named "example_spec.rb" with: - """ + """ruby class Database def self.transaction puts "open transaction" @@ -47,7 +47,7 @@ Feature: around hooks Scenario: invoke the example using run() Given a file named "example_spec.rb" with: - """ + """ruby describe "around hook" do around(:each) do |example| puts "around each before" @@ -70,7 +70,7 @@ Feature: around hooks Scenario: access the example metadata Given a file named "example_spec.rb" with: - """ + """ruby describe "something" do around(:each) do |example| puts example.metadata[:foo] @@ -86,7 +86,7 @@ Feature: around hooks Scenario: define a global around hook Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.around(:each) do |example| puts "around each before" @@ -111,7 +111,7 @@ Feature: around hooks Scenario: before/after(:each) hooks are wrapped by the around hook Given a file named "example_spec.rb" with: - """ + """ruby describe "around filter" do around(:each) do |example| puts "around each before" @@ -144,7 +144,7 @@ Feature: around hooks Scenario: before/after(:all) hooks are NOT wrapped by the around hook Given a file named "example_spec.rb" with: - """ + """ruby describe "around filter" do around(:each) do |example| puts "around each before" @@ -177,7 +177,7 @@ Feature: around hooks Scenario: examples run by an around block are run in the configured context Given a file named "example_spec.rb" with: - """ + """ruby module IncludedInConfigureBlock def included_in_configure_block; true; end end @@ -201,7 +201,7 @@ Feature: around hooks Scenario: implicitly pending examples are detected as Not yet implemented Given a file named "example_spec.rb" with: - """ + """ruby describe "implicit pending example" do around(:each) do |example| example.run @@ -222,7 +222,7 @@ Feature: around hooks Scenario: explicitly pending examples are detected as pending Given a file named "example_spec.rb" with: - """ + """ruby describe "explicit pending example" do around(:each) do |example| example.run @@ -243,7 +243,7 @@ Feature: around hooks Scenario: multiple around hooks in the same scope Given a file named "example_spec.rb" with: - """ + """ruby describe "if there are multiple around hooks in the same scope" do around(:each) do |example| puts "first around hook before" @@ -276,7 +276,7 @@ Feature: around hooks Scenario: around hooks in multiple scopes Given a file named "example_spec.rb" with: - """ + """ruby describe "if there are around hooks in an outer scope" do around(:each) do |example| puts "first outermost around hook before" diff --git a/features/hooks/before_and_after_hooks.feature b/features/hooks/before_and_after_hooks.feature index 4edd9c715d..1de846cb91 100644 --- a/features/hooks/before_and_after_hooks.feature +++ b/features/hooks/before_and_after_hooks.feature @@ -21,9 +21,13 @@ Feature: before and after hooks `before` and `after` hooks can be defined directly in the example groups they should run in, or in a global RSpec.configure block. + Setting instance variables are not supported in `before(:suite)`. + + Mocks are only supported in `before(:each)`. + Scenario: define before(:each) block Given a file named "before_each_spec.rb" with: - """ + """ruby require "rspec/expectations" class Thing @@ -57,7 +61,7 @@ Feature: before and after hooks Scenario: define before(:all) block in example group Given a file named "before_all_spec.rb" with: - """ + """ruby require "rspec/expectations" class Thing @@ -94,7 +98,7 @@ Feature: before and after hooks Scenario: failure in before(:all) block Given a file named "before_all_spec.rb" with: - """ + """ruby describe "an error in before(:all)" do before(:all) do raise "oops" @@ -149,7 +153,7 @@ Feature: before and after hooks Scenario: failure in after(:all) block Given a file named "after_all_spec.rb" with: - """ + """ruby describe "an error in after(:all)" do after(:all) do raise StandardError.new("Boom!") @@ -172,7 +176,7 @@ Feature: before and after hooks Scenario: define before and after blocks in configuration Given a file named "befores_in_configuration_spec.rb" with: - """ + """ruby require "rspec/expectations" RSpec.configure do |config| @@ -202,7 +206,7 @@ Feature: before and after hooks Scenario: before/after blocks are run in order Given a file named "ensure_block_order_spec.rb" with: - """ + """ruby require "rspec/expectations" describe "before and after callbacks" do @@ -238,7 +242,7 @@ Feature: before and after hooks Scenario: before/after blocks defined in config are run in order Given a file named "configuration_spec.rb" with: - """ + """ruby require "rspec/expectations" RSpec.configure do |config| @@ -285,7 +289,7 @@ Feature: before and after hooks Scenario: before/after all blocks are run once Given a file named "before_and_after_all_spec.rb" with: - """ + """ruby describe "before and after callbacks" do before(:all) do puts "outer before all" @@ -343,7 +347,7 @@ Feature: before and after hooks Scenario: nested examples have access to state set in outer before(:all) Given a file named "before_all_spec.rb" with: - """ + """ruby describe "something" do before :all do @value = 123 @@ -373,7 +377,7 @@ Feature: before and after hooks Scenario: before/after all blocks have access to state Given a file named "before_and_after_all_spec.rb" with: - """ + """ruby describe "before and after callbacks" do before(:all) do @outer_state = "set in outer before all" @@ -408,7 +412,7 @@ Feature: before and after hooks Scenario: exception in before(:each) is captured and reported as failure Given a file named "error_in_before_each_spec.rb" with: - """ + """ruby describe "error in before(:each)" do before(:each) do raise "this error" diff --git a/features/hooks/filtering.feature b/features/hooks/filtering.feature index 94deacab19..4c2a6cb6ab 100644 --- a/features/hooks/filtering.feature +++ b/features/hooks/filtering.feature @@ -17,7 +17,7 @@ Feature: filters Scenario: filter `before(:each)` hooks using arbitrary metadata Given a file named "filter_before_each_hooks_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.before(:each, :foo => :bar) do invoked_hooks << :before_each_foo_bar @@ -49,7 +49,7 @@ Feature: filters Scenario: filter `after(:each)` hooks using arbitrary metadata Given a file named "filter_after_each_hooks_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.after(:each, :foo => :bar) do raise "boom!" @@ -79,7 +79,7 @@ Feature: filters Scenario: filter around(:each) hooks using arbitrary metadata Given a file named "filter_around_each_hooks_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.around(:each, :foo => :bar) do |example| order << :before_around_each_foo_bar @@ -115,7 +115,7 @@ Feature: filters Scenario: filter before(:all) hooks using arbitrary metadata Given a file named "filter_before_all_hooks_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.before(:all, :foo => :bar) { @hook = :before_all_foo_bar } end @@ -151,7 +151,7 @@ Feature: filters Scenario: filter after(:all) hooks using arbitrary metadata Given a file named "filter_after_all_hooks_spec.rb" with: - """ + """ruby example_msgs = [] RSpec.configure do |config| @@ -195,7 +195,7 @@ Feature: filters Scenario: Use symbols as metadata Given a file named "less_verbose_metadata_filter.rb" with: - """ + """ruby RSpec.configure do |c| c.treat_symbols_as_metadata_keys_with_true_values = true c.before(:each, :before_each) { puts "before each" } diff --git a/features/metadata/current_example.feature b/features/metadata/current_example.feature index bac8c702e4..5fee6b46e3 100644 --- a/features/metadata/current_example.feature +++ b/features/metadata/current_example.feature @@ -5,7 +5,7 @@ Feature: current example Scenario: access the example object from within an example Given a file named "spec/example_spec.rb" with: - """ + """ruby describe "an example" do it "knows itself as example" do example.description.should eq("knows itself as example") diff --git a/features/metadata/described_class.feature b/features/metadata/described_class.feature index 7a2675be13..237d4cf0b9 100644 --- a/features/metadata/described_class.feature +++ b/features/metadata/described_class.feature @@ -5,7 +5,7 @@ Feature: described class Scenario: access the described class from the example Given a file named "spec/example_spec.rb" with: - """ + """ruby describe Fixnum do it "is available as described_class" do described_class.should eq(Fixnum) diff --git a/features/metadata/user_defined.feature b/features/metadata/user_defined.feature index a37f4f8abf..faa6634e08 100644 --- a/features/metadata/user_defined.feature +++ b/features/metadata/user_defined.feature @@ -23,7 +23,7 @@ Feature: User-defined metadata Scenario: define group metadata using a hash Given a file named "define_group_metadata_with_hash_spec.rb" with: - """ + """ruby describe "a group with user-defined metadata", :foo => 17 do it 'has access to the metadata in the example' do example.metadata[:foo].should eq(17) @@ -49,7 +49,7 @@ Feature: User-defined metadata Scenario: define example metadata using a hash Given a file named "define_example_metadata_with_hash_spec.rb" with: - """ + """ruby describe "a group with no user-defined metadata" do it 'has an example with metadata', :foo => 17 do example.metadata[:foo].should eq(17) @@ -68,7 +68,7 @@ Feature: User-defined metadata Scenario: override user-defined metadata Given a file named "override_metadata_spec.rb" with: - """ + """ruby describe "a group with user-defined metadata", :foo => 'bar' do it 'can be overridden by an example', :foo => 'bazz' do example.metadata[:foo].should == 'bazz' @@ -86,7 +86,7 @@ Feature: User-defined metadata Scenario: less verbose metadata Given a file named "less_verbose_metadata_spec.rb" with: - """ + """ruby RSpec.configure do |c| c.treat_symbols_as_metadata_keys_with_true_values = true end diff --git a/features/mock_framework_integration/use_any_framework.feature b/features/mock_framework_integration/use_any_framework.feature index ab4a4d1224..473e6ac7f0 100644 --- a/features/mock_framework_integration/use_any_framework.feature +++ b/features/mock_framework_integration/use_any_framework.feature @@ -6,20 +6,20 @@ Feature: mock with an alternative framework A mock framework adapter must expose three methods: - * setup_mocks_for_rspec + * `setup_mocks_for_rspec` * called before each example is run - * verify_mocks_for_rspec + * `verify_mocks_for_rspec` * called after each example is run * this is where message expectation failures should result in an error with the appropriate failure message - * teardown_mocks_for_rspec - * called after verify_mocks_for_rspec + * `teardown_mocks_for_rspec` + * called after `verify_mocks_for_rspec` * use this to clean up resources, restore objects to earlier state, etc * guaranteed to run even if there are failures Scenario: Mock with alternate framework Given a file named "expector.rb" with: - """ + """ruby class Expector class << self def expectors @@ -80,7 +80,7 @@ Feature: mock with an alternative framework """ Given a file named "example_spec.rb" with: - """ + """ruby require File.expand_path("../expector", __FILE__) RSpec.configure do |config| diff --git a/features/mock_framework_integration/use_flexmock.feature b/features/mock_framework_integration/use_flexmock.feature index 261832e5c2..408b055c04 100644 --- a/features/mock_framework_integration/use_flexmock.feature +++ b/features/mock_framework_integration/use_flexmock.feature @@ -4,7 +4,7 @@ Feature: mock with flexmock Scenario: passing message expectation Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :flexmock end @@ -22,7 +22,7 @@ Feature: mock with flexmock Scenario: failing message expecation Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :flexmock end @@ -39,7 +39,7 @@ Feature: mock with flexmock Scenario: failing message expectation in pending block (remains pending) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :flexmock end @@ -59,7 +59,7 @@ Feature: mock with flexmock Scenario: passing message expectation in pending block (fails) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :flexmock end @@ -81,7 +81,7 @@ Feature: mock with flexmock Scenario: accessing RSpec.configuration.mock_framework.framework_name Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :flexmock end diff --git a/features/mock_framework_integration/use_mocha.feature b/features/mock_framework_integration/use_mocha.feature index c1595166c2..bb29e9412c 100644 --- a/features/mock_framework_integration/use_mocha.feature +++ b/features/mock_framework_integration/use_mocha.feature @@ -4,7 +4,7 @@ Feature: mock with mocha Scenario: passing message expectation Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :mocha end @@ -22,7 +22,7 @@ Feature: mock with mocha Scenario: failing message expecation Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :mocha end @@ -39,7 +39,7 @@ Feature: mock with mocha Scenario: failing message expectation in pending block (remains pending) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :mocha end @@ -59,7 +59,7 @@ Feature: mock with mocha Scenario: passing message expectation in pending block (fails) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :mocha end @@ -81,7 +81,7 @@ Feature: mock with mocha Scenario: accessing RSpec.configuration.mock_framework.framework_name Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :mocha end diff --git a/features/mock_framework_integration/use_rr.feature b/features/mock_framework_integration/use_rr.feature index c3cf175e05..08c4e19d34 100644 --- a/features/mock_framework_integration/use_rr.feature +++ b/features/mock_framework_integration/use_rr.feature @@ -4,7 +4,7 @@ Feature: mock with rr Scenario: passing message expectation Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rr end @@ -22,7 +22,7 @@ Feature: mock with rr Scenario: failing message expecation Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rr end @@ -39,7 +39,7 @@ Feature: mock with rr Scenario: failing message expectation in pending block (remains pending) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rr end @@ -59,7 +59,7 @@ Feature: mock with rr Scenario: passing message expectation in pending block (fails) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rr end @@ -81,7 +81,7 @@ Feature: mock with rr Scenario: accessing RSpec.configuration.mock_framework.framework_name Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rr end diff --git a/features/mock_framework_integration/use_rspec.feature b/features/mock_framework_integration/use_rspec.feature index 79d44214db..9ade6e7d5b 100644 --- a/features/mock_framework_integration/use_rspec.feature +++ b/features/mock_framework_integration/use_rspec.feature @@ -5,7 +5,7 @@ Feature: mock with rspec Scenario: passing message expectation Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rspec end @@ -23,7 +23,7 @@ Feature: mock with rspec Scenario: failing message expecation Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rspec end @@ -40,7 +40,7 @@ Feature: mock with rspec Scenario: failing message expectation in pending block (remains pending) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rspec end @@ -60,7 +60,7 @@ Feature: mock with rspec Scenario: passing message expectation in pending block (fails) Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rspec end @@ -82,7 +82,7 @@ Feature: mock with rspec Scenario: accessing RSpec.configuration.mock_framework.framework_name Given a file named "example_spec.rb" with: - """ + """ruby RSpec.configure do |config| config.mock_framework = :rspec end diff --git a/features/pending/pending_examples.feature b/features/pending/pending_examples.feature index 78f952a897..68b9db24da 100644 --- a/features/pending/pending_examples.feature +++ b/features/pending/pending_examples.feature @@ -5,7 +5,7 @@ Feature: pending examples Scenario: pending implementation Given a file named "example_without_block_spec.rb" with: - """ + """ruby describe "an example" do it "is a pending example" end @@ -16,9 +16,9 @@ Feature: pending examples And the output should contain "Not yet implemented" And the output should contain "example_without_block_spec.rb:2" - Scenario: pending any arbitary reason, with no block + Scenario: pending any arbitrary reason, with no block Given a file named "pending_without_block_spec.rb" with: - """ + """ruby describe "an example" do it "is implemented but waiting" do pending("something else getting finished") @@ -37,9 +37,9 @@ Feature: pending examples # ./pending_without_block_spec.rb:2 """ - Scenario: pending any arbitary reason, with a block that fails + Scenario: pending any arbitrary reason, with a block that fails Given a file named "pending_with_failing_block_spec.rb" with: - """ + """ruby describe "an example" do it "is implemented but waiting" do pending("something else getting finished") do @@ -59,9 +59,9 @@ Feature: pending examples # ./pending_with_failing_block_spec.rb:2 """ - Scenario: pending any arbitary reason, with a block that passes + Scenario: pending any arbitrary reason, with a block that passes Given a file named "pending_with_passing_block_spec.rb" with: - """ + """ruby describe "an example" do it "is implemented but waiting" do pending("something else getting finished") do @@ -79,7 +79,7 @@ Feature: pending examples Scenario: temporarily pending by prefixing `it`, `specify`, or `example` with an x Given a file named "temporarily_pending_spec.rb" with: - """ + """ruby describe "an example" do xit "is pending using xit" do end @@ -110,7 +110,7 @@ Feature: pending examples Scenario: example with no docstring and pending method using documentation formatter Given a file named "pending_with_no_docstring_spec.rb" with: - """ + """ruby describe "an example" do it "checks something" do (3+4).should eq(7) @@ -132,7 +132,7 @@ Feature: pending examples Scenario: pending with no docstring using documentation formatter Given a file named "pending_with_no_docstring_spec.rb" with: - """ + """ruby describe "an example" do it "checks something" do (3+4).should eq(7) @@ -154,7 +154,7 @@ Feature: pending examples Scenario: conditionally pending examples Given a file named "conditionally_pending_spec.rb" with: - """ + """ruby describe "a failing spec" do def run_test; raise "failure"; end diff --git a/features/spec_files/arbitrary_file_suffix.feature b/features/spec_files/arbitrary_file_suffix.feature index 915d05fbbc..1e3439ccf7 100644 --- a/features/spec_files/arbitrary_file_suffix.feature +++ b/features/spec_files/arbitrary_file_suffix.feature @@ -2,7 +2,7 @@ Feature: arbitrary file suffix Scenario: .spec Given a file named "a.spec" with: - """ + """ruby describe "something" do it "does something" do 3.should eq(3) diff --git a/features/step_definitions/additional_cli_steps.rb b/features/step_definitions/additional_cli_steps.rb index bbbe14e370..9603587602 100644 --- a/features/step_definitions/additional_cli_steps.rb +++ b/features/step_definitions/additional_cli_steps.rb @@ -1,3 +1,5 @@ +require 'rspec/core' # to fix annoying "undefined method `configuration' for RSpec:Module (NoMethodError)" + Then /^the output should contain all of these:$/ do |table| table.raw.flatten.each do |string| assert_partial_output(string, all_output) diff --git a/features/subject/attribute_of_subject.feature b/features/subject/attribute_of_subject.feature index 0f09049c5b..b7788c62e7 100644 --- a/features/subject/attribute_of_subject.feature +++ b/features/subject/attribute_of_subject.feature @@ -23,7 +23,7 @@ Feature: attribute of subject Scenario: specify value of an attribute Given a file named "example_spec.rb" with: - """ + """ruby describe Array do context "when first created" do its(:size) { should eq(0) } @@ -41,7 +41,7 @@ Feature: attribute of subject Scenario: specify value of a nested attribute Given a file named "example_spec.rb" with: - """ + """ruby class Person attr_reader :phone_numbers def initialize @@ -72,7 +72,7 @@ Feature: attribute of subject Scenario: specify value of an attribute of a hash Given a file named "example_spec.rb" with: - """ + """ruby describe Hash do context "with two items" do subject do @@ -88,7 +88,7 @@ Feature: attribute of subject Scenario: specify value for key in a hash Given a file named "example_spec.rb" with: - """ + """ruby describe Hash do context "with keys :one and 'two'" do subject do @@ -105,7 +105,7 @@ Feature: attribute of subject Scenario: specify value for key in a hash-like object Given a file named "example_spec.rb" with: - """ + """ruby require 'matrix' describe Matrix do diff --git a/features/subject/explicit_subject.feature b/features/subject/explicit_subject.feature index cdf8ae69b5..ee14febefe 100644 --- a/features/subject/explicit_subject.feature +++ b/features/subject/explicit_subject.feature @@ -9,7 +9,7 @@ Feature: explicit subject Scenario: subject in top level group Given a file named "top_level_subject_spec.rb" with: - """ + """ruby describe Array, "with some elements" do subject { [1,2,3] } it "should have the prescribed elements" do @@ -22,7 +22,7 @@ Feature: explicit subject Scenario: subject in a nested group Given a file named "nested_subject_spec.rb" with: - """ + """ruby describe Array do subject { [1,2,3] } describe "with some elements" do @@ -37,7 +37,7 @@ Feature: explicit subject Scenario: access subject from before block Given a file named "top_level_subject_spec.rb" with: - """ + """ruby describe Array, "with some elements" do subject { [] } before { subject.push(1,2,3) } @@ -51,7 +51,7 @@ Feature: explicit subject Scenario: invoke helper method from subject block Given a file named "helper_subject_spec.rb" with: - """ + """ruby describe Array do def prepared_array; [1,2,3] end subject { prepared_array } @@ -67,7 +67,7 @@ Feature: explicit subject Scenario: subject block is invoked at most once per example Given a file named "nil_subject_spec.rb" with: - """ + """ruby describe Array do describe "#[]" do context "with index out of bounds" do diff --git a/features/subject/implicit_receiver.feature b/features/subject/implicit_receiver.feature index 5f9518d521..209bbe6536 100644 --- a/features/subject/implicit_receiver.feature +++ b/features/subject/implicit_receiver.feature @@ -5,7 +5,7 @@ Feature: implicit receiver Scenario: implicit subject Given a file named "example_spec.rb" with: - """ + """ruby describe Array do describe "when first created" do it { should be_empty } @@ -17,7 +17,7 @@ Feature: implicit receiver Scenario: explicit subject Given a file named "example_spec.rb" with: - """ + """ruby describe Array do describe "with 3 items" do subject { [1,2,3] } diff --git a/features/subject/implicit_subject.feature b/features/subject/implicit_subject.feature index c7f3ceca55..b8ec5af316 100644 --- a/features/subject/implicit_subject.feature +++ b/features/subject/implicit_subject.feature @@ -9,7 +9,7 @@ Feature: implicitly defined subject Scenario: subject exposed in top level group Given a file named "top_level_subject_spec.rb" with: - """ + """ruby describe Array do it "should be empty when first created" do subject.should be_empty @@ -21,7 +21,7 @@ Feature: implicitly defined subject Scenario: subject in a nested group Given a file named "nested_subject_spec.rb" with: - """ + """ruby describe Array do describe "when first created" do it "should be empty" do @@ -35,7 +35,7 @@ Feature: implicitly defined subject Scenario: subject in a nested group with a different class (outermost wins) Given a file named "nested_subject_spec.rb" with: - """ + """ruby class ArrayWithOneElement < Array def initialize(*) super diff --git a/lib/autotest/rspec2.rb b/lib/autotest/rspec2.rb index 50d07f6c1c..70a301f295 100644 --- a/lib/autotest/rspec2.rb +++ b/lib/autotest/rspec2.rb @@ -47,7 +47,7 @@ def consolidate_failures(failed) # Overrides Autotest's implementation to generate the rspec command to run def make_test_cmd(files_to_test) files_to_test.empty? ? '' : - "#{prefix}#{ruby}#{suffix} -S '#{RSPEC_EXECUTABLE}' --tty #{normalize(files_to_test).keys.flatten.map { |f| "'#{f}'"}.join(' ')}" + "#{prefix}'#{ruby}'#{suffix} -S '#{RSPEC_EXECUTABLE}' --tty #{normalize(files_to_test).keys.flatten.map { |f| "'#{f}'"}.join(' ')}" end # Generates a map of filenames to Arrays for Autotest diff --git a/lib/rspec/core.rb b/lib/rspec/core.rb index a39a06e253..63bdf0e8bb 100644 --- a/lib/rspec/core.rb +++ b/lib/rspec/core.rb @@ -1,43 +1,45 @@ -if defined?(require_relative) - # @private - def require_rspec(path) +require_rspec = if defined?(require_relative) + lambda do |path| require_relative path end else - # @private - def require_rspec(path) + lambda do |path| require "rspec/#{path}" end end require 'set' require 'rbconfig' -require_rspec 'core/filter_manager' -require_rspec 'core/dsl' -require_rspec 'core/extensions' -require_rspec 'core/load_path' -require_rspec 'core/deprecation' -require_rspec 'core/backward_compatibility' -require_rspec 'core/reporter' - -require_rspec 'core/metadata_hash_builder' -require_rspec 'core/hooks' -require_rspec 'core/subject' -require_rspec 'core/let' -require_rspec 'core/metadata' -require_rspec 'core/pending' - -require_rspec 'core/world' -require_rspec 'core/configuration' -require_rspec 'core/project_initializer' -require_rspec 'core/option_parser' -require_rspec 'core/configuration_options' -require_rspec 'core/command_line' -require_rspec 'core/runner' -require_rspec 'core/example' -require_rspec 'core/shared_example_group' -require_rspec 'core/example_group' -require_rspec 'core/version' +require_rspec['core/filter_manager'] +require_rspec['core/dsl'] +require_rspec['core/extensions/kernel'] +require_rspec['core/extensions/instance_eval_with_args'] +require_rspec['core/extensions/module_eval_with_args'] +require_rspec['core/extensions/ordered'] +require_rspec['core/load_path'] +require_rspec['core/deprecation'] +require_rspec['core/backward_compatibility'] +require_rspec['core/reporter'] + +require_rspec['core/metadata_hash_builder'] +require_rspec['core/hooks'] +require_rspec['core/subject'] +require_rspec['core/let'] +require_rspec['core/metadata'] +require_rspec['core/pending'] +require_rspec['core/formatters'] + +require_rspec['core/world'] +require_rspec['core/configuration'] +require_rspec['core/project_initializer'] +require_rspec['core/option_parser'] +require_rspec['core/configuration_options'] +require_rspec['core/command_line'] +require_rspec['core/runner'] +require_rspec['core/example'] +require_rspec['core/shared_example_group'] +require_rspec['core/example_group'] +require_rspec['core/version'] module RSpec autoload :SharedContext, 'rspec/core/shared_context' @@ -77,6 +79,20 @@ def self.reset # @see RSpec.configure # @see Core::Configuration def self.configuration + if block_given? + RSpec.warn_deprecation <<-WARNING + +***************************************************************** +DEPRECATION WARNING + +* RSpec.configuration with a block is deprecated and has no effect. +* please use RSpec.configure with a block instead. + +Called from #{caller(0)[1]} +***************************************************************** + +WARNING + end @configuration ||= RSpec::Core::Configuration.new end @@ -104,6 +120,11 @@ def self.windows_os? end module Core + # @private + # This avoids issues with reporting time caused by examples that + # change the value/meaning of Time.now without properly restoring + # it. + Time = ::Time.dup end def self.const_missing(name) @@ -123,4 +144,4 @@ def self.const_missing(name) end end -require_rspec 'core/backward_compatibility' +require_rspec['core/backward_compatibility'] diff --git a/lib/rspec/core/configuration.rb b/lib/rspec/core/configuration.rb index fa87ed7908..be4e4052b6 100644 --- a/lib/rspec/core/configuration.rb +++ b/lib/rspec/core/configuration.rb @@ -405,17 +405,21 @@ def full_backtrace=(true_or_false) @backtrace_clean_patterns = true_or_false ? [] : DEFAULT_BACKTRACE_PATTERNS end - def color - return false unless output_to_tty? + def color(output=output_stream) + # rspec's built-in formatters all call this with the output argument, + # but defaulting to output_stream for backward compatibility with + # formatters in extension libs + return false unless output_to_tty?(output) value_for(:color, @color) end def color=(bool) if bool - @color = true if RSpec.windows_os? and not ENV['ANSICON'] - warn "You must use ANSICON 1.31 or later (http://adoxa.110mb.com/ansicon/) to use colour on Windows" + warn "You must use ANSICON 1.31 or later (http://adoxa.3eeweb.com/ansicon/) to use colour on Windows" @color = false + else + @color = true end end end @@ -500,7 +504,7 @@ def reporter # @private def files_or_directories_to_run=(*files) files = files.flatten - files << default_path if command == 'rspec' && default_path && files.empty? + files << default_path if (command == 'rspec' || Runner.running_in_drb?) && default_path && files.empty? self.files_to_run = get_files_to_run(files) end @@ -777,10 +781,29 @@ def configure_expectation_framework # @private def load_spec_files - files_to_run.uniq.map {|f| load File.expand_path(f) } + files_to_run.uniq.each {|f| load File.expand_path(f) } raise_if_rspec_1_is_loaded end + # @private + DEFAULT_FORMATTER = lambda { |string| string } + + # Formats the docstring output using the block provided. + # + # @example + # # This will strip the descriptions of both examples and example groups. + # RSpec.configure do |config| + # config.format_docstrings { |s| s.strip } + # end + def format_docstrings(&block) + @format_docstrings_block = block_given? ? block : DEFAULT_FORMATTER + end + + # @private + def format_docstrings_block + @format_docstrings_block ||= DEFAULT_FORMATTER + end + # @api # # Sets the seed value and sets `order='rand'` @@ -799,6 +822,79 @@ def randomize? order.to_s.match(/rand/) end + # @private + DEFAULT_ORDERING = lambda { |list| list } + + # @private + RANDOM_ORDERING = lambda do |list| + Kernel.srand RSpec.configuration.seed + list.sort_by { Kernel.rand(list.size) } + end + + # Sets a strategy by which to order examples. + # + # @example + # RSpec.configure do |config| + # config.order_examples do |examples| + # examples.reverse + # end + # end + # + # @see #order_groups + # @see #order_groups_and_examples + # @see #order= + # @see #seed= + def order_examples(&block) + @example_ordering_block = block + @order = "custom" unless built_in_orderer?(block) + end + + # @private + def example_ordering_block + @example_ordering_block ||= DEFAULT_ORDERING + end + + # Sets a strategy by which to order groups. + # + # @example + # RSpec.configure do |config| + # config.order_groups do |groups| + # groups.reverse + # end + # end + # + # @see #order_examples + # @see #order_groups_and_examples + # @see #order= + # @see #seed= + def order_groups(&block) + @group_ordering_block = block + @order = "custom" unless built_in_orderer?(block) + end + + # @private + def group_ordering_block + @group_ordering_block ||= DEFAULT_ORDERING + end + + # Sets a strategy by which to order groups and examples. + # + # @example + # RSpec.configure do |config| + # config.order_groups_and_examples do |groups_or_examples| + # groups_or_examples.reverse + # end + # end + # + # @see #order_groups + # @see #order_examples + # @see #order= + # @see #seed= + def order_groups_and_examples(&block) + order_groups(&block) + order_examples(&block) + end + private def get_files_to_run(paths) @@ -806,12 +902,12 @@ def get_files_to_run(paths) paths.map do |path| path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR File.directory?(path) ? gather_directories(path, patterns) : extract_location(path) - end.flatten + end.flatten.sort end def gather_directories(path, patterns) patterns.map do |pattern| - pattern =~ /^#{path}/ ? Dir[pattern.strip] : Dir["#{path}/{#{pattern.strip}}"] + pattern =~ /^#{path}/ ? Dir[pattern.strip].sort : Dir["#{path}/{#{pattern.strip}}"].sort end end @@ -856,12 +952,8 @@ def raise_if_rspec_1_is_loaded end end - def output_to_tty? - begin - output_stream.tty? || tty? - rescue NoMethodError - false - end + def output_to_tty?(output=output_stream) + tty? || (output.respond_to?(:tty?) && output.tty?) end def built_in_formatter(key) @@ -878,6 +970,9 @@ def built_in_formatter(key) when 'p', 'progress' require 'rspec/core/formatters/progress_formatter' RSpec::Core::Formatters::ProgressFormatter + when 'j', 'json' + require 'rspec/core/formatters/json_formatter' + RSpec::Core::Formatters::JsonFormatter end end @@ -923,7 +1018,9 @@ def file_at(path) end def order_and_seed_from_seed(value) + order_groups_and_examples(&RANDOM_ORDERING) @order, @seed = 'rand', value.to_i + [@order, @seed] end def set_order_and_seed(hash) @@ -935,10 +1032,21 @@ def order_and_seed_from_order(type) order, seed = type.to_s.split(':') @order = order @seed = seed = seed.to_i if seed - @order, @seed = nil, nil if order == 'default' + + if randomize? + order_groups_and_examples(&RANDOM_ORDERING) + elsif order == 'default' + @order, @seed = nil, nil + order_groups_and_examples(&DEFAULT_ORDERING) + end + return order, seed end + def built_in_orderer?(block) + [DEFAULT_ORDERING, RANDOM_ORDERING].include?(block) + end + end end end diff --git a/lib/rspec/core/configuration_options.rb b/lib/rspec/core/configuration_options.rb index 25ecfe3dd3..b38c01451d 100644 --- a/lib/rspec/core/configuration_options.rb +++ b/lib/rspec/core/configuration_options.rb @@ -9,6 +9,13 @@ class ConfigurationOptions def initialize(args) @args = args + if args.include?("--default_path") + args[args.index("--default_path")] = "--default-path" + end + + if args.include?("--line_number") + args[args.index("--line_number")] = "--line-number" + end end def configure(config) @@ -71,7 +78,7 @@ def all_configs end def file_options - custom_options_file ? [custom_options] : [global_options, local_options] + custom_options_file ? [custom_options] : [global_options, project_options, local_options] end def env_options @@ -90,6 +97,10 @@ def local_options @local_options ||= options_from(local_options_file) end + def project_options + @project_options ||= options_from(project_options_file) + end + def global_options @global_options ||= options_from(global_options_file) end @@ -112,10 +123,14 @@ def custom_options_file command_line_options[:custom_options_file] end - def local_options_file + def project_options_file ".rspec" end + def local_options_file + ".rspec-local" + end + def global_options_file begin File.join(File.expand_path("~"), ".rspec") diff --git a/lib/rspec/core/example.rb b/lib/rspec/core/example.rb index 698c49d578..2219dd3a9b 100644 --- a/lib/rspec/core/example.rb +++ b/lib/rspec/core/example.rb @@ -49,7 +49,8 @@ def self.delegate_to_metadata(*keys) # there is one, otherwise returns a message including the location of the # example. def description - metadata[:description].to_s.empty? ? "example at #{location}" : metadata[:description] + description = metadata[:description].to_s.empty? ? "example at #{location}" : metadata[:description] + RSpec.configuration.format_docstrings_block.call(description) end # @attr_reader @@ -260,7 +261,7 @@ def with_around_each_hooks(&block) def start(reporter) reporter.example_started(self) - record :started_at => Time.now + record :started_at => RSpec::Core::Time.now end # @private @@ -290,8 +291,8 @@ def finish(reporter) end def record_finished(status, results={}) - finished_at = Time.now - record results.merge(:status => status, :finished_at => finished_at, :run_time => (finished_at - execution_result[:started_at])) + finished_at = RSpec::Core::Time.now + record results.merge(:status => status, :finished_at => finished_at, :run_time => (finished_at - execution_result[:started_at]).to_f) end def run_before_each diff --git a/lib/rspec/core/example_group.rb b/lib/rspec/core/example_group.rb index e7fef9dba9..fb2de4e179 100644 --- a/lib/rspec/core/example_group.rb +++ b/lib/rspec/core/example_group.rb @@ -22,6 +22,7 @@ class ExampleGroup include Subject::ExampleMethods include Pending include Let + include SharedExampleGroup # @private def self.world @@ -43,7 +44,12 @@ def self.delegate_to_metadata(*names) end end - delegate_to_metadata :description, :described_class, :file_path + def description + description = metadata[:example_group][:description] + RSpec.configuration.format_docstrings_block.call(description) + end + + delegate_to_metadata :described_class, :file_path alias_method :display_name, :description # @private alias_method :describes, :described_class @@ -241,7 +247,7 @@ def self.subclass(parent, args, &example_group_block) # @private def self.children - @children ||= [].extend(Extensions::Ordered) + @children ||= [].extend(Extensions::Ordered::ExampleGroups) end # @private @@ -249,9 +255,9 @@ def self.descendants @_descendants ||= [self] + children.inject([]) {|list, c| list + c.descendants} end - # @private - def self.ancestors - @_ancestors ||= super().select {|a| a < RSpec::Core::ExampleGroup} + ## @private + def self.parent_groups + @parent_groups ||= ancestors.select {|a| a < RSpec::Core::ExampleGroup} end # @private @@ -308,9 +314,12 @@ def self.assign_before_all_ivars(ivars, example_group_instance) # @private def self.run_before_all_hooks(example_group_instance) return if descendant_filtered_examples.empty? - assign_before_all_ivars(superclass.before_all_ivars, example_group_instance) - run_hook(:before, :all, example_group_instance) - store_before_all_ivars(example_group_instance) + begin + assign_before_all_ivars(superclass.before_all_ivars, example_group_instance) + run_hook(:before, :all, example_group_instance) + ensure + store_before_all_ivars(example_group_instance) + end end # @private @@ -361,6 +370,7 @@ def self.run(reporter) results_for_descendants = children.ordered.map {|child| child.run(reporter)}.all? result_for_this_group && results_for_descendants rescue Exception => ex + RSpec.wants_to_quit = true if fail_fast? fail_filtered_examples(ex, reporter) ensure run_after_all_hooks(new) @@ -417,7 +427,7 @@ def self.declaration_line_numbers # @private def self.top_level_description - ancestors.last.description + parent_groups.last.description end # @private diff --git a/lib/rspec/core/extensions.rb b/lib/rspec/core/extensions.rb deleted file mode 100644 index ecc75bbd46..0000000000 --- a/lib/rspec/core/extensions.rb +++ /dev/null @@ -1,4 +0,0 @@ -require_rspec 'core/extensions/kernel' -require_rspec 'core/extensions/instance_eval_with_args' -require_rspec 'core/extensions/module_eval_with_args' -require_rspec 'core/extensions/ordered' diff --git a/lib/rspec/core/extensions/ordered.rb b/lib/rspec/core/extensions/ordered.rb index ca58c8fdb2..7264909597 100644 --- a/lib/rspec/core/extensions/ordered.rb +++ b/lib/rspec/core/extensions/ordered.rb @@ -7,12 +7,18 @@ module Extensions # strategies like randomization. module Ordered # @private - def ordered - if RSpec.configuration.randomize? - Kernel.srand RSpec.configuration.seed - sort_by { Kernel.rand size } - else - self + module ExampleGroups + # @private + def ordered + RSpec.configuration.group_ordering_block.call(self) + end + end + + # @private + module Examples + # @private + def ordered + RSpec.configuration.example_ordering_block.call(self) end end end diff --git a/lib/rspec/core/formatters.rb b/lib/rspec/core/formatters.rb new file mode 100644 index 0000000000..5c54177568 --- /dev/null +++ b/lib/rspec/core/formatters.rb @@ -0,0 +1,55 @@ +# ## Built-in Formatters +# +# * progress (default) - prints dots for passing examples, `F` for failures, `*` for pending +# * documentation - prints the docstrings passed to `describe` and `it` methods (and their aliases) +# * html +# * textmate - html plus links to editor +# * json - useful for archiving data for subsequent analysis +# +# The progress formatter is the default, but you can choose any one or more of +# the other formatters by passing with the `--format` (or `-f` for short) +# command-line option, e.g. +# +# rspec --format documentation +# +# You can also send the output of multiple formatters to different streams, e.g. +# +# rspec --format documentation --format html --out results.html +# +# This example sends the output of the documentation formatter to `STDOUT`, and +# the output of the html formatter to results.html. +# +# ## Custom Formatters +# +# You can tell RSpec to use a custom formatter by passing its path and name to +# the `rspec` commmand. For example, if you define MyCustomFormatter in +# path/to/my_custom_formatter.rb, you would type this command: +# +# rspec --require path/to/my_custom_formatter.rb --format MyCustomFormatter +# +# The reporter calls every formatter with this protocol: +# +# * `start(expected_example_count)` +# * zero or more of the following +# * `example_group_started(group)` +# * `example_started(example)` +# * `example_passed(example)` +# * `example_failed(example)` +# * `example_pending(example)` +# * `message(string)` +# * `stop` +# * `start_dump` +# * `dump_pending` +# * `dump_failures` +# * `dump_summary(duration, example_count, failure_count, pending_count)` +# * `seed(value)` +# * `close` +# +# You can either implement all of those methods or subclass +# `RSpec::Core::Formatters::BaseTextFormatter` and override the methods you want +# to enhance. +# +# @see RSpec::Core::Formatters::BaseTextFormatter +# @see RSpec::Core::Reporter +module RSpec::Core::Formatters +end diff --git a/lib/rspec/core/formatters/base_formatter.rb b/lib/rspec/core/formatters/base_formatter.rb index 5afed53221..7b1ac1dd34 100644 --- a/lib/rspec/core/formatters/base_formatter.rb +++ b/lib/rspec/core/formatters/base_formatter.rb @@ -4,7 +4,12 @@ module RSpec module Core module Formatters - + # RSpec's built-in formatters are all subclasses of RSpec::Core::Formatters::BaseTextFormatter, + # but the BaseTextFormatter documents all of the methods needed to be implemented by a formatter, + # as they are called from the reporter. + # + # @see RSpec::Core::Formatters::BaseTextFormatter + # @see RSpec::Core::Reporter class BaseFormatter include Helpers attr_accessor :example_group @@ -21,54 +26,68 @@ def initialize(output) @example_group = nil end - # This method is invoked before any examples are run, right after - # they have all been collected. This can be useful for special - # formatters that need to provide progress on feedback (graphical ones) + # Invoked before any examples are run, right after they have all + # been collected. This can be useful for formatters that provide + # feedback on progress through a suite. # - # This will only be invoked once, and the next one to be invoked - # is #example_group_started + # @param example_count def start(example_count) start_sync_output @example_count = example_count end - # This method is invoked at the beginning of the execution of each example group. - # +example_group+ is the example_group. + # Invoked at the beginning of the execution of each example + # group. # - # The next method to be invoked after this is +example_passed+, - # +example_pending+, or +example_finished+ + # @param example_group subclass of `RSpec::Core::ExampleGroup` def example_group_started(example_group) @example_group = example_group end - # This method is invoked at the end of the execution of each example group. - # +example_group+ is the example_group. + # Invoked at the end of the execution of each example group. + # + # @param example_group subclass of `RSpec::Core::ExampleGroup` def example_group_finished(example_group) end + + # Invoked at the beginning of the execution of each example. + # + # @param example instance of subclass of `RSpec::Core::ExampleGroup` def example_started(example) examples << example end + # Invoked when an example passes. + # + # @param example instance of subclass of `RSpec::Core::ExampleGroup` def example_passed(example) end + # Invoked when an example is pending. + # + # @param example instance of subclass of `RSpec::Core::ExampleGroup` def example_pending(example) @pending_examples << example end + # Invoked when an example fails. + # + # @param example instance of subclass of `RSpec::Core::ExampleGroup` def example_failed(example) @failed_examples << example end + # Used by the reporter to send messages to the output stream. + # @param [String] message def message(message) end + # Invoked after all examples have executed, before dumping post-run reports. def stop end - # This method is invoked after all of the examples have executed. The next method - # to be invoked after this one is #dump_failure (once for each failed example), + # Invoked after all of the examples have executed (after `stop`). def start_dump end @@ -76,7 +95,7 @@ def start_dump def dump_failures end - # This method is invoked after the dumping of examples and failures. + # Invoked after the dumping of examples and failures. def dump_summary(duration, example_count, failure_count, pending_count) @duration = duration @example_count = example_count @@ -84,41 +103,26 @@ def dump_summary(duration, example_count, failure_count, pending_count) @pending_count = pending_count end - # This gets invoked after the summary if option is set to do so. + # Invoked after the summary if option is set to do so. def dump_pending end + # @private not intended for use outside RSpec. def seed(number) end - # This method is invoked at the very end. Allows the formatter to clean up, like closing open streams. + # Invoked at the very end, `close` allows the formatter to clean + # up resources, e.g. open streams, etc. def close restore_sync_output end - def format_backtrace(backtrace, example) - return "" unless backtrace - return backtrace if example.metadata[:full_backtrace] == true - - if at_exit_index = backtrace.index(RSpec::Core::Runner::AT_EXIT_HOOK_BACKTRACE_LINE) - backtrace = backtrace[0, at_exit_index] - end - - cleansed = backtrace.map { |line| backtrace_line(line) }.compact - cleansed.empty? ? backtrace : cleansed - end - protected def configuration RSpec.configuration end - def backtrace_line(line) - return nil if configuration.cleaned_from_backtrace?(line) - RSpec::Core::Metadata::relative_path(line) - end - def read_failed_line(exception, example) unless matching_line = find_failed_line(exception.backtrace, example.file_path) return "Unable to find matching line from backtrace" @@ -127,10 +131,13 @@ def read_failed_line(exception, example) file_path, line_number = matching_line.match(/(.+?):(\d+)(|:\d+)/)[1..2] if File.exist?(file_path) - File.readlines(file_path)[line_number.to_i - 1] + File.readlines(file_path)[line_number.to_i - 1] || + "Unable to find matching line in #{file_path}" else "Unable to find #{file_path} to read failed line" end + rescue SecurityError + "Unable to read failed line" end def find_failed_line(backtrace, path) @@ -158,11 +165,9 @@ def profile_examples? end def color_enabled? - configuration.color_enabled? + configuration.color_enabled?(output) end - end - end end end diff --git a/lib/rspec/core/formatters/base_text_formatter.rb b/lib/rspec/core/formatters/base_text_formatter.rb index cb96ff42cb..fceebc8c5e 100644 --- a/lib/rspec/core/formatters/base_text_formatter.rb +++ b/lib/rspec/core/formatters/base_text_formatter.rb @@ -4,8 +4,12 @@ module RSpec module Core module Formatters + # Base for all of RSpec's built-in formatters. See RSpec::Core::Formatters::BaseFormatter + # to learn more about all of the methods called by the reporter. + # + # @see RSpec::Core::Formatters::BaseFormatter + # @see RSpec::Core::Reporter class BaseTextFormatter < BaseFormatter - def message(message) output.puts message end @@ -156,7 +160,7 @@ def format_caller(caller_info) end def dump_backtrace(example) - format_backtrace(example.execution_result[:exception].backtrace, example).each do |backtrace_info| + format_backtrace(example.execution_result[:exception].backtrace, example.metadata).each do |backtrace_info| output.puts cyan("#{long_padding}# #{backtrace_info}") end end @@ -191,11 +195,11 @@ def dump_shared_failure_info(group) end def find_shared_group(example) - group_and_ancestors(example).find {|group| group.metadata[:shared_group_name]} + group_and_parent_groups(example).find {|group| group.metadata[:shared_group_name]} end - def group_and_ancestors(example) - example.example_group.ancestors + [example.example_group] + def group_and_parent_groups(example) + example.example_group.parent_groups + [example.example_group] end end end diff --git a/lib/rspec/core/formatters/documentation_formatter.rb b/lib/rspec/core/formatters/documentation_formatter.rb index f65d2dfd2e..4e61a9be6e 100644 --- a/lib/rspec/core/formatters/documentation_formatter.rb +++ b/lib/rspec/core/formatters/documentation_formatter.rb @@ -59,7 +59,7 @@ def current_indentation end def example_group_chain - example_group.ancestors.reverse + example_group.parent_groups.reverse end end end diff --git a/lib/rspec/core/formatters/helpers.rb b/lib/rspec/core/formatters/helpers.rb index 5da56896fb..21a8f1b6e5 100644 --- a/lib/rspec/core/formatters/helpers.rb +++ b/lib/rspec/core/formatters/helpers.rb @@ -1,8 +1,34 @@ module RSpec module Core - module Formatters + module BacktraceFormatter + extend self + + def format_backtrace(backtrace, options = {}) + return "" unless backtrace + return backtrace if options[:full_backtrace] == true + + if at_exit_index = backtrace.index(RSpec::Core::Runner::AT_EXIT_HOOK_BACKTRACE_LINE) + backtrace = backtrace[0, at_exit_index] + end + + cleansed = backtrace.map { |line| backtrace_line(line) }.compact + cleansed.empty? ? backtrace : cleansed + end + + protected + def backtrace_line(line) + return nil if RSpec.configuration.cleaned_from_backtrace?(line) + RSpec::Core::Metadata::relative_path(line) + rescue SecurityError + nil + end + end + + module Formatters module Helpers + include BacktraceFormatter + SUB_SECOND_PRECISION = 5 DEFAULT_PRECISION = 2 @@ -11,9 +37,9 @@ def format_duration(duration) minutes = duration.to_i / 60 seconds = duration - minutes * 60 - "#{pluralize(minutes, 'minute')} #{format_seconds(seconds)} seconds" + "#{pluralize(minutes, 'minute')} #{pluralize(format_seconds(seconds), 'second')}" else - "#{format_seconds(duration)} seconds" + pluralize(format_seconds(duration), 'second') end end @@ -29,9 +55,8 @@ def strip_trailing_zeroes(string) end def pluralize(count, string) - "#{count} #{string}#{'s' unless count == 1}" + "#{count} #{string}#{'s' unless count.to_f == 1}" end - end end diff --git a/lib/rspec/core/formatters/html_formatter.rb b/lib/rspec/core/formatters/html_formatter.rb index b24b033071..bb58a7266d 100644 --- a/lib/rspec/core/formatters/html_formatter.rb +++ b/lib/rspec/core/formatters/html_formatter.rb @@ -1,17 +1,17 @@ -require 'erb' require 'rspec/core/formatters/base_text_formatter' +require 'rspec/core/formatters/html_printer' module RSpec module Core module Formatters class HtmlFormatter < BaseTextFormatter - include ERB::Util # for the #h method def initialize(output) super(output) @example_group_number = 0 @example_number = 0 @header_red = nil + @printer = HtmlPrinter.new(output) end private @@ -35,29 +35,25 @@ def example_number def start(example_count) super(example_count) - @output.puts html_header - @output.puts report_header - @output.flush + @printer.print_html_start + @printer.flush end def example_group_started(example_group) super(example_group) @example_group_red = false @example_group_number += 1 + unless example_group_number == 1 - @output.puts " " - @output.puts "" + @printer.print_example_group_end end - @output.puts "
" - @output.puts "
" - @output.puts "
#{h(example_group.description)}
" - @output.flush + @printer.print_example_group_start( example_group_number, example_group.description, example_group.parent_groups.size ) + @printer.flush end def start_dump - @output.puts "
" - @output.puts "
" - @output.flush + @printer.print_example_group_end + @printer.flush end def example_started(example) @@ -66,41 +62,55 @@ def example_started(example) end def example_passed(example) - move_progress - @output.puts "
#{h(example.description)}#{sprintf("%.5f", example.execution_result[:run_time])}s
" - @output.flush + @printer.move_progress(percent_done) + @printer.print_example_passed( example.description, example.execution_result[:run_time] ) + @printer.flush end def example_failed(example) super(example) + + unless @header_red + @header_red = true + @printer.make_header_red + end + + unless @example_group_red + @example_group_red = true + @printer.make_example_group_header_red(example_group_number) + end + + @printer.move_progress(percent_done) + exception = example.metadata[:execution_result][:exception] + exception_details = if exception + { + :message => exception.message, + :backtrace => format_backtrace(exception.backtrace, example.metadata).join("\n") + } + else + false + end extra = extra_failure_content(exception) - @output.puts " " unless @header_red - @header_red = true - @output.puts " " unless @example_group_red - @output.puts " " unless @example_group_red - @example_group_red = true - move_progress - @output.puts "
" - @output.puts " #{h(example.description)}" - @output.puts " #{sprintf('%.5f', example.execution_result[:run_time])}s" - @output.puts "
" - @output.puts "
#{h(exception.message)}
" unless exception.nil? - @output.puts "
#{format_backtrace(exception.backtrace, example).join("\n")}
" if exception - @output.puts extra unless extra == "" - @output.puts "
" - @output.puts "
" - @output.flush + + @printer.print_example_failed( + exception.pending_fixed?, + example.description, + example.execution_result[:run_time], + @failed_examples.size, + exception_details, + (extra == "") ? false : extra + ) + @printer.flush end def example_pending(example) - message = example.metadata[:execution_result][:pending_message] - @output.puts " " unless @header_red - @output.puts " " unless @example_group_red - @output.puts " " unless @example_group_red - move_progress - @output.puts "
#{h(example.description)} (PENDING: #{h(message)})
" - @output.flush + + @printer.make_header_yellow unless @header_red + @printer.make_example_group_header_yellow(example_group_number) unless @example_group_red + @printer.move_progress(percent_done) + @printer.print_example_pending( example.description, example.metadata[:execution_result][:pending_message] ) + @printer.flush end # Override this method if you wish to output extra HTML for a failed spec. For example, you @@ -114,11 +124,6 @@ def extra_failure_content(exception) "
#{@snippet_extractor.snippet(backtrace)}
" end - def move_progress - @output.puts " " - @output.flush - end - def percent_done result = 100.0 if @example_count > 0 @@ -134,329 +139,14 @@ def dump_pending end def dump_summary(duration, example_count, failure_count, pending_count) - # TODO - kill dry_run? - if dry_run? - totals = "This was a dry-run" - else - totals = "#{example_count} example#{'s' unless example_count == 1}, " - totals << "#{failure_count} failure#{'s' unless failure_count == 1}" - totals << ", #{pending_count} pending" if pending_count > 0 - end - @output.puts "" - @output.puts "" - @output.puts "" - @output.puts "" - @output.puts "" - @output.puts "" - @output.flush - end - - def current_indentation - "style=\"margin-left: #{(example_group.ancestors.size - 1) * 15}px;\"" - end - - def html_header - <<-EOF - - - - - RSpec results - - - - - - - - -EOF - end - - def report_header - <<-EOF -
- -
-
-

RSpec Code Examples

-
- -
- - - -
- -
-

 

-

 

-
-
- - -
-EOF - end - - def global_scripts - <<-EOF - -function addClass(element_id, classname) { - document.getElementById(element_id).className += (" " + classname); -} - -function removeClass(element_id, classname) { - var elem = document.getElementById(element_id); - var classlist = elem.className.replace(classname,''); - elem.className = classlist; -} - -function moveProgressBar(percentDone) { - document.getElementById("rspec-header").style.width = percentDone +"%"; -} - -function makeRed(element_id) { - removeClass(element_id, 'passed'); - removeClass(element_id, 'not_implemented'); - addClass(element_id,'failed'); -} - -function makeYellow(element_id) { - var elem = document.getElementById(element_id); - if (elem.className.indexOf("failed") == -1) { // class doesn't includes failed - if (elem.className.indexOf("not_implemented") == -1) { // class doesn't include not_implemented - removeClass(element_id, 'passed'); - addClass(element_id,'not_implemented'); - } - } -} - -function apply_filters() { - var passed_filter = document.getElementById('passed_checkbox').checked; - var failed_filter = document.getElementById('failed_checkbox').checked; - var pending_filter = document.getElementById('pending_checkbox').checked; - - assign_display_style("example passed", passed_filter); - assign_display_style("example failed", failed_filter); - assign_display_style("example not_implemented", pending_filter); - - assign_display_style_for_group("example_group passed", passed_filter); - assign_display_style_for_group("example_group not_implemented", pending_filter, pending_filter || passed_filter); - assign_display_style_for_group("example_group failed", failed_filter, failed_filter || pending_filter || passed_filter); -} - -function get_display_style(display_flag) { - var style_mode = 'none'; - if (display_flag == true) { - style_mode = 'block'; - } - return style_mode; -} - -function assign_display_style(classname, display_flag) { - var style_mode = get_display_style(display_flag); - var elems = document.getElementsByClassName(classname) - for (var i=0; i" + @output.puts "
" + end + + def print_example_group_start( group_id, description, number_of_parents ) + @output.puts "
" + @output.puts "
" + @output.puts "
#{h(description)}
" + end + + def print_example_passed( description, run_time ) + formatted_run_time = sprintf("%.5f", run_time) + @output.puts "
#{h(description)}#{formatted_run_time}s
" + end + + def print_example_failed( pending_fixed, description, run_time, failure_id, exception, extra_content ) + formatted_run_time = sprintf("%.5f", run_time) + + @output.puts "
" + @output.puts " #{h(description)}" + @output.puts " #{formatted_run_time}s" + @output.puts "
" + if exception + @output.puts "
#{h(exception[:message])}
" + @output.puts "
#{exception[:backtrace]}
" + end + @output.puts extra_content if extra_content + @output.puts "
" + @output.puts "
" + end + + def print_example_pending( description, pending_message ) + @output.puts "
#{h(description)} (PENDING: #{h(pending_message)})
" + end + + def print_summary( was_dry_run, duration, example_count, failure_count, pending_count ) + # TODO - kill dry_run? + if was_dry_run + totals = "This was a dry-run" + else + totals = "#{example_count} example#{'s' unless example_count == 1}, " + totals << "#{failure_count} failure#{'s' unless failure_count == 1}" + totals << ", #{pending_count} pending" if pending_count > 0 + end + + formatted_duration = sprintf("%.5f", duration) + + @output.puts "" + @output.puts "" + @output.puts "
" + @output.puts "
" + @output.puts "" + @output.puts "" + end + + def flush + @output.flush + end + + def move_progress( percent_done ) + @output.puts " " + @output.flush + end + + def make_header_red + @output.puts " " + end + + def make_header_yellow + @output.puts " " + end + + def make_example_group_header_red(group_id) + @output.puts " " + @output.puts " " + end + + def make_example_group_header_yellow(group_id) + @output.puts " " + @output.puts " " + end + + + private + + def indentation_style( number_of_parents ) + "style=\"margin-left: #{(number_of_parents - 1) * 15}px;\"" + end + + + REPORT_HEADER = <<-EOF +
+ +
+
+

RSpec Code Examples

+
+ +
+ + + +
+ +
+

 

+

 

+
+
+ + +
+EOF + + GLOBAL_SCRIPTS = <<-EOF + +function addClass(element_id, classname) { + document.getElementById(element_id).className += (" " + classname); +} + +function removeClass(element_id, classname) { + var elem = document.getElementById(element_id); + var classlist = elem.className.replace(classname,''); + elem.className = classlist; +} + +function moveProgressBar(percentDone) { + document.getElementById("rspec-header").style.width = percentDone +"%"; +} + +function makeRed(element_id) { + removeClass(element_id, 'passed'); + removeClass(element_id, 'not_implemented'); + addClass(element_id,'failed'); +} + +function makeYellow(element_id) { + var elem = document.getElementById(element_id); + if (elem.className.indexOf("failed") == -1) { // class doesn't includes failed + if (elem.className.indexOf("not_implemented") == -1) { // class doesn't include not_implemented + removeClass(element_id, 'passed'); + addClass(element_id,'not_implemented'); + } + } +} + +function apply_filters() { + var passed_filter = document.getElementById('passed_checkbox').checked; + var failed_filter = document.getElementById('failed_checkbox').checked; + var pending_filter = document.getElementById('pending_checkbox').checked; + + assign_display_style("example passed", passed_filter); + assign_display_style("example failed", failed_filter); + assign_display_style("example not_implemented", pending_filter); + + assign_display_style_for_group("example_group passed", passed_filter); + assign_display_style_for_group("example_group not_implemented", pending_filter, pending_filter || passed_filter); + assign_display_style_for_group("example_group failed", failed_filter, failed_filter || pending_filter || passed_filter); +} + +function get_display_style(display_flag) { + var style_mode = 'none'; + if (display_flag == true) { + style_mode = 'block'; + } + return style_mode; +} + +function assign_display_style(classname, display_flag) { + var style_mode = get_display_style(display_flag); + var elems = document.getElementsByClassName(classname) + for (var i=0; i + + + + RSpec results + + + + + + + + +EOF + + end + end + end +end diff --git a/lib/rspec/core/formatters/json_formatter.rb b/lib/rspec/core/formatters/json_formatter.rb new file mode 100644 index 0000000000..e17820ed53 --- /dev/null +++ b/lib/rspec/core/formatters/json_formatter.rb @@ -0,0 +1,73 @@ +require 'rspec/core/formatters/base_formatter' +require 'json' + +module RSpec + module Core + module Formatters + + class JsonFormatter < BaseFormatter + + attr_reader :output_hash + + def initialize(output) + super + @output_hash = {} + end + + def message(message) + (@output_hash[:messages] ||= []) << message + end + + def dump_summary(duration, example_count, failure_count, pending_count) + super(duration, example_count, failure_count, pending_count) + @output_hash[:summary] = { + :duration => duration, + :example_count => example_count, + :failure_count => failure_count, + :pending_count => pending_count + } + @output_hash[:summary_line] = summary_line(example_count, failure_count, pending_count) + + # Don't print out profiled info if there are failures, it just clutters the output + dump_profile if profile_examples? && failure_count == 0 + end + + def summary_line(example_count, failure_count, pending_count) + summary = pluralize(example_count, "example") + summary << ", " << pluralize(failure_count, "failure") + summary << ", #{pending_count} pending" if pending_count > 0 + summary + end + + def stop + super + @output_hash[:examples] = examples.map do |example| + { + :description => example.description, + :full_description => example.full_description, + :status => example.execution_result[:status], + # :example_group, + # :execution_result, + :file_path => example.metadata[:file_path], + :line_number => example.metadata[:line_number], + }.tap do |hash| + if e=example.exception + hash[:exception] = { + :class => e.class.name, + :message => e.message, + :backtrace => e.backtrace, + } + end + end + end + end + + def close + output.write @output_hash.to_json + output.close if IO === output && output != $stdout + end + + end + end + end +end diff --git a/lib/rspec/core/formatters/snippet_extractor.rb b/lib/rspec/core/formatters/snippet_extractor.rb index 32db215b9a..b9e8edd209 100644 --- a/lib/rspec/core/formatters/snippet_extractor.rb +++ b/lib/rspec/core/formatters/snippet_extractor.rb @@ -4,7 +4,7 @@ module Formatters # This class extracts code snippets by looking at the backtrace of the passed error class SnippetExtractor class NullConverter; def convert(code, pre); code; end; end - + begin require 'syntax/convertors/html' @@converter = Syntax::Convertors::HTML.for_syntax "ruby" @@ -40,6 +40,8 @@ def lines_around(file, line) else "# Couldn't get snippet for #{file}" end + rescue SecurityError + "# Couldn't get snippet for #{file}" end def post_process(highlighted, offending_line) diff --git a/lib/rspec/core/hooks.rb b/lib/rspec/core/hooks.rb index 60cfc83900..ea3ca911e6 100644 --- a/lib/rspec/core/hooks.rb +++ b/lib/rspec/core/hooks.rb @@ -119,7 +119,7 @@ def register_globals host, globals private def process host, globals, position, scope globals[position][scope].each do |hook| - unless host.ancestors.any? { |a| a.hooks[position][scope].include? hook } + unless host.parent_groups.any? { |a| a.hooks[position][scope].include? hook } self[position][scope] << hook if scope == :each || hook.options_apply?(host) end end @@ -426,7 +426,7 @@ def run_hook(hook, scope, example_or_group=ExampleGroup.new, initial_procsy=nil) # @private def around_each_hooks_for(example, initial_procsy=nil) - AroundHookCollection.new(ancestors.map {|a| a.hooks[:around][:each]}.flatten).for(example, initial_procsy) + AroundHookCollection.new(parent_groups.map {|a| a.hooks[:around][:each]}.flatten).for(example, initial_procsy) end private @@ -448,11 +448,11 @@ def after_all_hooks_for(group) end def before_each_hooks_for(example) - HookCollection.new(ancestors.reverse.map {|a| a.hooks[:before][:each]}.flatten).for(example) + HookCollection.new(parent_groups.reverse.map {|a| a.hooks[:before][:each]}.flatten).for(example) end def after_each_hooks_for(example) - HookCollection.new(ancestors.map {|a| a.hooks[:after][:each]}.flatten).for(example) + HookCollection.new(parent_groups.map {|a| a.hooks[:after][:each]}.flatten).for(example) end def register_hook prepend_or_append, hook, *args, &block diff --git a/lib/rspec/core/metadata.rb b/lib/rspec/core/metadata.rb index ba89b5a067..2d55940220 100644 --- a/lib/rspec/core/metadata.rb +++ b/lib/rspec/core/metadata.rb @@ -31,6 +31,8 @@ def self.relative_path(line) line = line.sub(/\A([^:]+:\d+)$/, '\\1') return nil if line == '-e:1' line + rescue SecurityError + nil end # @private @@ -41,7 +43,18 @@ module MetadataHash # ExampleMetadataHash and GroupMetadataHash, which get mixed in to # Metadata for ExampleGroups and Examples (respectively). def [](key) - return super if has_key?(key) + store_computed(key) unless has_key?(key) + super + end + + def fetch(key, *args) + store_computed(key) unless has_key?(key) + super + end + + private + + def store_computed(key) case key when :location store(:location, location) @@ -49,7 +62,6 @@ def [](key) file_path, line_number = file_and_line_number store(:file_path, file_path) store(:line_number, line_number) - super when :execution_result store(:execution_result, {}) when :describes, :described_class @@ -61,13 +73,9 @@ def [](key) store(:full_description, full_description) when :description store(:description, build_description_from(*self[:description_args])) - else - super end end - private - def location "#{self[:file_path]}:#{self[:line_number]}" end diff --git a/lib/rspec/core/mocking/with_mocha.rb b/lib/rspec/core/mocking/with_mocha.rb index 963117b25b..bb96b050eb 100644 --- a/lib/rspec/core/mocking/with_mocha.rb +++ b/lib/rspec/core/mocking/with_mocha.rb @@ -1,5 +1,28 @@ -require 'mocha/standalone' -require 'mocha/object' +# In order to support all versions of mocha, we have to jump through some +# hoops here. +# +# mocha >= '0.13.0': +# require 'mocha/api' is required +# require 'mocha/object' raises a LoadError b/c the file no longer exists +# mocha < '0.13.0', >= '0.9.7' +# require 'mocha/api' is required +# require 'mocha/object' is required +# mocha < '0.9.7': +# require 'mocha/api' raises a LoadError b/c the file does not yet exist +# require 'mocha/standalone' is required +# require 'mocha/object' is required +begin + require 'mocha/api' + + begin + require 'mocha/object' + rescue LoadError + # Mocha >= 0.13.0 no longer contains this file nor needs it to be loaded + end +rescue LoadError + require 'mocha/standalone' + require 'mocha/object' +end module RSpec module Core diff --git a/lib/rspec/core/mocking/with_rspec.rb b/lib/rspec/core/mocking/with_rspec.rb index f7c4694317..f18f19287a 100644 --- a/lib/rspec/core/mocking/with_rspec.rb +++ b/lib/rspec/core/mocking/with_rspec.rb @@ -3,9 +3,13 @@ module RSpec module Core module MockFrameworkAdapter - + def self.framework_name; :rspec end - + + def self.configuration + RSpec::Mocks.configuration + end + def setup_mocks_for_rspec RSpec::Mocks::setup(self) end diff --git a/lib/rspec/core/option_parser.rb b/lib/rspec/core/option_parser.rb index 2f71de44ff..69dff95285 100644 --- a/lib/rspec/core/option_parser.rb +++ b/lib/rspec/core/option_parser.rb @@ -13,15 +13,35 @@ class << self def parse!(args) return {} if args.empty? - if args.include?("--formatter") - RSpec.deprecate("the --formatter option", "-f or --format") - args[args.index("--formatter")] = "--format" - end + + convert_deprecated_args(args) + options = args.delete('--tty') ? {:tty => true} : {} - parser(options).parse!(args) + begin + parser(options).parse!(args) + rescue OptionParser::InvalidOption => e + abort "#{e.message}\n\nPlease use --help for a listing of valid options" + end + options end + def convert_deprecated_args(args) + args.map! { |arg| + case arg + when "--formatter" + RSpec.deprecate("the --formatter option", "-f or --format") + "--format" + when "--default_path" + "--default-path" + when "--line_number" + "--line-number" + else + arg + end + } + end + alias_method :parse, :parse! def parser(options) @@ -92,6 +112,7 @@ def parser(options) ' [d]ocumentation (group and example names)', ' [h]tml', ' [t]extmate', + ' [j]son', ' custom formatter class name') do |o| options[:formatters] ||= [] options[:formatters] << [o] @@ -139,7 +160,7 @@ def parser(options) (options[:full_description] ||= []) << Regexp.compile(Regexp.escape(o)) end - parser.on('-l', '--line_number LINE', 'Specify line number of an example or group (may be', + parser.on('-l', '--line-number LINE', 'Specify line number of an example or group (may be', ' used more than once).') do |o| (options[:line_numbers] ||= []) << o end @@ -158,7 +179,7 @@ def parser(options) options[filter_type][name] = value.nil? ? true : eval(value) rescue value end - parser.on('--default_path PATH', 'Set the default path where RSpec looks for examples (can', + parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can', ' be a path to a file or a directory).') do |path| options[:default_path] = path end diff --git a/lib/rspec/core/project_initializer.rb b/lib/rspec/core/project_initializer.rb index b813f26136..06934274f7 100644 --- a/lib/rspec/core/project_initializer.rb +++ b/lib/rspec/core/project_initializer.rb @@ -6,7 +6,6 @@ def initialize(arg=nil) end def run - warn "The --configure option no longer needs any arguments, so #{@arg} was ignored." if @arg create_spec_helper_file create_dot_rspec_file delete_if_confirmed("autotest/discover.rb", <<-MESSAGE) diff --git a/lib/rspec/core/rake_task.rb b/lib/rspec/core/rake_task.rb index 2c74737125..ed25c10238 100644 --- a/lib/rspec/core/rake_task.rb +++ b/lib/rspec/core/rake_task.rb @@ -1,4 +1,3 @@ -require 'rspec/core' require 'rspec/core/deprecation' require 'rake' require 'rake/tasklib' @@ -63,6 +62,9 @@ def warning=(true_or_false) # Use rcov for code coverage? # + # Due to the many ways `rcov` can run, if this option is enabled, it is + # required that `require 'rspec/autorun'` appears in `spec_helper`.rb + # # default: # false attr_accessor :rcov @@ -109,34 +111,47 @@ def spec_opts=(opts) @rspec_opts = opts end - def initialize(*args) + def initialize(*args, &task_block) + setup_ivars(args) + + desc "Run RSpec code examples" unless ::Rake.application.last_comment + + task name, *args do |_, task_args| + RakeFileUtils.send(:verbose, verbose) do + task_block.call(*[self, task_args].slice(0, task_block.arity)) if task_block + run_task verbose + end + end + end + + def setup_ivars(args) @name = args.shift || :spec - @pattern, @rcov_path, @rcov_opts, @ruby_opts, @rspec_opts = nil, nil, nil, nil, nil + @rcov_opts, @ruby_opts, @rspec_opts = nil, nil, nil @warning, @rcov = false, false @verbose, @fail_on_error = true, true - yield self if block_given? - - @rcov_path ||= 'rcov' - @rspec_path ||= 'rspec' - @pattern ||= './spec{,/*/**}/*_spec.rb' + @rcov_path = 'rcov' + @rspec_path = 'rspec' + @pattern = './spec{,/*/**}/*_spec.rb' + end - desc("Run RSpec code examples") unless ::Rake.application.last_comment + def has_files? + empty = files_to_run.empty? + puts "No examples matching #{pattern} could be found" if empty + not empty + end - task name do - RakeFileUtils.send(:verbose, verbose) do - if files_to_run.empty? - puts "No examples matching #{pattern} could be found" - else - begin - puts spec_command if verbose - success = system(spec_command) - rescue - puts failure_message if failure_message - end - raise("#{spec_command} failed") if fail_on_error unless success - end + def run_task(verbose) + files = has_files? + if files + command = spec_command + begin + puts command if verbose + success = system(command) + rescue + puts failure_message if failure_message end + raise("#{command} failed") if fail_on_error unless success end end @@ -144,29 +159,25 @@ def initialize(*args) def files_to_run if ENV['SPEC'] - FileList[ ENV['SPEC'] ] + FileList[ ENV['SPEC'] ].sort else - FileList[ pattern ].map { |f| f.gsub(/"/, '\"').gsub(/'/, "\\\\'") } + FileList[ pattern ].sort.map { |f| f.shellescape } end end def spec_command - @spec_command ||= begin - cmd_parts = [] - cmd_parts << RUBY - cmd_parts << ruby_opts - cmd_parts << "-w" if @warning - cmd_parts << "-S" << runner - cmd_parts << "-Ispec:lib" << rcov_opts if rcov - cmd_parts << files_to_run - cmd_parts << "--" if rcov && rspec_opts - cmd_parts << rspec_opts - cmd_parts.flatten.reject(&blank).join(" ") - end + cmd_parts = [] + cmd_parts << RUBY + cmd_parts << ruby_opts + cmd_parts << "-w" if @warning + cmd_parts << "-S" << runner + cmd_parts << "-Ispec:lib" << rcov_opts if rcov + cmd_parts << files_to_run + cmd_parts << "--" if rcov && rspec_opts + cmd_parts << rspec_opts + cmd_parts.flatten.reject(&blank).join(" ") end - private - def runner rcov ? rcov_path : rspec_path end diff --git a/lib/rspec/core/reporter.rb b/lib/rspec/core/reporter.rb index 56648e9242..d6234aa925 100644 --- a/lib/rspec/core/reporter.rb +++ b/lib/rspec/core/reporter.rb @@ -38,7 +38,7 @@ def report(expected_example_count, seed=nil) end def start(expected_example_count) - @start = Time.now + @start = RSpec::Core::Time.now notify :start, expected_example_count end @@ -89,7 +89,7 @@ def finish(seed) alias_method :abort, :finish def stop - @duration = Time.now - @start if @start + @duration = (RSpec::Core::Time.now - @start).to_f if @start notify :stop end diff --git a/lib/rspec/core/shared_example_group.rb b/lib/rspec/core/shared_example_group.rb index 9786724e4d..25411136e9 100644 --- a/lib/rspec/core/shared_example_group.rb +++ b/lib/rspec/core/shared_example_group.rb @@ -29,68 +29,116 @@ module SharedExampleGroup # @see ExampleGroup.include_examples # @see ExampleGroup.include_context def shared_examples *args, &block - if key? args.first - key = args.shift - raise_key_taken key if key_taken? key - RSpec.world.shared_example_groups[key] = block - end - - unless args.empty? - mod = Module.new - (class << mod; self; end).send :define_method, :extended do |host| - host.class_eval(&block) - end - RSpec.configuration.extend mod, *args - end + Registry.add_group(*args, &block) end alias_method :shared_context, :shared_examples alias_method :share_examples_for, :shared_examples alias_method :shared_examples_for, :shared_examples + # @deprecated def share_as(name, &block) - if Object.const_defined?(name) - mod = Object.const_get(name) - raise_name_error unless mod.created_from_caller(caller) - end + RSpec.deprecate("Rspec::Core::SharedExampleGroup#share_as", + "RSpec::SharedContext or shared_examples") + Registry.add_const(name, &block) + end + + # @private + # + # Used internally to manage the shared example groups and + # constants. We want to limit the number of methods we add + # to objects we don't own (main and Module) so this allows + # us to have helper methods that don't get added to those + # objects. + module Registry + extend self - mod = Module.new do - @shared_block = block - @caller_line = caller.last + def add_group(*args, &block) + ensure_block_has_source_location(block, caller[1]) - def self.created_from_caller(other_caller) - @caller_line == other_caller.last + if key? args.first + key = args.shift + warn_if_key_taken key, block + RSpec.world.shared_example_groups[key] = block end - def self.included(kls) - kls.describe(&@shared_block) - kls.children.first.metadata[:shared_group_name] = name + unless args.empty? + mod = Module.new + (class << mod; self; end).send :define_method, :extended do |host| + host.class_eval(&block) + end + RSpec.configuration.extend mod, *args end end - shared_const = Object.const_set(name, mod) - RSpec.world.shared_example_groups[shared_const] = block - end + def add_const(name, &block) + if Object.const_defined?(name) + mod = Object.const_get(name) + raise_name_error unless mod.created_from_caller(caller) + end - private + mod = Module.new do + @shared_block = block + @caller_line = caller.last - def key? candidate - [String, Symbol, Module].any? { |cls| cls === candidate } - end + def self.created_from_caller(other_caller) + @caller_line == other_caller.last + end - def raise_name_error - raise NameError, "The first argument (#{name}) to share_as must be a legal name for a constant not already in use." - end + def self.included(kls) + kls.describe(&@shared_block) + kls.children.first.metadata[:shared_group_name] = name + end + end - def raise_key_taken key - raise ArgumentError, "Shared example group '#{key}' already exists" - end + shared_const = Object.const_set(name, mod) + RSpec.world.shared_example_groups[shared_const] = block + end - def key_taken? key - RSpec.world.shared_example_groups.has_key?(key) + private + + def key? candidate + [String, Symbol, Module].any? { |cls| cls === candidate } + end + + def raise_name_error + raise NameError, "The first argument (#{name}) to share_as must be a legal name for a constant not already in use." + end + + def warn_if_key_taken key, new_block + return unless existing_block = example_block_for(key) + + Kernel.warn <<-WARNING.gsub(/^ +\|/, '') + |WARNING: Shared example group '#{key}' has been previously defined at: + | #{formatted_location existing_block} + |...and you are now defining it at: + | #{formatted_location new_block} + |The new definition will overwrite the original one. + WARNING + end + + def formatted_location block + block.source_location.join ":" + end + + def example_block_for key + RSpec.world.shared_example_groups[key] + end + + def ensure_block_has_source_location(block, caller_line) + return if block.respond_to?(:source_location) + + block.extend Module.new { + define_method :source_location do + caller_line.split(':') + end + } + end end end end end -include RSpec::Core::SharedExampleGroup +extend RSpec::Core::SharedExampleGroup +Module.send(:include, RSpec::Core::SharedExampleGroup) + diff --git a/lib/rspec/core/subject.rb b/lib/rspec/core/subject.rb index 0dbdbcb9fc..81a057bb46 100644 --- a/lib/rspec/core/subject.rb +++ b/lib/rspec/core/subject.rb @@ -193,8 +193,12 @@ def its(attribute, &block) # @see ExampleMethods#subject # @see ExampleMethods#should def subject(name=nil, &block) - define_method(name) { subject } if name - block ? @explicit_subject_block = block : explicit_subject || implicit_subject + if name + let(name, &block) + subject { send name } + else + block ? @explicit_subject_block = block : explicit_subject || implicit_subject + end end attr_reader :explicit_subject_block diff --git a/lib/rspec/core/version.rb b/lib/rspec/core/version.rb index 488d06355f..6813833cb5 100644 --- a/lib/rspec/core/version.rb +++ b/lib/rspec/core/version.rb @@ -1,7 +1,7 @@ module RSpec module Core module Version - STRING = '2.11.1' + STRING = '2.12.0' end end end diff --git a/lib/rspec/core/world.rb b/lib/rspec/core/world.rb index da4f247ab8..992cfa5f9f 100644 --- a/lib/rspec/core/world.rb +++ b/lib/rspec/core/world.rb @@ -9,14 +9,14 @@ class World def initialize(configuration=RSpec.configuration) @configuration = configuration - @example_groups = [].extend(Extensions::Ordered) + @example_groups = [].extend(Extensions::Ordered::ExampleGroups) @shared_example_groups = {} @filtered_examples = Hash.new { |hash,group| hash[group] = begin examples = group.examples.dup examples = filter_manager.prune(examples) examples.uniq - examples.extend(Extensions::Ordered) + examples.extend(Extensions::Ordered::Examples) end } end diff --git a/rspec-core.gemspec b/rspec-core.gemspec index 54dcaae5d5..5f033118cc 100644 --- a/rspec-core.gemspec +++ b/rspec-core.gemspec @@ -23,16 +23,15 @@ Gem::Specification.new do |s| s.rdoc_options = ["--charset=UTF-8"] s.require_path = "lib" - s.add_development_dependency "rake", "~> 0.9.2" + s.add_development_dependency "rake", "~> 10.0.0" s.add_development_dependency "cucumber", "~> 1.1.9" s.add_development_dependency "aruba", "~> 0.4.11" s.add_development_dependency "ZenTest", "4.6.2" s.add_development_dependency "nokogiri", "1.5.2" - s.add_development_dependency "fakefs", "0.4.0" s.add_development_dependency "syntax", "1.0.0" - s.add_development_dependency "mocha", "~> 0.10.5" + s.add_development_dependency "mocha", "~> 0.13.0" s.add_development_dependency "rr", "~> 1.0.4" s.add_development_dependency "flexmock", "~> 0.9.0" end diff --git a/script/FullBuildRakeFile b/script/FullBuildRakeFile deleted file mode 100644 index 272227a2c3..0000000000 --- a/script/FullBuildRakeFile +++ /dev/null @@ -1,63 +0,0 @@ -# this is in a separate rakefile because our main one depends on the bundled gems -# already being installed. This must be able to run w/o bundled gems installed. - -def rake(command = "") - sh "rake #{command}" -end - -desc "Run a full build: install necessary gems with bundler, runs specs, run cukes" -task :build => :bundle_install do - rake -end - -desc "Install necessary gems with bundler and runs specs" -task :spec => :bundle_install do - rake "spec" -end - -desc "Install necessary gems with bundler and runs cukes" -task :cucumber => :bundle_install do - rake "cucumber" -end - -desc "Prints description of current ruby interpreter" -task :print_ruby_description do - description = if defined?(RUBY_DESCRIPTION) - RUBY_DESCRIPTION - else - # RUBY_DESCRIPTION is undefined on 1.8.6 - "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} patchlevel #{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]" - end - - puts - puts "=" * 80 - puts "Using #{description}" - puts "=" * 80 - puts -end - -task :bundle_install => :ensure_bundler_installed do - # Unfortunately, there is no version of ruby-debug that installs cleanly on 1.9.1 and 1.9.2. - # Our Gemfile specifies different versions using conditionals, but we still need to bundle update - # to get bundler to use the different versions. - if RUBY_VERSION =~ /^1\.9/ - sh "bundle update ruby-debug-base19" - end - - sh "bundle install" -end - -task :ensure_bundler_installed => :print_ruby_description do - installed = begin - require 'rubygems' - require 'bundler' - true - rescue LoadError - false - end - - unless installed - sh "gem install bundler" - end -end - diff --git a/script/cucumber b/script/cucumber deleted file mode 100755 index 18356127c2..0000000000 --- a/script/cucumber +++ /dev/null @@ -1 +0,0 @@ -rvm 1.8.6,1.8.7,ree,1.9.1,1.9.2,jruby rake -f script/FullBuildRakeFile cucumber | tee tmp/cucumber.out diff --git a/script/find_path_to_rspec_exe b/script/find_path_to_rspec_exe new file mode 100755 index 0000000000..c09d406f21 --- /dev/null +++ b/script/find_path_to_rspec_exe @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +require File.expand_path('../../bundle/bundler/setup', __FILE__) +rspec_core_path = $LOAD_PATH.grep(/rspec-core\/lib$/).first + +puts File.expand_path('../exe/rspec', rspec_core_path) + diff --git a/script/full_build b/script/full_build deleted file mode 100755 index 65b9b2c941..0000000000 --- a/script/full_build +++ /dev/null @@ -1 +0,0 @@ -rvm 1.8.6,1.8.7,ree,1.9.1,1.9.2,jruby rake -f script/FullBuildRakeFile build | tee tmp/full_build.out diff --git a/script/spec b/script/spec deleted file mode 100755 index 8767d6cb8d..0000000000 --- a/script/spec +++ /dev/null @@ -1 +0,0 @@ -rvm 1.8.6,1.8.7,ree,1.9.1,1.9.2,jruby rake -f script/FullBuildRakeFile spec | tee tmp/spec.out diff --git a/script/test_all b/script/test_all new file mode 100755 index 0000000000..502dd3c8e8 --- /dev/null +++ b/script/test_all @@ -0,0 +1,28 @@ +#!/bin/bash + +function print_and_run { + echo $1 + ($1) +} + +set -e + +echo "Bundling Standalone so we can run the specs w/o bundler loaded" + +bundle install --standalone +path_to_rspec_exe=`script/find_path_to_rspec_exe` + +command_prefix="ruby -r./bundle/bundler/setup.rb -S $path_to_rspec_exe" + +echo "Running all..." + +print_and_run "$command_prefix spec -b --format progress --profile" + +echo +echo "--------------------------------------------------------------------" +echo + +for file in `find spec -iname '*_spec.rb'`; do + print_and_run "$command_prefix $file -b --format progress" +done + diff --git a/spec/autotest/rspec_spec.rb b/spec/autotest/rspec_spec.rb index 69d4be262a..3db337670f 100644 --- a/spec/autotest/rspec_spec.rb +++ b/spec/autotest/rspec_spec.rb @@ -3,7 +3,7 @@ describe Autotest::Rspec2 do let(:rspec_autotest) { Autotest::Rspec2.new } let(:spec_cmd) { File.expand_path("../../../exe/rspec", __FILE__) } - let(:ruby_cmd) { "ruby" } + let(:ruby_cmd) { "/path/to/ruby" } before do File.stub(:exist?) { false } @@ -50,6 +50,11 @@ end end + it "quotes the path of the ruby executable" do + cmd = rspec_autotest.make_test_cmd(@files_to_test) + cmd.should match(%r('/path/to/ruby')) + end + it "gives '--tty' to #{Autotest::Rspec2::RSPEC_EXECUTABLE}, not '--autotest'" do cmd = rspec_autotest.make_test_cmd(@files_to_test) cmd.should match(' --tty ') diff --git a/spec/command_line/order_spec.rb b/spec/command_line/order_spec.rb index 1ddbfabf43..d8f31e2de3 100644 --- a/spec/command_line/order_spec.rb +++ b/spec/command_line/order_spec.rb @@ -5,6 +5,32 @@ let(:stdout) { StringIO.new } before :all do + write_file 'spec/simple_spec.rb', """ + describe 'group 1' do + specify('group 1 example 1') {} + specify('group 1 example 2') {} + specify('group 1 example 3') {} + describe 'group 1-1' do + specify('group 1-1 example 1') {} + specify('group 1-1 example 2') {} + specify('group 1-1 example 3') {} + end + end + """ + + write_file 'spec/simple_spec2.rb', """ + describe 'group 2' do + specify('group 2 example 1') {} + specify('group 2 example 2') {} + specify('group 2 example 3') {} + describe 'group 2-1' do + specify('group 2-1 example 1') {} + specify('group 2-1 example 2') {} + specify('group 2-1 example 3') {} + end + end + """ + write_file 'spec/order_spec.rb', """ describe 'group 1' do specify('group 1 example 1') {} @@ -94,6 +120,14 @@ examples('group 1') {|first_run, second_run| first_run.should eq(second_run)} examples('group 1-1') {|first_run, second_run| first_run.should eq(second_run)} end + + it "runs examples in the same order, regardless of the order in which files are given" do + run_command 'tmp/aruba/spec/simple_spec.rb tmp/aruba/spec/simple_spec2.rb --seed 1337 -f doc' + run_command 'tmp/aruba/spec/simple_spec2.rb tmp/aruba/spec/simple_spec.rb --seed 1337 -f doc' + + top_level_groups {|first_run, second_run| first_run.should eq(second_run)} + nested_groups {|first_run, second_run| first_run.should eq(second_run)} + end end describe '--order default on CLI with --order rand in .rspec' do @@ -110,6 +144,39 @@ end end + context 'when a custom order is configured' do + before do + write_file 'spec/custom_order_spec.rb', """ + RSpec.configure do |config| + config.order_groups_and_examples do |list| + list.sort_by { |item| item.description } + end + end + + describe 'group B' do + specify('group B example D') {} + specify('group B example B') {} + specify('group B example A') {} + specify('group B example C') {} + end + + describe 'group A' do + specify('group A example 1') {} + end + """ + end + + it 'orders the groups and examples by the provided strategy' do + run_command 'tmp/aruba/spec/custom_order_spec.rb -f doc' + + top_level_groups { |groups| groups.flatten.should eq(['group A', 'group B']) } + examples('group B') do |examples| + letters = examples.flatten.map { |e| e[/(.)\z/, 1] } + letters.should eq(['A', 'B', 'C', 'D']) + end + end + end + def examples(group) yield split_in_half(stdout.string.scan(/^\s+#{group} example.*$/)) end diff --git a/spec/rspec/core/configuration_options_spec.rb b/spec/rspec/core/configuration_options_spec.rb index eb39ba385e..1bfa51b0a5 100644 --- a/spec/rspec/core/configuration_options_spec.rb +++ b/spec/rspec/core/configuration_options_spec.rb @@ -1,17 +1,15 @@ require 'spec_helper' require 'ostruct' +require 'rspec/core/drb_options' -describe RSpec::Core::ConfigurationOptions, :fakefs do +describe RSpec::Core::ConfigurationOptions, :isolated_directory => true, :isolated_home => true do include ConfigOptionsHelper it "warns when HOME env var is not set", :unless => (RUBY_PLATFORM == 'java') do - begin - orig_home = ENV.delete("HOME") + without_env_vars 'HOME' do coo = RSpec::Core::ConfigurationOptions.new([]) coo.should_receive(:warn) coo.parse_options - ensure - ENV["HOME"] = orig_home end end @@ -97,19 +95,21 @@ end it "merges --require specified by multiple configuration sources" do - ENV['SPEC_OPTS'] = "--require file_from_env" - opts = config_options_object(*%w[--require file_from_opts]) - config = RSpec::Core::Configuration.new - config.should_receive(:requires=).with(["file_from_opts", "file_from_env"]) - opts.configure(config) + with_env_vars 'SPEC_OPTS' => "--require file_from_env" do + opts = config_options_object(*%w[--require file_from_opts]) + config = RSpec::Core::Configuration.new + config.should_receive(:requires=).with(["file_from_opts", "file_from_env"]) + opts.configure(config) + end end it "merges --I specified by multiple configuration sources" do - ENV['SPEC_OPTS'] = "-I dir_from_env" - opts = config_options_object(*%w[-I dir_from_opts]) - config = RSpec::Core::Configuration.new - config.should_receive(:libs=).with(["dir_from_opts", "dir_from_env"]) - opts.configure(config) + with_env_vars 'SPEC_OPTS' => "-I dir_from_env" do + opts = config_options_object(*%w[-I dir_from_opts]) + config = RSpec::Core::Configuration.new + config.should_receive(:libs=).with(["dir_from_opts", "dir_from_env"]) + opts.configure(config) + end end end @@ -324,49 +324,56 @@ end end - describe "sources: ~/.rspec, ./.rspec, custom, CLI, and SPEC_OPTS" do - before(:each) do - FileUtils.mkpath(File.expand_path("~")) - end - + describe "sources: ~/.rspec, ./.rspec, ./.rspec-local, custom, CLI, and SPEC_OPTS" do it "merges global, local, SPEC_OPTS, and CLI" do File.open("./.rspec", "w") {|f| f << "--line 37"} - File.open("~/.rspec", "w") {|f| f << "--color"} - ENV["SPEC_OPTS"] = "--debug --example 'foo bar'" - options = parse_options("--drb") - options[:color].should be_true - options[:line_numbers].should eq(["37"]) - options[:debug].should be_true - options[:full_description].should eq([/foo\ bar/]) - options[:drb].should be_true + File.open("./.rspec-local", "w") {|f| f << "--format global"} + File.open(File.expand_path("~/.rspec"), "w") {|f| f << "--color"} + with_env_vars 'SPEC_OPTS' => "--debug --example 'foo bar'" do + options = parse_options("--drb") + options[:color].should be_true + options[:line_numbers].should eq(["37"]) + options[:debug].should be_true + options[:full_description].should eq([/foo\ bar/]) + options[:drb].should be_true + options[:formatters].should eq([['global']]) + end end it "prefers SPEC_OPTS over CLI" do - ENV["SPEC_OPTS"] = "--format spec_opts" - parse_options("--format", "cli")[:formatters].should eq([['spec_opts']]) + with_env_vars 'SPEC_OPTS' => "--format spec_opts" do + parse_options("--format", "cli")[:formatters].should eq([['spec_opts']]) + end end it "prefers CLI over file options" do - File.open("./.rspec", "w") {|f| f << "--format local"} - File.open("~/.rspec", "w") {|f| f << "--format global"} + File.open("./.rspec", "w") {|f| f << "--format project"} + File.open(File.expand_path("~/.rspec"), "w") {|f| f << "--format global"} parse_options("--format", "cli")[:formatters].should eq([['cli']]) end - it "prefers local file options over global" do - File.open("./.rspec", "w") {|f| f << "--format local"} - File.open("~/.rspec", "w") {|f| f << "--format global"} + it "prefers project file options over global file options" do + File.open("./.rspec", "w") {|f| f << "--format project"} + File.open(File.expand_path("~/.rspec"), "w") {|f| f << "--format global"} + parse_options[:formatters].should eq([['project']]) + end + + it "prefers local file options over project file options" do + File.open("./.rspec-local", "w") {|f| f << "--format local"} + File.open("./.rspec", "w") {|f| f << "--format global"} parse_options[:formatters].should eq([['local']]) end context "with custom options file" do - it "ignores local and global options files" do - File.open("./.rspec", "w") {|f| f << "--format local"} - File.open("~/.rspec", "w") {|f| f << "--format global"} + it "ignores project and global options files" do + File.open("./.rspec", "w") {|f| f << "--format project"} + File.open(File.expand_path("~/.rspec"), "w") {|f| f << "--format global"} File.open("./custom.opts", "w") {|f| f << "--color"} options = parse_options("-O", "./custom.opts") options[:format].should be_nil options[:color].should be_true end + it "parses -e 'full spec description'" do File.open("./custom.opts", "w") {|f| f << "-e 'The quick brown fox jumps over the lazy dog'"} options = parse_options("-O", "./custom.opts") diff --git a/spec/rspec/core/configuration_spec.rb b/spec/rspec/core/configuration_spec.rb index 40ba7cb1df..ef3ca6babb 100644 --- a/spec/rspec/core/configuration_spec.rb +++ b/spec/rspec/core/configuration_spec.rb @@ -1,15 +1,21 @@ require 'spec_helper' require 'tmpdir' -# so the stdlib module is available... -module Test; module Unit; module Assertions; end; end; end - module RSpec::Core describe Configuration do let(:config) { Configuration.new } + describe "RSpec.configuration with a block" do + before { RSpec.stub(:warn_deprecation) } + + it "is deprecated" do + RSpec.should_receive(:warn_deprecation) + RSpec.configuration {} + end + end + describe "#load_spec_files" do it "loads files using load" do @@ -25,12 +31,8 @@ module RSpec::Core end context "with rspec-1 loaded" do - before do - Object.const_set(:Spec, Module.new) - ::Spec::const_set(:VERSION, Module.new) - ::Spec::VERSION::const_set(:MAJOR, 1) - end - after { Object.__send__(:remove_const, :Spec) } + before { stub_const("Spec::VERSION::MAJOR", 1) } + it "raises with a helpful message" do expect { config.load_spec_files @@ -101,6 +103,16 @@ module RSpec::Core end end + it "allows rspec-mocks to be configured with a provided block" do + mod = Module.new + + RSpec::Mocks.configuration.should_receive(:add_stub_and_should_receive_to).with(mod) + + config.mock_with :rspec do |c| + c.add_stub_and_should_receive_to mod + end + end + context "with a module" do it "sets the mock_framework_adapter to that module" do mod = Module.new @@ -153,7 +165,10 @@ module RSpec::Core end describe "#expect_with" do - before { config.stub(:require) } + before do + stub_const("Test::Unit::Assertions", Module.new) + config.stub(:require) + end it_behaves_like "a configurable framework adapter", :expect_with @@ -213,7 +228,10 @@ module RSpec::Core end describe "#expecting_with_rspec?" do - before { config.stub(:require) } + before do + stub_const("Test::Unit::Assertions", Module.new) + config.stub(:require) + end it "returns false by default" do config.should_not be_expecting_with_rspec @@ -314,12 +332,68 @@ module RSpec::Core config.files_to_run.should_not be_empty end + it "loads files in the default path when run with DRB (e.g., spork)" do + config.stub(:command) { 'spork' } + RSpec::Core::Runner.stub(:running_in_drb?) { true } + config.files_or_directories_to_run = [] + config.files_to_run.should_not be_empty + end + it "does not load files in the default path when run by ruby" do config.stub(:command) { 'ruby' } config.files_or_directories_to_run = [] config.files_to_run.should be_empty end end + + def specify_consistent_ordering_of_files_to_run + File.stub(:directory?).with('a') { true } + + orderings = [ + %w[ a/1.rb a/2.rb a/3.rb ], + %w[ a/2.rb a/1.rb a/3.rb ], + %w[ a/3.rb a/2.rb a/1.rb ] + ].map do |files| + Dir.should_receive(:[]).with(/^a/) { files } + yield + config.files_to_run + end + + orderings.uniq.size.should eq(1) + end + + context 'when the given directories match the pattern' do + it 'orders the files in a consistent ordering, regardless of the underlying OS ordering' do + specify_consistent_ordering_of_files_to_run do + config.pattern = 'a/*.rb' + config.files_or_directories_to_run = 'a' + end + end + end + + context 'when the pattern is given relative to the given directories' do + it 'orders the files in a consistent ordering, regardless of the underlying OS ordering' do + specify_consistent_ordering_of_files_to_run do + config.pattern = '*.rb' + config.files_or_directories_to_run = 'a' + end + end + end + + context 'when given multiple file paths' do + it 'orders the files in a consistent ordering, regardless of the given order' do + File.stub(:directory?) { false } # fake it into thinking these a full file paths + + files = ['a/b/c_spec.rb', 'c/b/a_spec.rb'] + config.files_or_directories_to_run = *files + ordering_1 = config.files_to_run + + config.files_or_directories_to_run = *(files.reverse) + ordering_2 = config.files_to_run + + expect(ordering_1).to eq(ordering_2) + end + end end %w[pattern= filename_pattern=].each do |setter| @@ -503,33 +577,57 @@ def metadata_hash(*args) %w[color color_enabled].each do |color_option| describe "##{color_option}=" do context "given true" do - context "with non-tty output and no autotest" do + before { config.send "#{color_option}=", true } + + context "with config.tty? and output.tty?" do it "does not set color_enabled" do - config.output_stream = StringIO.new - config.output_stream.stub(:tty?) { false } - config.tty = false - config.send "#{color_option}=", true - config.send(color_option).should be_false + output = StringIO.new + config.output_stream = output + + config.tty = true + config.output_stream.stub :tty? => true + + config.send(color_option).should be_true + config.send(color_option, output).should be_true end end - context "with tty output" do + context "with config.tty? and !output.tty?" do + it "sets color_enabled" do + output = StringIO.new + config.output_stream = output + + config.tty = true + config.output_stream.stub :tty? => false + + config.send(color_option).should be_true + config.send(color_option, output).should be_true + end + end + + context "with config.tty? and !output.tty?" do it "does not set color_enabled" do - config.output_stream = StringIO.new - config.output_stream.stub(:tty?) { true } + output = StringIO.new + config.output_stream = output + config.tty = false - config.send "#{color_option}=", true + config.output_stream.stub :tty? => true + config.send(color_option).should be_true + config.send(color_option, output).should be_true end end - context "with tty set" do + context "with !config.tty? and !output.tty?" do it "does not set color_enabled" do - config.output_stream = StringIO.new - config.output_stream.stub(:tty?) { false } - config.tty = true - config.send "#{color_option}=", true - config.send(color_option).should be_true + output = StringIO.new + config.output_stream = output + + config.tty = false + config.output_stream.stub :tty? => false + + config.send(color_option).should be_false + config.send(color_option, output).should be_false end end @@ -546,18 +644,11 @@ def metadata_hash(*args) end context "with ANSICON available" do - before(:all) do - @original_ansicon = ENV['ANSICON'] - ENV['ANSICON'] = 'ANSICON' - end - - after(:all) do - ENV['ANSICON'] = @original_ansicon - end + around(:each) { |e| with_env_vars('ANSICON' => 'ANSICON', &e) } it "enables colors" do config.output_stream = StringIO.new - config.output_stream.stub(:tty?) { true } + config.output_stream.stub :tty? => true config.send "#{color_option}=", true config.send(color_option).should be_true end @@ -631,23 +722,23 @@ def metadata_hash(*args) end it "finds a formatter by class name" do - Object.const_set("ACustomFormatter", Class.new(Formatters::BaseFormatter)) - config.add_formatter "ACustomFormatter" - config.formatters.first.should be_an_instance_of(ACustomFormatter) + stub_const("CustomFormatter", Class.new(Formatters::BaseFormatter)) + config.add_formatter "CustomFormatter" + config.formatters.first.should be_an_instance_of(CustomFormatter) end it "finds a formatter by class fully qualified name" do - RSpec.const_set("CustomFormatter", Class.new(Formatters::BaseFormatter)) + stub_const("RSpec::CustomFormatter", Class.new(Formatters::BaseFormatter)) config.add_formatter "RSpec::CustomFormatter" config.formatters.first.should be_an_instance_of(RSpec::CustomFormatter) end it "requires a formatter file based on its fully qualified name" do - config.should_receive(:require).with('rspec/custom_formatter2') do - RSpec.const_set("CustomFormatter2", Class.new(Formatters::BaseFormatter)) + config.should_receive(:require).with('rspec/custom_formatter') do + stub_const("RSpec::CustomFormatter", Class.new(Formatters::BaseFormatter)) end - config.add_formatter "RSpec::CustomFormatter2" - config.formatters.first.should be_an_instance_of(RSpec::CustomFormatter2) + config.add_formatter "RSpec::CustomFormatter" + config.formatters.first.should be_an_instance_of(RSpec::CustomFormatter) end it "raises NameError if class is unresolvable" do @@ -1128,6 +1219,14 @@ def metadata_hash(*args) config.order.should eq("rand") end + it 'can set random ordering' do + config.force :seed => "rand:37" + RSpec.stub(:configuration => config) + list = [1, 2, 3, 4].extend(Extensions::Ordered::Examples) + Kernel.should_receive(:rand).and_return(3, 1, 4, 2) + list.ordered.should eq([2, 4, 1, 3]) + end + it "forces 'false' value" do config.add_setting :custom_option config.custom_option = true @@ -1175,6 +1274,13 @@ def metadata_hash(*args) it 'sets seed to 123' do config.seed.should eq(123) end + + it 'sets up random ordering' do + RSpec.stub(:configuration => config) + list = [1, 2, 3, 4].extend(Extensions::Ordered::Examples) + Kernel.should_receive(:rand).and_return(3, 1, 4, 2) + list.ordered.should eq([2, 4, 1, 3]) + end end context 'given "default"' do @@ -1190,6 +1296,75 @@ def metadata_hash(*args) it "sets the seed to nil" do config.seed.should be_nil end + + it 'clears the random ordering' do + RSpec.stub(:configuration => config) + list = [1, 2, 3, 4].extend(Extensions::Ordered::Examples) + Kernel.should_not_receive(:rand) + list.ordered.should eq([1, 2, 3, 4]) + end + end + end + + describe "#order_examples" do + before { RSpec.stub(:configuration => config) } + + it 'sets a block that determines the ordering of a collection extended with Extensions::Ordered::Examples' do + examples = [1, 2, 3, 4] + examples.extend Extensions::Ordered::Examples + config.order_examples { |examples| examples.reverse } + examples.ordered.should eq([4, 3, 2, 1]) + end + + it 'sets #order to "custom"' do + config.order_examples { |examples| examples.reverse } + config.order.should eq("custom") + end + end + + describe "#example_ordering_block" do + it 'defaults to a block that returns the passed argument' do + config.example_ordering_block.call([1, 2, 3]).should eq([1, 2, 3]) + end + end + + describe "#order_groups" do + before { RSpec.stub(:configuration => config) } + + it 'sets a block that determines the ordering of a collection extended with Extensions::Ordered::ExampleGroups' do + groups = [1, 2, 3, 4] + groups.extend Extensions::Ordered::ExampleGroups + config.order_groups { |groups| groups.reverse } + groups.ordered.should eq([4, 3, 2, 1]) + end + + it 'sets #order to "custom"' do + config.order_groups { |groups| groups.reverse } + config.order.should eq("custom") + end + end + + describe "#group_ordering_block" do + it 'defaults to a block that returns the passed argument' do + config.group_ordering_block.call([1, 2, 3]).should eq([1, 2, 3]) + end + end + + describe "#order_groups_and_examples" do + let(:examples) { [1, 2, 3, 4].extend Extensions::Ordered::Examples } + let(:groups) { [1, 2, 3, 4].extend Extensions::Ordered::ExampleGroups } + + before do + RSpec.stub(:configuration => config) + config.order_groups_and_examples { |list| list.reverse } + end + + it 'sets a block that determines the ordering of a collection extended with Extensions::Ordered::Examples' do + examples.ordered.should eq([4, 3, 2, 1]) + end + + it 'sets a block that determines the ordering of a collection extended with Extensions::Ordered::ExampleGroups' do + groups.ordered.should eq([4, 3, 2, 1]) end end end diff --git a/spec/rspec/core/deprecations_spec.rb b/spec/rspec/core/deprecations_spec.rb index b628731c75..1e9fd81d35 100644 --- a/spec/rspec/core/deprecations_spec.rb +++ b/spec/rspec/core/deprecations_spec.rb @@ -37,6 +37,15 @@ end end + describe RSpec::Core::SharedExampleGroup do + describe 'share_as' do + it 'is deprecated' do + RSpec.should_receive(:warn_deprecation) + RSpec::Core::SharedExampleGroup.share_as(:DeprecatedSharedConst) {} + end + end + end + describe "Spec::Runner.configure" do it "is deprecated" do RSpec.stub(:warn_deprecation) diff --git a/spec/rspec/core/drb_command_line_spec.rb b/spec/rspec/core/drb_command_line_spec.rb index 9dca54e01c..6763f50cd3 100644 --- a/spec/rspec/core/drb_command_line_spec.rb +++ b/spec/rspec/core/drb_command_line_spec.rb @@ -26,13 +26,7 @@ def config_options(*args) describe "--drb-port" do def with_RSPEC_DRB_set_to(val) - original = ENV['RSPEC_DRB'] - ENV['RSPEC_DRB'] = val - begin - yield - ensure - ENV['RSPEC_DRB'] = original - end + with_env_vars('RSPEC_DRB' => val) { yield } end context "without RSPEC_DRB environment variable set" do diff --git a/spec/rspec/core/drb_options_spec.rb b/spec/rspec/core/drb_options_spec.rb index c510317d6a..2ea34dcd58 100644 --- a/spec/rspec/core/drb_options_spec.rb +++ b/spec/rspec/core/drb_options_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" require 'rspec/core/drb_options' -describe RSpec::Core::DrbOptions, :fakefs do +describe RSpec::Core::DrbOptions, :isolated_directory => true, :isolated_home => true do include ConfigOptionsHelper describe "#drb_argv" do diff --git a/spec/rspec/core/dsl_spec.rb b/spec/rspec/core/dsl_spec.rb index 86a106138b..a79872f787 100644 --- a/spec/rspec/core/dsl_spec.rb +++ b/spec/rspec/core/dsl_spec.rb @@ -1,17 +1,25 @@ require 'spec_helper' main = self -describe "The describe method" do - it 'is available on the main object' do - main.should respond_to(:describe) - end - it 'is available on modules (so example groups can be nested inside them)' do - Module.new.should respond_to(:describe) - end +describe "The RSpec DSL" do + methods = [ + :describe, + :share_examples_for, + :shared_examples_for, + :shared_examples, + :shared_context, + :share_as + ] - it 'is not available on other types of objects' do - Object.new.should_not respond_to(:describe) + methods.each do |method_name| + describe "##{method_name}" do + it "is not added to every object in the system" do + main.should respond_to(method_name) + Module.new.should respond_to(method_name) + Object.new.should_not respond_to(method_name) + end + end end end diff --git a/spec/rspec/core/example_group_spec.rb b/spec/rspec/core/example_group_spec.rb index cdbc7a0335..168dac75c4 100644 --- a/spec/rspec/core/example_group_spec.rb +++ b/spec/rspec/core/example_group_spec.rb @@ -19,6 +19,14 @@ def metadata_hash(*args) end end + context "when RSpec.configuration.format_docstrings is set to a block" do + it "formats the description with that block" do + RSpec.configuration.format_docstrings { |s| s.upcase } + group = ExampleGroup.describe(' an example ') + group.description.should eq(' AN EXAMPLE ') + end + end + context 'when RSpec.configuration.treat_symbols_as_metadata_keys_with_true_values is set to false' do before(:each) do RSpec.configure { |c| c.treat_symbols_as_metadata_keys_with_true_values = false } @@ -385,6 +393,15 @@ def metadata_hash(*args) order.should eq([1,2,3]) end + it "does not set RSpec.wants_to_quit in case of an error in before all (without fail_fast?)" do + group = ExampleGroup.describe + group.before(:all) { raise "error in before all" } + group.example("example") {} + + group.run + RSpec.wants_to_quit.should be_false + end + it "runs the before eachs in order" do group = ExampleGroup.describe order = [] @@ -553,6 +570,24 @@ def metadata_hash(*args) example.metadata[:execution_result][:exception].message.should eq("error in before all") end + it "exposes instance variables set in before(:all) from after(:all) even if a before(:all) error occurs" do + ivar_value_in_after_hook = nil + + group = ExampleGroup.describe do + before(:all) do + @an_ivar = :set_in_before_all + raise "fail" + end + + after(:all) { ivar_value_in_after_hook = @an_ivar } + + it("has a spec") { } + end + + group.run + ivar_value_in_after_hook.should eq(:set_in_before_all) + end + it "treats an error in before(:all) as a failure for a spec in a nested group" do example = nil group = ExampleGroup.describe do @@ -696,7 +731,7 @@ def metadata_hash(*args) example.example_group.description.should eq('A sample nested group') end - it "has top level metadata from the example_group and its ancestors" do + it "has top level metadata from the example_group and its parent groups" do example.example_group.metadata.should include(:little_less_nested => 'yep', :nested_describe => 'yep') end @@ -716,7 +751,7 @@ def metadata_hash(*args) example('ex 1') { 1.should eq(1) } example('ex 2') { 1.should eq(1) } end - group.stub(:filtered_examples) { group.examples.extend(Extensions::Ordered) } + group.stub(:filtered_examples) { group.examples.extend(Extensions::Ordered::Examples) } group.run(reporter).should be_true end @@ -725,7 +760,7 @@ def metadata_hash(*args) example('ex 1') { 1.should eq(1) } example('ex 2') { 1.should eq(2) } end - group.stub(:filtered_examples) { group.examples.extend(Extensions::Ordered) } + group.stub(:filtered_examples) { group.examples.extend(Extensions::Ordered::Examples) } group.run(reporter).should be_false end @@ -734,7 +769,7 @@ def metadata_hash(*args) example('ex 1') { 1.should eq(2) } example('ex 2') { 1.should eq(1) } end - group.stub(:filtered_examples) { group.examples.extend(Extensions::Ordered) } + group.stub(:filtered_examples) { group.examples.extend(Extensions::Ordered::Examples) } group.filtered_examples.each do |example| example.should_receive(:run) end @@ -820,9 +855,13 @@ def metadata_hash(*args) let(:reporter) { double("reporter").as_null_object } context "with fail_fast? => true" do - it "does not run examples after the failed example" do + let(:group) do group = RSpec::Core::ExampleGroup.describe group.stub(:fail_fast?) { true } + group + end + + it "does not run examples after the failed example" do examples_run = [] group.example('example 1') { examples_run << self } group.example('example 2') { examples_run << self; fail; } @@ -832,6 +871,13 @@ def metadata_hash(*args) examples_run.length.should eq(2) end + + it "sets RSpec.wants_to_quit flag if encountering an exception in before(:all)" do + group.before(:all) { raise "error in before all" } + example = group.example("equality") { 1.should eq(2) } + group.run.should be_false + RSpec.wants_to_quit.should be_true + end end context "with RSpec.wants_to_quit=true" do diff --git a/spec/rspec/core/example_spec.rb b/spec/rspec/core/example_spec.rb index b5146313b5..2188baa8d8 100644 --- a/spec/rspec/core/example_spec.rb +++ b/spec/rspec/core/example_spec.rb @@ -45,6 +45,17 @@ def metadata_hash(*args) end end + describe "when there is an explicit description" do + context "when RSpec.configuration.format_docstrings is set to a block" do + it "formats the description using the block" do + RSpec.configuration.format_docstrings { |s| s.strip } + example = example_group.example(' an example with whitespace ') {} + example_group.run + example.description.should eql('an example with whitespace') + end + end + end + describe "when there is no explicit description" do def expect_with(*frameworks) RSpec.configuration.stub(:expecting_with_rspec?).and_return(frameworks.include?(:rspec)) @@ -58,6 +69,16 @@ def assert(val) end end + context "when RSpec.configuration.format_docstrings is set to a block" do + it "formats the description using the block" do + RSpec.configuration.format_docstrings { |s| s.upcase } + example_group.example { 5.should eq(5) } + example_group.run + pattern = /EXAMPLE AT #{relative_path(__FILE__).upcase}:#{__LINE__ - 2}/ + example_group.examples.first.description.should match(pattern) + end + end + context "when `expect_with :rspec` is configured" do before(:each) { expect_with :rspec } @@ -221,12 +242,12 @@ def assert(val) group.run results.should eq([ - "around (before)", - "before", - "example", - "after", - "around (after)" - ]) + "around (before)", + "before", + "example", + "after", + "around (after)" + ]) end context "clearing ivars" do @@ -328,7 +349,7 @@ def run_and_capture_reported_message(group) blah.should be(:success) end end - + context "in before(:each)" do it "sets each example to pending" do group = RSpec::Core::ExampleGroup.describe do @@ -365,6 +386,17 @@ def run_and_capture_reported_message(group) group.examples.first.should be_pending end end + end + describe "timing" do + it "uses RSpec::Core::Time as to not be affected by changes to time in examples" do + reporter = double(:reporter).as_null_object + group = RSpec::Core::ExampleGroup.describe + example = group.example + example.__send__ :start, reporter + Time.stub(:now => Time.utc(2012, 10, 1)) + example.__send__ :finish, reporter + expect(example.metadata[:execution_result][:run_time]).to be < 0.2 + end end end diff --git a/spec/rspec/core/filter_manager_spec.rb b/spec/rspec/core/filter_manager_spec.rb index d8a228e8c3..45e0c35153 100644 --- a/spec/rspec/core/filter_manager_spec.rb +++ b/spec/rspec/core/filter_manager_spec.rb @@ -32,6 +32,26 @@ def opposite(name) filter_manager.send(type).should eq(:foo => 2) filter_manager.send(opposite(type)).should be_empty end + + if name == "include" + [:locations, :line_numbers, :full_description].each do |filter| + context "with :#{filter}" do + it "clears previous inclusions" do + filter_manager = FilterManager.new + filter_manager.include :foo => :bar + filter_manager.include filter => "value" + filter_manager.inclusions.should eq({filter => "value"}) + end + + it "does nothing when :#{filter} previously set" do + filter_manager = FilterManager.new + filter_manager.include filter => "a_value" + filter_manager.include :foo => :bar + filter_manager.inclusions.should eq(filter => "a_value") + end + end + end + end end describe "##{name}!" do @@ -222,35 +242,5 @@ def filterable_object_with(args = {}) filter_manager.exclusions.description.should eq({ :unless => :custom_filter }.inspect) end end - - it "clears the inclusion filter on include :line_numbers" do - filter_manager = FilterManager.new - filter_manager.include :foo => :bar - filter_manager.include :line_numbers => [100] - filter_manager.inclusions.should eq(:line_numbers => [100]) - end - - it "clears the inclusion filter on include :locations" do - filter_manager = FilterManager.new - filter_manager.include :foo => :bar - filter_manager.include :locations => { "path/to/file.rb" => [37] } - filter_manager.inclusions.should eq(:locations => { "path/to/file.rb" => [37] }) - end - - it "clears the inclusion filter on include :full_description" do - filter_manager = FilterManager.new - filter_manager.include :foo => :bar - filter_manager.include :full_description => "this and that" - filter_manager.inclusions.should eq(:full_description => "this and that") - end - - [:locations, :line_numbers, :full_description].each do |filter| - it "does nothing on include if already set standalone filter #{filter}" do - filter_manager = FilterManager.new - filter_manager.include filter => "a_value" - filter_manager.include :foo => :bar - filter_manager.inclusions.should eq(filter => "a_value") - end - end end end diff --git a/spec/rspec/core/formatters/base_formatter_spec.rb b/spec/rspec/core/formatters/base_formatter_spec.rb index 8753856171..272498ff99 100644 --- a/spec/rspec/core/formatters/base_formatter_spec.rb +++ b/spec/rspec/core/formatters/base_formatter_spec.rb @@ -16,6 +16,14 @@ formatter.__send__(:backtrace_line, original_line) original_line.should eq(File.expand_path(__FILE__)) end + + it "deals gracefully with a security error" do + safely do + formatter.__send__(:backtrace_line, __FILE__) + # on some rubies, this doesn't raise a SecurityError; this test just + # assures that if it *does* raise an error, the error is caught inside + end + end end describe "read_failed_line" do @@ -32,6 +40,26 @@ }.should_not raise_error end + it "deals gracefully with a security error" do + exception = mock(:Exception, :backtrace => [ "#{__FILE__}:#{__LINE__}"]) + example = mock(:Example, :file_path => __FILE__) + safely do + lambda { + formatter.send(:read_failed_line, exception, example) + }.should_not raise_error + end + end + + context "when ruby reports a bogus line number in the stack trace" do + it "reports the filename and that it was unable to find the matching line" do + exception = mock(:Exception, :backtrace => [ "#{__FILE__}:10000000" ]) + example = mock(:Example, :file_path => __FILE__) + + msg = formatter.send(:read_failed_line, exception, example) + expect(msg).to include("Unable to find matching line") + end + end + context "when String alias to_int to_i" do before do String.class_eval do @@ -73,7 +101,7 @@ end it "removes lines from rspec and lines that come before the invocation of the at_exit autorun hook" do - formatter.format_backtrace(backtrace, stub.as_null_object).should eq(["./my_spec.rb:5"]) + formatter.format_backtrace(backtrace).should eq(["./my_spec.rb:5"]) end end diff --git a/spec/rspec/core/formatters/base_text_formatter_spec.rb b/spec/rspec/core/formatters/base_text_formatter_spec.rb index ae1227e36e..2853e11055 100644 --- a/spec/rspec/core/formatters/base_text_formatter_spec.rb +++ b/spec/rspec/core/formatters/base_text_formatter_spec.rb @@ -61,12 +61,12 @@ def run_all_and_dump_failures it "preserves ancestry" do example = group.example("example name") { raise "something" } run_all_and_dump_failures - example.example_group.ancestors.size.should == 1 + example.example_group.parent_groups.size.should == 1 end end context "with an exception that has an exception instance as its message" do - it "should not raise NoMethodError" do + it "does not raise NoMethodError" do gonzo_exception = RuntimeError.new gonzo_exception.stub(:message) { gonzo_exception } group.example("example name") { raise gonzo_exception } @@ -138,6 +138,8 @@ def run_all_and_dump_failures end context 'for #share_as' do + before { RSpec.stub(:warn) } + it 'outputs the name and location' do share_as :FooBar do @@ -275,6 +277,8 @@ def run_all_and_dump_pending end context 'for #share_as' do + before { RSpec.stub(:warn) } + it 'outputs the name and location' do share_as :FooBar2 do diff --git a/spec/rspec/core/formatters/helpers_spec.rb b/spec/rspec/core/formatters/helpers_spec.rb index 5d12c78503..c8cb0e03cf 100644 --- a/spec/rspec/core/formatters/helpers_spec.rb +++ b/spec/rspec/core/formatters/helpers_spec.rb @@ -22,6 +22,18 @@ helper.format_duration(45.5).should eq("45.5 seconds") end end + + context '= 61' do + it "returns 'x minute x second' formatted string" do + helper.format_duration(61).should eq("1 minute 1 second") + end + end + + context '= 1' do + it "returns 'x second' formatted string" do + helper.format_duration(1).should eq("1 second") + end + end end describe "format seconds" do diff --git a/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html b/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html new file mode 100644 index 0000000000..0e8f39cb39 --- /dev/null +++ b/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html @@ -0,0 +1,462 @@ + + + + + RSpec results + + + + + + + + +
+ +
+
+

RSpec Code Examples

+
+ +
+ + + +
+ +
+

 

+

 

+
+
+ + +
+
+
+
pending spec with no implementation
+ + + + +
is pending (PENDING: Not yet implemented)
+
+
+
+
+
pending command with block format
+
+
+
+
+
with content that would fail
+ + + + +
is pending (PENDING: No reason given)
+
+
+
+
+
with content that would pass
+ + + + +
+ fails + n.nnnns +
+
RSpec::Core::Pending::PendingExampleFixedError
+
./spec/rspec/core/resources/formatter_specs.rb:18:in `__script__'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+./spec/rspec/core/formatters/html_formatter_spec.rb:31:in `Formatters'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/hash18.rb:196:in `fetch'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/io.rb:255:in `open'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/dir.rb:70:in `chdir'
+./spec/rspec/core/formatters/html_formatter_spec.rb:52:in `Formatters'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/eval18.rb:106:in `instance_exec'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/loader.rb:696:in `run_at_exits'
+kernel/loader.rb:716:in `epilogue'
+kernel/loader.rb:849:in `main'
+
16  context "with content that would pass" do
+17    it "fails" do
+18      pending do
+19        1.should eq(1)
+20      end
+
+
+
+
+
+
+
passing spec
+ +
passesn.nnnns
+
+
+
+
+
failing spec
+ + + +
+ fails + n.nnnns +
+
+expected: 2
+     got: 1
+
+(compared using ==)
+
+
./spec/rspec/core/resources/formatter_specs.rb:33:in `__script__'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+./spec/rspec/core/formatters/html_formatter_spec.rb:31:in `Formatters'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/hash18.rb:196:in `fetch'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/io.rb:255:in `open'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/dir.rb:70:in `chdir'
+./spec/rspec/core/formatters/html_formatter_spec.rb:52:in `Formatters'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/eval18.rb:106:in `instance_exec'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/loader.rb:696:in `run_at_exits'
+kernel/loader.rb:716:in `epilogue'
+kernel/loader.rb:849:in `main'
+
31describe "failing spec" do
+32  it "fails" do
+33    1.should eq(2)
+34  end
+35end
+
+
+
+
+
+
+
a failing spec with odd backtraces
+ + + +
+ fails with a backtrace that has no file + n.nnnns +
+
foo
+
(erb):1:in `__script__'
+kernel/common/block_environment.rb:75:in `call_on_instance'
+kernel/common/eval.rb:75:in `eval'
+/Users/alindeman/.rvm/rubies/rbx-head/lib/18/erb.rb:719:in `result'
+./spec/rspec/core/resources/formatter_specs.rb:41:in `__script__'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+./spec/rspec/core/formatters/html_formatter_spec.rb:31:in `Formatters'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/hash18.rb:196:in `fetch'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/io.rb:255:in `open'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/dir.rb:70:in `chdir'
+./spec/rspec/core/formatters/html_formatter_spec.rb:52:in `Formatters'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/eval18.rb:45:in `instance_eval'
+kernel/common/eval18.rb:106:in `instance_exec'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/bootstrap/array18.rb:18:in `map'
+kernel/loader.rb:696:in `run_at_exits'
+kernel/loader.rb:716:in `epilogue'
+kernel/loader.rb:849:in `main'
+
-1# Couldn't get snippet for (erb)
+
+
+ +
+ fails with a backtrace containing an erb file + n.nnnns +
+
Exception
+
/foo.html.erb:1:in `
': foo (RuntimeError)
+
-1# Couldn't get snippet for /foo.html.erb
+
+
+
+
+ + +
+
+ + diff --git a/spec/rspec/core/formatters/html_formatted-1.9.2-jruby.html b/spec/rspec/core/formatters/html_formatted-1.9.2-jruby.html new file mode 100644 index 0000000000..5abeb5aff1 --- /dev/null +++ b/spec/rspec/core/formatters/html_formatted-1.9.2-jruby.html @@ -0,0 +1,410 @@ + + + + + RSpec results + + + + + + + + +
+ +
+
+

RSpec Code Examples

+
+ +
+ + + +
+ +
+

 

+

 

+
+
+ + +
+
+
+
pending spec with no implementation
+ + + + +
is pending (PENDING: Not yet implemented)
+
+
+
+
+
pending command with block format
+
+
+
+
+
with content that would fail
+ + + + +
is pending (PENDING: No reason given)
+
+
+
+
+
with content that would pass
+ + + + +
+ fails + n.nnnns +
+
RSpec::Core::Pending::PendingExampleFixedError
+
./spec/rspec/core/resources/formatter_specs.rb:18:in `(root)'
+./spec/rspec/core/formatters/html_formatter_spec.rb:32:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:54:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:54:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+
16  context "with content that would pass" do
+17    it "fails" do
+18      pending do
+19        1.should eq(1)
+20      end
+
+
+
+
+
+
+
passing spec
+ +
passesn.nnnns
+
+
+
+
+
failing spec
+ + + +
+ fails + n.nnnns +
+
+expected: 2
+     got: 1
+
+(compared using ==)
+
+
./spec/rspec/core/resources/formatter_specs.rb:33:in `(root)'
+./spec/rspec/core/formatters/html_formatter_spec.rb:32:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:54:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:54:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+
31describe "failing spec" do
+32  it "fails" do
+33    1.should eq(2)
+34  end
+35end
+
+
+
+
+
+
+
a failing spec with odd backtraces
+ + + +
+ fails with a backtrace that has no file + n.nnnns +
+
foo
+
(erb):1:in `result'
+./spec/rspec/core/resources/formatter_specs.rb:41:in `(root)'
+./spec/rspec/core/formatters/html_formatter_spec.rb:32:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:54:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:54:in `Formatters'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+
-1# Couldn't get snippet for (erb)
+
+
+ +
+ fails with a backtrace containing an erb file + n.nnnns +
+
Exception
+
/foo.html.erb:1:in `
': foo (RuntimeError)
+
-1# Couldn't get snippet for /foo.html.erb
+
+
+
+
+ + +
+
+ + diff --git a/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html b/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html new file mode 100644 index 0000000000..5fbcbb9f34 --- /dev/null +++ b/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html @@ -0,0 +1,462 @@ + + + + + RSpec results + + + + + + + + +
+ +
+
+

RSpec Code Examples

+
+ +
+ + + +
+ +
+

 

+

 

+
+
+ + +
+
+
+
pending spec with no implementation
+ + + + +
is pending (PENDING: Not yet implemented)
+
+
+
+
+
pending command with block format
+
+
+
+
+
with content that would fail
+ + + + +
is pending (PENDING: No reason given)
+
+
+
+
+
with content that would pass
+ + + + +
+ fails + n.nnnns +
+
RSpec::Core::Pending::PendingExampleFixedError
+
./spec/rspec/core/resources/formatter_specs.rb:18:in `__script__'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+./spec/rspec/core/formatters/html_formatter_spec.rb:31:in `Formatters'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/hash19.rb:257:in `fetch'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/io.rb:255:in `open'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/dir.rb:70:in `chdir'
+./spec/rspec/core/formatters/html_formatter_spec.rb:52:in `Formatters'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/eval19.rb:105:in `instance_exec'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/loader.rb:696:in `run_at_exits'
+kernel/loader.rb:716:in `epilogue'
+kernel/loader.rb:849:in `main'
+
16  context "with content that would pass" do
+17    it "fails" do
+18      pending do
+19        1.should eq(1)
+20      end
+
+
+
+
+
+
+
passing spec
+ +
passesn.nnnns
+
+
+
+
+
failing spec
+ + + +
+ fails + n.nnnns +
+
+expected: 2
+     got: 1
+
+(compared using ==)
+
+
./spec/rspec/core/resources/formatter_specs.rb:33:in `__script__'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+./spec/rspec/core/formatters/html_formatter_spec.rb:31:in `Formatters'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/hash19.rb:257:in `fetch'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/io.rb:255:in `open'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/dir.rb:70:in `chdir'
+./spec/rspec/core/formatters/html_formatter_spec.rb:52:in `Formatters'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/eval19.rb:105:in `instance_exec'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/loader.rb:696:in `run_at_exits'
+kernel/loader.rb:716:in `epilogue'
+kernel/loader.rb:849:in `main'
+
31describe "failing spec" do
+32  it "fails" do
+33    1.should eq(2)
+34  end
+35end
+
+
+
+
+
+
+
a failing spec with odd backtraces
+ + + +
+ fails with a backtrace that has no file + n.nnnns +
+
foo
+
(erb):1:in `__script__'
+kernel/common/block_environment.rb:75:in `call_on_instance'
+kernel/common/eval.rb:75:in `eval'
+/Users/alindeman/.rvm/rubies/rbx-head/lib/19/erb.rb:753:in `result'
+./spec/rspec/core/resources/formatter_specs.rb:41:in `__script__'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+./spec/rspec/core/formatters/html_formatter_spec.rb:31:in `Formatters'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/hash19.rb:257:in `fetch'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/io.rb:255:in `open'
+./spec/rspec/core/formatters/html_formatter_spec.rb:53:in `Formatters'
+kernel/common/dir.rb:70:in `chdir'
+./spec/rspec/core/formatters/html_formatter_spec.rb:52:in `Formatters'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/eval19.rb:45:in `instance_eval'
+kernel/common/eval19.rb:105:in `instance_exec'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/bootstrap/array19.rb:18:in `map'
+kernel/loader.rb:696:in `run_at_exits'
+kernel/loader.rb:716:in `epilogue'
+kernel/loader.rb:849:in `main'
+
-1# Couldn't get snippet for (erb)
+
+
+ +
+ fails with a backtrace containing an erb file + n.nnnns +
+
Exception
+
/foo.html.erb:1:in `
': foo (RuntimeError)
+
-1# Couldn't get snippet for /foo.html.erb
+
+
+
+
+ + +
+
+ + diff --git a/spec/rspec/core/formatters/html_formatter_spec.rb b/spec/rspec/core/formatters/html_formatter_spec.rb index 69ac2b34c6..a6604eea77 100644 --- a/spec/rspec/core/formatters/html_formatter_spec.rb +++ b/spec/rspec/core/formatters/html_formatter_spec.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 require 'spec_helper' require 'rspec/core/formatters/html_formatter' require 'nokogiri' @@ -6,10 +7,17 @@ module RSpec module Core module Formatters describe HtmlFormatter, :if => RUBY_VERSION =~ /^(1.8.7|1.9.2|1.9.3)$/ do - let(:jruby?) { ::RUBY_PLATFORM == 'java' } - let(:root) { File.expand_path("#{File.dirname(__FILE__)}/../../../..") } - let(:suffix) { jruby? ? '-jruby' : '' } + let(:suffix) { + if ::RUBY_PLATFORM == 'java' + "-jruby" + elsif defined?(Rubinius) + "-rbx" + else + "" + end + } + let(:root) { File.expand_path("#{File.dirname(__FILE__)}/../../../..") } let(:expected_file) do "#{File.dirname(__FILE__)}/html_formatted-#{::RUBY_VERSION}#{suffix}.html" end diff --git a/spec/rspec/core/formatters/json_formatter_spec.rb b/spec/rspec/core/formatters/json_formatter_spec.rb new file mode 100644 index 0000000000..4b3be4225b --- /dev/null +++ b/spec/rspec/core/formatters/json_formatter_spec.rb @@ -0,0 +1,110 @@ +require 'spec_helper' +require 'rspec/core/formatters/json_formatter' +require 'json' +require 'rspec/core/reporter' + +# todo, someday: +# it "lists the groups (describe and context) separately" +# it "includes full 'execution_result'" +# it "relativizes backtrace paths" +# it "includes profile information (implements dump_profile)" +# it "shows the pending message if one was given" +# it "shows the seed if run was randomized" +# it "lists pending specs that were fixed" +describe RSpec::Core::Formatters::JsonFormatter do + let(:output) { StringIO.new } + let(:formatter) { RSpec::Core::Formatters::JsonFormatter.new(output) } + let(:reporter) { RSpec::Core::Reporter.new(formatter) } + + it "outputs json (brittle high level functional test)" do + group = RSpec::Core::ExampleGroup.describe("one apiece") do + it("succeeds") { 1.should == 1 } + it("fails") { fail "eek" } + it("pends") { pending "world peace" } + end + succeeding_line = __LINE__ - 4 + failing_line = __LINE__ - 4 + pending_line = __LINE__ - 4 + + now = Time.now + Time.stub(:now).and_return(now) + reporter.report(2) do |r| + group.run(r) + end + + # grab the actual backtrace -- kind of a cheat + failing_backtrace = formatter.output_hash[:examples][1][:exception][:backtrace] + this_file = relative_path(__FILE__) + + expected = { + :examples => [ + { + :description => "succeeds", + :full_description => "one apiece succeeds", + :status => "passed", + :file_path => this_file, + :line_number => succeeding_line, + }, + { + :description => "fails", + :full_description => "one apiece fails", + :status => "failed", + :file_path => this_file, + :line_number => failing_line, + :exception => {:class => "RuntimeError", :message => "eek", :backtrace => failing_backtrace} + }, + { + :description => "pends", + :full_description => "one apiece pends", + :status => "pending", + :file_path => this_file, + :line_number => pending_line, + }, + ], + :summary => { + :duration => formatter.output_hash[:summary][:duration], + :example_count => 3, + :failure_count => 1, + :pending_count => 1, + }, + :summary_line => "3 examples, 1 failure, 1 pending" + } + formatter.output_hash.should == expected + output.string.should == expected.to_json + end + + describe "#stop" do + it "adds all examples to the output hash" do + formatter.stop + formatter.output_hash[:examples].should_not be_nil + end + end + + describe "#close" do + it "outputs the results as a JSON string" do + output.string.should == "" + formatter.close + output.string.should == {}.to_json + end + end + + describe "#message" do + it "adds a message to the messages list" do + formatter.message("good job") + formatter.output_hash[:messages].should == ["good job"] + end + end + + describe "#dump_summary" do + it "adds summary info to the output hash" do + duration, example_count, failure_count, pending_count = 1.0, 2, 1, 1 + formatter.dump_summary(duration, example_count, failure_count, pending_count) + summary = formatter.output_hash[:summary] + %w(duration example_count failure_count pending_count).each do |key| + summary[key.to_sym].should == eval(key) + end + summary_line = formatter.output_hash[:summary_line] + summary_line.should == "2 examples, 1 failure, 1 pending" + end + end +end diff --git a/spec/rspec/core/formatters/snippet_extractor_spec.rb b/spec/rspec/core/formatters/snippet_extractor_spec.rb index 1d3d3a6829..656153f7fa 100644 --- a/spec/rspec/core/formatters/snippet_extractor_spec.rb +++ b/spec/rspec/core/formatters/snippet_extractor_spec.rb @@ -12,6 +12,14 @@ module Formatters it "falls back on a default message when it doesn't find the file" do RSpec::Core::Formatters::SnippetExtractor.new.lines_around("blech", 8).should eq("# Couldn't get snippet for blech") end + + it "falls back on a default message when it gets a security error" do + message = nil + safely do + message = RSpec::Core::Formatters::SnippetExtractor.new.lines_around("blech", 8) + end + message.should eq("# Couldn't get snippet for blech") + end end end end diff --git a/spec/rspec/core/formatters/text_mate_formatted-1.8.7-rbx.html b/spec/rspec/core/formatters/text_mate_formatted-1.8.7-rbx.html new file mode 100644 index 0000000000..461a4fa4d7 --- /dev/null +++ b/spec/rspec/core/formatters/text_mate_formatted-1.8.7-rbx.html @@ -0,0 +1,462 @@ + + + + + RSpec results + + + + + + + + +
+ +
+
+

RSpec Code Examples

+
+ +
+ + + +
+ +
+

 

+

 

+
+
+ + +
+
+
+
pending spec with no implementation
+ + + + +
is pending (PENDING: Not yet implemented)
+
+
+
+
+
pending command with block format
+
+
+
+
+
with content that would fail
+ + + + +
is pending (PENDING: No reason given)
+
+
+
+
+
with content that would pass
+ + + + +
+ fails + n.nnnns +
+
RSpec::Core::Pending::PendingExampleFixedError
+ +
16  context "with content that would pass" do
+17    it "fails" do
+18      pending do
+19        1.should eq(1)
+20      end
+
+
+
+
+
+
+
passing spec
+ +
passesn.nnnns
+
+
+
+
+
failing spec
+ + + +
+ fails + n.nnnns +
+
+expected: 2
+     got: 1
+
+(compared using ==)
+
+ +
31describe "failing spec" do
+32  it "fails" do
+33    1.should eq(2)
+34  end
+35end
+
+
+
+
+
+
+
a failing spec with odd backtraces
+ + + +
+ fails with a backtrace that has no file + n.nnnns + +
+ +
+ fails with a backtrace containing an erb file + n.nnnns +
+
Exception
+
/foo.html.erb:1 :in `<main>': foo (RuntimeError)
+
-1# Couldn't get snippet for /foo.html.erb
+
+
+
+
+ + +
+
+ + diff --git a/spec/rspec/core/formatters/text_mate_formatted-1.9.2-jruby.html b/spec/rspec/core/formatters/text_mate_formatted-1.9.2-jruby.html new file mode 100644 index 0000000000..47ff4f36bf --- /dev/null +++ b/spec/rspec/core/formatters/text_mate_formatted-1.9.2-jruby.html @@ -0,0 +1,410 @@ + + + + + RSpec results + + + + + + + + +
+ +
+
+

RSpec Code Examples

+
+ +
+ + + +
+ +
+

 

+

 

+
+
+ + +
+
+
+
pending spec with no implementation
+ + + + +
is pending (PENDING: Not yet implemented)
+
+
+
+
+
pending command with block format
+
+
+
+
+
with content that would fail
+ + + + +
is pending (PENDING: No reason given)
+
+
+
+
+
with content that would pass
+ + + + +
+ fails + n.nnnns +
+
RSpec::Core::Pending::PendingExampleFixedError
+ +
16  context "with content that would pass" do
+17    it "fails" do
+18      pending do
+19        1.should eq(1)
+20      end
+
+
+
+
+
+
+
passing spec
+ +
passesn.nnnns
+
+
+
+
+
failing spec
+ + + +
+ fails + n.nnnns +
+
+expected: 2
+     got: 1
+
+(compared using ==)
+
+ +
31describe "failing spec" do
+32  it "fails" do
+33    1.should eq(2)
+34  end
+35end
+
+
+
+
+
+
+
a failing spec with odd backtraces
+ + + +
+ fails with a backtrace that has no file + n.nnnns + +
+ +
+ fails with a backtrace containing an erb file + n.nnnns +
+
Exception
+
/foo.html.erb:1 :in `<main>': foo (RuntimeError)
+
-1# Couldn't get snippet for /foo.html.erb
+
+
+
+
+ + +
+
+ + diff --git a/spec/rspec/core/formatters/text_mate_formatted-1.9.3-rbx.html b/spec/rspec/core/formatters/text_mate_formatted-1.9.3-rbx.html new file mode 100644 index 0000000000..0ab70af5ca --- /dev/null +++ b/spec/rspec/core/formatters/text_mate_formatted-1.9.3-rbx.html @@ -0,0 +1,462 @@ + + + + + RSpec results + + + + + + + + +
+ +
+
+

RSpec Code Examples

+
+ +
+ + + +
+ +
+

 

+

 

+
+
+ + +
+
+
+
pending spec with no implementation
+ + + + +
is pending (PENDING: Not yet implemented)
+
+
+
+
+
pending command with block format
+
+
+
+
+
with content that would fail
+ + + + +
is pending (PENDING: No reason given)
+
+
+
+
+
with content that would pass
+ + + + +
+ fails + n.nnnns +
+
RSpec::Core::Pending::PendingExampleFixedError
+ +
16  context "with content that would pass" do
+17    it "fails" do
+18      pending do
+19        1.should eq(1)
+20      end
+
+
+
+
+
+
+
passing spec
+ +
passesn.nnnns
+
+
+
+
+
failing spec
+ + + +
+ fails + n.nnnns +
+
+expected: 2
+     got: 1
+
+(compared using ==)
+
+ +
31describe "failing spec" do
+32  it "fails" do
+33    1.should eq(2)
+34  end
+35end
+
+
+
+
+
+
+
a failing spec with odd backtraces
+ + + +
+ fails with a backtrace that has no file + n.nnnns + +
+ +
+ fails with a backtrace containing an erb file + n.nnnns +
+
Exception
+
/foo.html.erb:1 :in `<main>': foo (RuntimeError)
+
-1# Couldn't get snippet for /foo.html.erb
+
+
+
+
+ + +
+
+ + diff --git a/spec/rspec/core/formatters/text_mate_formatter_spec.rb b/spec/rspec/core/formatters/text_mate_formatter_spec.rb index fe25a62978..a40bb96792 100644 --- a/spec/rspec/core/formatters/text_mate_formatter_spec.rb +++ b/spec/rspec/core/formatters/text_mate_formatter_spec.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 require 'spec_helper' require 'rspec/core/formatters/text_mate_formatter' require 'nokogiri' @@ -6,10 +7,17 @@ module RSpec module Core module Formatters describe TextMateFormatter do - let(:jruby?) { ::RUBY_PLATFORM == 'java' } - let(:root) { File.expand_path("#{File.dirname(__FILE__)}/../../../..") } - let(:suffix) { jruby? ? '-jruby' : '' } + let(:suffix) { + if ::RUBY_PLATFORM == 'java' + "-jruby" + elsif defined?(Rubinius) + "-rbx" + else + "" + end + } + let(:root) { File.expand_path("#{File.dirname(__FILE__)}/../../../..") } let(:expected_file) do "#{File.dirname(__FILE__)}/text_mate_formatted-#{::RUBY_VERSION}#{suffix}.html" end diff --git a/spec/rspec/core/hooks_filtering_spec.rb b/spec/rspec/core/hooks_filtering_spec.rb index e4b6d85c2a..11aabfbb90 100644 --- a/spec/rspec/core/hooks_filtering_spec.rb +++ b/spec/rspec/core/hooks_filtering_spec.rb @@ -3,7 +3,7 @@ module RSpec::Core describe "config block hook filtering" do describe "unfiltered hooks" do - it "should be ran" do + it "is run" do filters = [] RSpec.configure do |c| c.before(:all) { filters << "before all in config"} @@ -28,7 +28,7 @@ module RSpec::Core 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 + it "is run 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} @@ -46,7 +46,7 @@ module RSpec::Core end end - it "should be ran if the filter matches the example group's filter" do + it "is run if the filter matches the example group's filter" do filters = [] RSpec.configure do |c| c.before(:all, :match => true) { filters << "before all in config"} @@ -116,7 +116,7 @@ module RSpec::Core filters.should eq([:before_all, :after_all]) end - it "should not be ran if the filter doesn't match the example group's filter" do + it "does not run if the filter doesn't match the example group's filter" do filters = [] RSpec.configure do |c| c.before(:all, :match => false) { filters << "before all in config"} @@ -187,7 +187,7 @@ def filters end describe "hooks with multiple filters" do - it "should be ran if all hook filters match the group's filters" do + it "is run if all hook filters match the group's filters" do filters = [] RSpec.configure do |c| c.before(:all, :one => 1) { filters << "before all in config"} @@ -208,7 +208,7 @@ def filters ]) end - it "should not be ran if some hook filters don't match the group's filters" do + it "does not run if some hook filters don't match the group's filters" do filters = [] RSpec.configure do |c| c.before(:all, :one => 1, :four => 4) { filters << "before all in config"} diff --git a/spec/rspec/core/metadata_spec.rb b/spec/rspec/core/metadata_spec.rb index 05b0dd6fec..b7e6247b7b 100644 --- a/spec/rspec/core/metadata_spec.rb +++ b/spec/rspec/core/metadata_spec.rb @@ -4,6 +4,28 @@ module RSpec module Core describe Metadata do + describe '.relative_path' do + let(:here) { File.expand_path(".") } + it "transforms absolute paths to relative paths" do + Metadata.relative_path(here).should == "." + end + it "transforms absolute paths to relative paths anywhere in its argument" do + Metadata.relative_path("foo #{here} bar").should == "foo . bar" + end + it "returns nil if passed an unparseable file:line combo" do + Metadata.relative_path("-e:1").should be_nil + end + # I have no idea what line = line.sub(/\A([^:]+:\d+)$/, '\\1') is supposed to do + it "gracefully returns nil if run in a secure thread" do + safely do + value = Metadata.relative_path(".") + # on some rubies, File.expand_path is not a security error, so accept "." as well + [nil, "."].should include(value) + end + end + + end + describe "#process" do Metadata::RESERVED_KEYS.each do |key| it "prohibits :#{key} as a hash key" do @@ -186,26 +208,32 @@ module Core let(:line_number) { __LINE__ - 1 } it "stores the description" do + mfe.fetch(:description).should eq("example description") mfe[:description].should eq("example description") end it "stores the full_description (group description + example description)" do + mfe.fetch(:full_description).should eq("group description example description") mfe[:full_description].should eq("group description example description") end it "creates an empty execution result" do + mfe.fetch(:execution_result).should eq({}) mfe[:execution_result].should eq({}) end it "extracts file path from caller" do + mfe.fetch(:file_path).should eq(relative_path(__FILE__)) mfe[:file_path].should eq(relative_path(__FILE__)) end it "extracts line number from caller" do + mfe.fetch(:line_number).should eq(line_number) mfe[:line_number].should eq(line_number) end it "extracts location from caller" do + mfe.fetch(:location).should eq("#{relative_path(__FILE__)}:#{line_number}") mfe[:location].should eq("#{relative_path(__FILE__)}:#{line_number}") end @@ -215,6 +243,7 @@ module Core end it "merges arbitrary options" do + mfe.fetch(:arbitrary).should eq(:options) mfe[:arbitrary].should eq(:options) end diff --git a/spec/rspec/core/option_parser_spec.rb b/spec/rspec/core/option_parser_spec.rb index 2c69d052cf..64ba36107f 100644 --- a/spec/rspec/core/option_parser_spec.rb +++ b/spec/rspec/core/option_parser_spec.rb @@ -15,6 +15,17 @@ module RSpec::Core parser.parse!([]) end + it "proposes you to use --help and returns an error on incorrect argument" do + parser = Parser.new + option = "--my_wrong_arg" + + parser.should_receive(:abort) do |msg| + expect(msg).to include('use --help', option) + end + + parser.parse!([option]) + end + describe "--formatter" do it "is deprecated" do RSpec.should_receive(:deprecate) @@ -27,6 +38,37 @@ module RSpec::Core end end + describe "--default_path" do + it "gets converted to --default-path" do + options = Parser.parse!(%w[--default_path foo]) + options[:default_path].should == "foo" + end + end + + describe "--line_number" do + it "gets converted to --line-number" do + options = Parser.parse!(%w[--line_number 3]) + options[:line_numbers].should == ["3"] + end + end + + + describe "--default-path" do + it "sets the default path where RSpec looks for examples" do + options = Parser.parse!(%w[--default-path foo]) + options[:default_path].should == "foo" + end + end + + %w[--line-number -l].each do |option| + describe option do + it "sets the line number of an example to run" do + options = Parser.parse!([option, "3"]) + options[:line_numbers].should == ["3"] + end + end + end + %w[--format -f].each do |option| describe option do it "defines the formatter" do diff --git a/spec/rspec/core/project_initializer_spec.rb b/spec/rspec/core/project_initializer_spec.rb index 729bc83606..77f3934b83 100644 --- a/spec/rspec/core/project_initializer_spec.rb +++ b/spec/rspec/core/project_initializer_spec.rb @@ -1,7 +1,8 @@ require "spec_helper" module RSpec::Core - describe ProjectInitializer, :fakefs do + describe ProjectInitializer, :isolated_directory => true do + describe "#run" do context "with no args" do let(:command_line_config) { ProjectInitializer.new } @@ -121,7 +122,6 @@ module RSpec::Core config = ProjectInitializer.new("another_arg") config.stub(:puts) config.stub(:gets => 'no') - config.should_receive(:warn).with(/no longer.*another_arg was ignored/) config.run end end diff --git a/spec/rspec/core/rake_task_spec.rb b/spec/rspec/core/rake_task_spec.rb index c886cfcb77..f2f9b97c2c 100644 --- a/spec/rspec/core/rake_task_spec.rb +++ b/spec/rspec/core/rake_task_spec.rb @@ -19,6 +19,25 @@ def spec_command task.__send__(:spec_command) end + context "with a name passed to the constructor" do + let(:task) { RakeTask.new(:task_name) } + + it "correctly sets the name" do + task.name.should == :task_name + end + end + + context "with args passed to the rake task" do + it "correctly passes along task arguments" do + task = RakeTask.new(:rake_task_args, :files) do |t, args| + args[:files].should == "first_spec.rb" + end + + task.should_receive(:run_task) { true } + Rake.application.invoke_task("rake_task_args[first_spec.rb]").should be_true + end + end + context "default" do it "renders rspec" do spec_command.should =~ /^#{ruby} -S rspec/ @@ -27,10 +46,10 @@ def spec_command context "with rcov" do it "renders rcov" do - with_rcov do - spec_command.should =~ /^#{ruby} -S rcov/ - end + with_rcov do + spec_command.should =~ /^#{ruby} -S rcov/ end + end end context "with ruby options" do @@ -80,31 +99,55 @@ def spec_command end end - context "with SPEC=path/to/file" do - before do - @orig_spec = ENV["SPEC"] - ENV["SPEC"] = "path/to/file" + def specify_consistent_ordering_of_files_to_run(pattern, task) + orderings = [ + %w[ a/1.rb a/2.rb a/3.rb ], + %w[ a/2.rb a/1.rb a/3.rb ], + %w[ a/3.rb a/2.rb a/1.rb ] + ].map do |files| + FileList.should_receive(:[]).with(pattern) { files } + task.__send__(:files_to_run) end - after do - ENV["SPEC"] = @orig_spec - end + orderings.uniq.size.should eq(1) + end + context "with SPEC env var set" do it "sets files to run" do - task.__send__(:files_to_run).should eq(["path/to/file"]) + with_env_vars 'SPEC' => 'path/to/file' do + task.__send__(:files_to_run).should eq(["path/to/file"]) + end end - end - context "with paths with quotes" do - it "escapes the quotes" do - task = RakeTask.new do |t| - t.pattern = File.join(Dir.tmpdir, "*spec.rb") + it "sets the files to run in a consistent order, regardless of the underlying FileList ordering" do + with_env_vars 'SPEC' => 'a/*.rb' do + specify_consistent_ordering_of_files_to_run('a/*.rb', task) end - ["first_spec.rb", "second_\"spec.rb", "third_\'spec.rb"].each do |file_name| + end + end + + it "sets the files to run in a consistent order, regardless of the underlying FileList ordering" do + task = RakeTask.new(:consistent_file_order) do |t| + t.pattern = 'a/*.rb' + end + + # since the config block is deferred til task invocation, must fake + # calling the task so the expected pattern is picked up + task.should_receive(:run_task) { true } + Rake.application.invoke_task(task.name).should be_true + + specify_consistent_ordering_of_files_to_run('a/*.rb', task) + end + + context "with paths with quotes or spaces" do + it "escapes the quotes and spaces" do + task.pattern = File.join(Dir.tmpdir, "*spec.rb") + ["first_spec.rb", "second_\"spec.rb", "third_\'spec.rb", "fourth spec.rb"].each do |file_name| FileUtils.touch(File.join(Dir.tmpdir, file_name)) end task.__send__(:files_to_run).sort.should eq([ File.join(Dir.tmpdir, "first_spec.rb"), + File.join(Dir.tmpdir, "fourth\\ spec.rb"), File.join(Dir.tmpdir, "second_\\\"spec.rb"), File.join(Dir.tmpdir, "third_\\\'spec.rb") ]) diff --git a/spec/rspec/core/reporter_spec.rb b/spec/rspec/core/reporter_spec.rb index 1bb211fa29..d7b32971d3 100644 --- a/spec/rspec/core/reporter_spec.rb +++ b/spec/rspec/core/reporter_spec.rb @@ -99,5 +99,22 @@ module RSpec::Core yielded.should eq(reporter) end end + + describe "timing" do + it "uses RSpec::Core::Time as to not be affected by changes to time in examples" do + formatter = double(:formatter).as_null_object + reporter = Reporter.new formatter + reporter.start 1 + Time.stub(:now => Time.utc(2012, 10, 1)) + + duration = nil + formatter.stub(:dump_summary) do |dur, _, _, _| + duration = dur + end + + reporter.finish 1234 + duration.should be < 0.2 + end + end end end diff --git a/spec/rspec/core/runner_spec.rb b/spec/rspec/core/runner_spec.rb index ee146cf8c7..91ba0b7d02 100644 --- a/spec/rspec/core/runner_spec.rb +++ b/spec/rspec/core/runner_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'rspec/core/drb_command_line' module RSpec::Core describe Runner do diff --git a/spec/rspec/core/shared_example_group_spec.rb b/spec/rspec/core/shared_example_group_spec.rb index 7d903513cb..0b0570f2d6 100644 --- a/spec/rspec/core/shared_example_group_spec.rb +++ b/spec/rspec/core/shared_example_group_spec.rb @@ -6,18 +6,28 @@ module RSpec::Core ExampleModule = Module.new ExampleClass = Class.new + it 'does not add a bunch of private methods to Module' do + seg_methods = RSpec::Core::SharedExampleGroup.private_instance_methods + expect(Module.private_methods & seg_methods).to eq([]) + end + %w[share_examples_for shared_examples_for shared_examples shared_context].each do |shared_method_name| describe shared_method_name do it "is exposed to the global namespace" do Kernel.should respond_to(shared_method_name) end - it "raises an ArgumentError when adding a second shared example group with the same name" do + it "displays a warning when adding a second shared example group with the same name" do group = ExampleGroup.describe('example group') - group.send(shared_method_name, 'shared group') {} - lambda do - group.send(shared_method_name, 'shared group') {} - end.should raise_error(ArgumentError, "Shared example group 'shared group' already exists") + group.send(shared_method_name, 'some shared group') {} + original_declaration = [__FILE__, __LINE__ - 1].join(':') + + warning = nil + Kernel.stub(:warn) { |msg| warning = msg } + + group.send(shared_method_name, 'some shared group') {} + second_declaration = [__FILE__, __LINE__ - 1].join(':') + warning.should include('some shared group', original_declaration, second_declaration) end ["name", :name, ExampleModule, ExampleClass].each do |object| @@ -62,6 +72,8 @@ module RSpec::Core end describe "#share_as" do + before { RSpec.stub(:warn) } + it "is exposed to the global namespace" do Kernel.should respond_to("share_as") end diff --git a/spec/rspec/core/subject_spec.rb b/spec/rspec/core/subject_spec.rb index 140d67df6b..1c4a8bf9d0 100644 --- a/spec/rspec/core/subject_spec.rb +++ b/spec/rspec/core/subject_spec.rb @@ -91,6 +91,17 @@ module RSpec::Core end group.run.should be_true end + + it "is referred from inside subject by the name" do + group = ExampleGroup.describe do + subject(:list) { [1,2,3] } + describe 'first' do + subject(:first_element) { list.first } + it { should eq(1) } + end + end + group.run.should be_true + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ed62ec6c7d..1174b61cc8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,7 +18,13 @@ def self.each_run require 'rspec/autorun' require 'autotest/rspec2' require 'aruba/api' - require 'fakefs/spec_helpers' + + if RUBY_PLATFORM == 'java' + # Works around https://jira.codehaus.org/browse/JRUBY-5678 + require 'fileutils' + ENV['TMPDIR'] = File.expand_path('../../tmp', __FILE__) + FileUtils.mkdir_p(ENV['TMPDIR']) + end Dir['./spec/support/**/*.rb'].map {|f| require f} @@ -66,6 +72,30 @@ def in_editor? ENV.has_key?('TM_MODE') || ENV.has_key?('EMACS') || ENV.has_key?('VIM') end + module EnvHelpers + def with_env_vars(vars) + original = ENV.to_hash + vars.each { |k, v| ENV[k] = v } + + begin + yield + ensure + ENV.replace(original) + end + end + + def without_env_vars(*vars) + original = ENV.to_hash + vars.each { |k| ENV.delete(k) } + + begin + yield + ensure + ENV.replace(original) + end + end + end + RSpec.configure do |c| # structural c.alias_it_behaves_like_to 'it_has_behavior' @@ -79,7 +109,7 @@ def in_editor? c.treat_symbols_as_metadata_keys_with_true_values = true c.color = !in_editor? c.filter_run :focus - c.include FakeFS::SpecHelpers, :fakefs + c.include EnvHelpers c.run_all_when_everything_filtered = true c.filter_run_excluding :ruby => lambda {|version| case version.to_s diff --git a/spec/support/config_options_helper.rb b/spec/support/config_options_helper.rb index 8a6d6514d2..2f987a5c74 100644 --- a/spec/support/config_options_helper.rb +++ b/spec/support/config_options_helper.rb @@ -1,16 +1,7 @@ -require 'fakefs/safe' - module ConfigOptionsHelper extend RSpec::SharedContext - before do - @orig_spec_opts = ENV["SPEC_OPTS"] - ENV.delete("SPEC_OPTS") - end - - after do - ENV["SPEC_OPTS"] = @orig_spec_opts - end + around(:each) { |e| without_env_vars('SPEC_OPTS', &e) } def config_options_object(*args) coo = RSpec::Core::ConfigurationOptions.new(args) diff --git a/spec/support/helper_methods.rb b/spec/support/helper_methods.rb index 74cbdb6750..12368c7783 100644 --- a/spec/support/helper_methods.rb +++ b/spec/support/helper_methods.rb @@ -2,4 +2,17 @@ module RSpecHelpers def relative_path(path) RSpec::Core::Metadata.relative_path(path) end + + def safely + Thread.new do + $SAFE = 3 + yield + end.join + + # $SAFE is not supported on Rubinius + unless defined?(Rubinius) + expect($SAFE).to eql 0 # $SAFE should not have changed in this thread. + end + end + end diff --git a/spec/support/isolated_directory.rb b/spec/support/isolated_directory.rb new file mode 100644 index 0000000000..b01c2b9efd --- /dev/null +++ b/spec/support/isolated_directory.rb @@ -0,0 +1,10 @@ +require 'tmpdir' +require 'fileutils' + +shared_context "isolated directory", :isolated_directory => true do + around do |ex| + Dir.mktmpdir do |tmp_dir| + Dir.chdir(tmp_dir, &ex) + end + end +end diff --git a/spec/support/isolated_home_directory.rb b/spec/support/isolated_home_directory.rb new file mode 100644 index 0000000000..b66f6064f1 --- /dev/null +++ b/spec/support/isolated_home_directory.rb @@ -0,0 +1,16 @@ +require 'tmpdir' +require 'fileutils' + +shared_context "isolated home directory", :isolated_home => true do + around do |ex| + Dir.mktmpdir do |tmp_dir| + original_home = ENV['HOME'] + begin + ENV['HOME'] = tmp_dir + ex.call + ensure + ENV['HOME'] = original_home + end + end + end +end