From 4dd320b38bc6376e1355e66995521a961bc9d236 Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Wed, 1 Jan 2020 15:31:07 +0100 Subject: [PATCH 01/18] Bump yard to support Ruby 2.7 See: https://github.com/lsegal/yard/releases/tag/v0.9.21 - Avoid a bug with a yard and source code not well rendered by bumping redcarpet version - To avoid loosing big comment in yard we need to have blank line This is not needed to provide this option --- Gemfile | 6 +++--- lib/rspec/core/formatters.rb | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index b6618befeb..22e791c05d 100644 --- a/Gemfile +++ b/Gemfile @@ -20,12 +20,12 @@ else gem 'rake', '< 11.0.0' # rake 11 requires Ruby 1.9.3 or later end -gem 'yard', '~> 0.9.12', :require => false +gem 'yard', '~> 0.9.24', :require => false ### deps for rdoc.info group :documentation do - gem 'redcarpet', '2.1.1', :platform => :mri - gem 'github-markup', '0.7.2', :platform => :mri + gem 'redcarpet', :platform => :mri + gem 'github-markup', :platform => :mri end if RUBY_VERSION < '2.0.0' || RUBY_ENGINE == 'java' diff --git a/lib/rspec/core/formatters.rb b/lib/rspec/core/formatters.rb index 7a412a1a1c..a693a80c5c 100644 --- a/lib/rspec/core/formatters.rb +++ b/lib/rspec/core/formatters.rb @@ -1,4 +1,5 @@ RSpec::Support.require_rspec_support "directory_maker" + # ## Built-in Formatters # # * progress (default) - Prints dots for passing examples, `F` for failures, `*` From 36c5ad5a061fb9b5cd1c9aafe423079209fdc2b5 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Sun, 12 Jan 2020 21:08:45 +0000 Subject: [PATCH 02/18] Merge pull request #2687 from rspec/add-around-context-warning Emit a warning for `around(:context)` --- Changelog.md | 8 ++++++++ lib/rspec/core/hooks.rb | 5 +++++ spec/rspec/core/hooks_spec.rb | 29 +++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/Changelog.md b/Changelog.md index 40c1237da2..1598f0e4a1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,11 @@ +### Development +[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.1...master) + +Bug Fixes: + +* Emit a warning when `around` hook is used with `:context` scope + (Phil Pirozhkov, #2687) + ### 3.9.1 / 2019-12-28 [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.0...v3.9.1) diff --git a/lib/rspec/core/hooks.rb b/lib/rspec/core/hooks.rb index 56c0be852d..6cde2ca1a5 100644 --- a/lib/rspec/core/hooks.rb +++ b/lib/rspec/core/hooks.rb @@ -448,6 +448,11 @@ def register(prepend_or_append, position, *args, &block) "`#{position}(:suite)` hook, registered on an example " \ "group, will be ignored." return + elsif scope == :context && position == :around + # TODO: consider making this an error in RSpec 4. For SemVer reasons, + # we are only warning in RSpec 3. + RSpec.warn_with "WARNING: `around(:context)` hooks are not supported and " \ + "behave like `around(:example)." end hook = HOOK_TYPES[position][scope].new(block, options) diff --git a/spec/rspec/core/hooks_spec.rb b/spec/rspec/core/hooks_spec.rb index d9fb62de9f..895de436ca 100644 --- a/spec/rspec/core/hooks_spec.rb +++ b/spec/rspec/core/hooks_spec.rb @@ -492,5 +492,34 @@ def yielder :hooks ]) end + + it 'emits a warning for `around(:context)`' do + expect(RSpec).to receive(:warn_with).with(a_string_including( + '`around(:context)` hooks are not supported' + )) + RSpec.describe do + around(:context) { } + end + end + + it 'emits a warning for `around(:context)` defined in `configure`' do + expect(RSpec).to receive(:warn_with).with(a_string_including( + '`around(:context)` hooks are not supported' + )) + RSpec.configure do |c| + c.around(:context) { } + end + end + + [:before, :around, :after].each do |type| + it "emits a warning for `#{type}(:suite)` hooks" do + expect(RSpec).to receive(:warn_with).with(a_string_including( + "`#{type}(:suite)` hooks are only supported on the RSpec configuration object." + )) + RSpec.describe do + send(type, :suite) { } + end + end + end end end From 305671f64ef78654401c2f860df7feabded51bde Mon Sep 17 00:00:00 2001 From: Phil Pirozhkov Date: Fri, 24 Jan 2020 00:45:39 +0300 Subject: [PATCH 03/18] Merge pull request #2691 from rspec/update-travis-build-scripts-2020-01-23-for-master Updates from rspec-dev (2020-01-23) --- .rubocop_rspec_base.yml | 2 +- .travis.yml | 2 +- appveyor.yml | 2 +- script/clone_all_rspec_repos | 2 +- script/functions.sh | 2 +- script/predicate_functions.sh | 28 ++++++++++++++-------- script/run_build | 2 +- script/travis_functions.sh | 2 +- script/update_rubygems_and_install_bundler | 2 +- 9 files changed, 26 insertions(+), 18 deletions(-) diff --git a/.rubocop_rspec_base.yml b/.rubocop_rspec_base.yml index 4e00c2c555..852893b2a8 100644 --- a/.rubocop_rspec_base.yml +++ b/.rubocop_rspec_base.yml @@ -1,4 +1,4 @@ -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. # This file contains defaults for RSpec projects. Individual projects diff --git a/.travis.yml b/.travis.yml index cd2c8230f7..41253a3efe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. # In order to install old Rubies, we need to use old Ubuntu distibution. diff --git a/appveyor.yml b/appveyor.yml index fb9dfcf0d4..d5eb832c73 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. version: "{build}" diff --git a/script/clone_all_rspec_repos b/script/clone_all_rspec_repos index 72fa6df32f..bd137b3a77 100755 --- a/script/clone_all_rspec_repos +++ b/script/clone_all_rspec_repos @@ -1,5 +1,5 @@ #!/bin/bash -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e diff --git a/script/functions.sh b/script/functions.sh index 127aa3e933..545a18b86c 100644 --- a/script/functions.sh +++ b/script/functions.sh @@ -1,4 +1,4 @@ -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" diff --git a/script/predicate_functions.sh b/script/predicate_functions.sh index b54fa61d63..17516df418 100644 --- a/script/predicate_functions.sh +++ b/script/predicate_functions.sh @@ -1,4 +1,4 @@ -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. function is_mri { @@ -57,6 +57,22 @@ function is_mri_2plus { fi } +function is_ruby_23_plus { + if ruby -e "exit(RUBY_VERSION.to_f >= 2.3)"; then + return 0 + else + return 1 + fi +} + +function is_ruby_25_plus { + if ruby -e "exit(RUBY_VERSION.to_f >= 2.5)"; then + return 0 + else + return 1 + fi +} + function is_mri_27 { if is_mri; then if ruby -e "exit(RUBY_VERSION.to_f == 2.7)"; then @@ -69,16 +85,8 @@ function is_mri_27 { fi } -function is_ruby_23_plus { - if ruby -e "exit(RUBY_VERSION.to_f >= 2.3)"; then - return 0 - else - return 1 - fi -} - function rspec_rails_compatible { - if is_ruby_23_plus; then + if is_ruby_25_plus; then return 0 else return 1 diff --git a/script/run_build b/script/run_build index f8ce7a4cda..f1b755274f 100755 --- a/script/run_build +++ b/script/run_build @@ -1,5 +1,5 @@ #!/bin/bash -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e diff --git a/script/travis_functions.sh b/script/travis_functions.sh index 3770b23d89..9574746a3c 100644 --- a/script/travis_functions.sh +++ b/script/travis_functions.sh @@ -1,4 +1,4 @@ -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. # Taken from: diff --git a/script/update_rubygems_and_install_bundler b/script/update_rubygems_and_install_bundler index 1b4ff8b04d..b569ac0aa4 100755 --- a/script/update_rubygems_and_install_bundler +++ b/script/update_rubygems_and_install_bundler @@ -1,5 +1,5 @@ #!/bin/bash -# This file was generated on 2019-12-26T17:20:33+00:00 from the rspec-dev repo. +# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e From b7d4234058e1c4a23f145de3e6e31faa65aa0fdd Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Fri, 31 Jan 2020 17:04:33 +0000 Subject: [PATCH 04/18] Merge pull request #2681 from rspec/metadata-slightly-improve-code-and-docs Some improvements to metadata docs --- lib/rspec/core/configuration.rb | 47 ++++++++++++++++++++++++++------- lib/rspec/core/example_group.rb | 35 +++++++++++++++--------- lib/rspec/core/hooks.rb | 28 +++++++++++--------- 3 files changed, 76 insertions(+), 34 deletions(-) diff --git a/lib/rspec/core/configuration.rb b/lib/rspec/core/configuration.rb index 8bc099ce2b..0ad7e28b4a 100644 --- a/lib/rspec/core/configuration.rb +++ b/lib/rspec/core/configuration.rb @@ -1350,6 +1350,12 @@ def exclusion_filter # end # end # + # module PreferencesHelpers + # def preferences(user, preferences = {}) + # # ... + # end + # end + # # module UserHelpers # def users(username) # # ... @@ -1358,12 +1364,17 @@ def exclusion_filter # # RSpec.configure do |config| # config.include(UserHelpers) # included in all groups + # + # # included in examples with `:preferences` metadata + # config.include(PreferenceHelpers, :preferences) + # + # # included in examples with `:type => :request` metadata # config.include(AuthenticationHelpers, :type => :request) # end # - # describe "edit profile", :type => :request do + # describe "edit profile", :preferences, :type => :request do # it "can be viewed by owning user" do - # login_as users(:jdoe) + # login_as preferences(users(:jdoe), :lang => 'es') # get "/profiles/jdoe" # assert_select ".username", :text => 'jdoe' # end @@ -1391,17 +1402,21 @@ def include(mod, *filters) # # @example # - # RSpec.shared_context "example users" do + # RSpec.shared_context "example admin user" do # let(:admin_user) { create_user(:admin) } + # end + # + # RSpec.shared_context "example guest user" do # let(:guest_user) { create_user(:guest) } # end # # RSpec.configure do |config| - # config.include_context "example users", :type => :request + # config.include_context "example guest user", :type => :request + # config.include_context "example admin user", :admin, :type => :request # end # # RSpec.describe "The admin page", :type => :request do - # it "can be viewed by admins" do + # it "can be viewed by admins", :admin do # login_with admin_user # get "/admin" # expect(response).to be_ok @@ -1443,12 +1458,20 @@ def include_context(shared_group_name, *filters) # end # end # + # module PermissionHelpers + # def define_permissions + # # ... + # end + # end + # # RSpec.configure do |config| # config.extend(UiHelpers, :type => :request) + # config.extend(PermissionHelpers, :with_permissions, :type => :request) # end # - # describe "edit profile", :type => :request do + # describe "edit profile", :with_permissions, :type => :request do # run_in_browser + # define_permissions # # it "does stuff in the client" do # # ... @@ -1906,7 +1929,8 @@ def apply_derived_metadata_to(metadata) # # This method differs from {Hooks#before} in only one way: it supports # the `:suite` scope. Hooks with the `:suite` scope will be run once before - # the first example of the entire suite is executed. + # the first example of the entire suite is executed. Conditions passed along + # with `:suite` are effectively ignored. # # @see #prepend_before # @see #after @@ -1935,7 +1959,8 @@ def before(scope=nil, *meta, &block) # # This method differs from {Hooks#prepend_before} in only one way: it supports # the `:suite` scope. Hooks with the `:suite` scope will be run once before - # the first example of the entire suite is executed. + # the first example of the entire suite is executed. Conditions passed along + # with `:suite` are effectively ignored. # # @see #before # @see #after @@ -1959,7 +1984,8 @@ def prepend_before(scope=nil, *meta, &block) # # This method differs from {Hooks#after} in only one way: it supports # the `:suite` scope. Hooks with the `:suite` scope will be run once after - # the last example of the entire suite is executed. + # the last example of the entire suite is executed. Conditions passed along + # with `:suite` are effectively ignored. # # @see #append_after # @see #before @@ -1988,7 +2014,8 @@ def after(scope=nil, *meta, &block) # # This method differs from {Hooks#append_after} in only one way: it supports # the `:suite` scope. Hooks with the `:suite` scope will be run once after - # the last example of the entire suite is executed. + # the last example of the entire suite is executed. Conditions passed along + # with `:suite` are effectively ignored. # # @see #append_after # @see #before diff --git a/lib/rspec/core/example_group.rb b/lib/rspec/core/example_group.rb index 05f4fa7596..2654f105d3 100644 --- a/lib/rspec/core/example_group.rb +++ b/lib/rspec/core/example_group.rb @@ -111,16 +111,14 @@ def described_class # @overload $1 # @overload $1(&example_implementation) # @param example_implementation [Block] The implementation of the example. - # @overload $1(doc_string, *metadata_keys, metadata={}) + # @overload $1(doc_string, *metadata) # @param doc_string [String] The example's doc string. - # @param metadata [Hash] Metadata for the example. - # @param metadata_keys [Array] Metadata tags for the example. - # Will be transformed into hash entries with `true` values. - # @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation) + # @param metadata [Array, Hash] Metadata for the example. + # Symbols will be transformed into hash entries with `true` values. + # @overload $1(doc_string, *metadata, &example_implementation) # @param doc_string [String] The example's doc string. - # @param metadata [Hash] Metadata for the example. - # @param metadata_keys [Array] Metadata tags for the example. - # Will be transformed into hash entries with `true` values. + # @param metadata [Array, Hash] Metadata for the example. + # Symbols will be transformed into hash entries with `true` values. # @param example_implementation [Block] The implementation of the example. # @yield [Example] the example object # @example @@ -139,6 +137,11 @@ def described_class # $1 "does something" do |ex| # # ex is the Example object that contains metadata about the example # end + # + # @example + # $1 "does something", :slow, :load_factor => 100 do + # end + # def self.define_example_method(name, extra_options={}) idempotently_define_singleton_method(name) do |*all_args, &block| desc, *args = *all_args @@ -204,11 +207,10 @@ def self.define_example_method(name, extra_options={}) # @overload $1 # @overload $1(&example_group_definition) # @param example_group_definition [Block] The definition of the example group. - # @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation) + # @overload $1(doc_string, *metadata, &example_implementation) # @param doc_string [String] The group's doc string. - # @param metadata [Hash] Metadata for the group. - # @param metadata_keys [Array] Metadata tags for the group. - # Will be transformed into hash entries with `true` values. + # @param metadata [Array, Hash] Metadata for the group. + # Symbols will be transformed into hash entries with `true` values. # @param example_group_definition [Block] The definition of the example group. # # Generates a subclass of this example group which inherits @@ -223,12 +225,21 @@ def self.define_example_method(name, extra_options={}) # do_something_before # end # + # before(:example, :clean_env) do + # env.clear! + # end + # # let(:thing) { Thing.new } # # $1 "attribute (of something)" do # # examples in the group get the before hook # # declared above, and can access `thing` # end + # + # $1 "needs additional setup", :clean_env, :implementation => JSON do + # # specifies that hooks with matching metadata + # # should be be run additionally + # end # end # # @see DSL#describe diff --git a/lib/rspec/core/hooks.rb b/lib/rspec/core/hooks.rb index 6cde2ca1a5..d942dce060 100644 --- a/lib/rspec/core/hooks.rb +++ b/lib/rspec/core/hooks.rb @@ -13,13 +13,14 @@ module Hooks # @overload before(scope, &block) # @param scope [Symbol] `:example`, `:context`, or `:suite` # (defaults to `:example`) - # @overload before(scope, conditions, &block) + # @overload before(scope, *conditions, &block) # @param scope [Symbol] `:example`, `:context`, or `:suite` # (defaults to `:example`) - # @param conditions [Hash] - # constrains this hook to examples matching these conditions e.g. + # @param conditions [Array, Hash] constrains this hook to + # examples matching these conditions e.g. # `before(:example, :ui => true) { ... }` will only run with examples - # or groups declared with `:ui => true`. + # or groups declared with `:ui => true`. Symbols will be transformed + # into hash entries with `true` values. # @overload before(conditions, &block) # @param conditions [Hash] # constrains this hook to examples matching these conditions e.g. @@ -214,13 +215,14 @@ def prepend_before(*args, &block) # @overload after(scope, &block) # @param scope [Symbol] `:example`, `:context`, or `:suite` (defaults to # `:example`) - # @overload after(scope, conditions, &block) + # @overload after(scope, *conditions, &block) # @param scope [Symbol] `:example`, `:context`, or `:suite` (defaults to # `:example`) - # @param conditions [Hash] - # constrains this hook to examples matching these conditions e.g. + # @param conditions [Array, Hash] constrains this hook to + # examples matching these conditions e.g. # `after(:example, :ui => true) { ... }` will only run with examples - # or groups declared with `:ui => true`. + # or groups declared with `:ui => true`. Symbols will be transformed + # into hash entries with `true` values. # @overload after(conditions, &block) # @param conditions [Hash] # constrains this hook to examples matching these conditions e.g. @@ -290,13 +292,15 @@ def append_after(*args, &block) # @param scope [Symbol] `:example` (defaults to `:example`) # present for syntax parity with `before` and `after`, but # `:example`/`:each` is the only supported value. - # @overload around(scope, conditions, &block) + # @overload around(scope, *conditions, &block) # @param scope [Symbol] `:example` (defaults to `:example`) # present for syntax parity with `before` and `after`, but # `:example`/`:each` is the only supported value. - # @param conditions [Hash] constrains this hook to examples matching - # these conditions e.g. `around(:example, :ui => true) { ... }` will - # only run with examples or groups declared with `:ui => true`. + # @param conditions [Array, Hash] constrains this hook to + # examples matching these conditions e.g. + # `around(:example, :ui => true) { ... }` will only run with examples + # or groups declared with `:ui => true`. Symbols will be transformed + # into hash entries with `true` values. # @overload around(conditions, &block) # @param conditions [Hash] constrains this hook to examples matching # these conditions e.g. `around(:example, :ui => true) { ... }` will From 4d2a6bb7c76ff5124aaa92636a1cf4f92cdcbdb5 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Tue, 4 Feb 2020 16:28:55 +0000 Subject: [PATCH 05/18] Merge pull request #2693 from skalee/missing-backtick-in-features Add a missing backtick in scenario title --- features/hooks/before_and_after_hooks.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/hooks/before_and_after_hooks.feature b/features/hooks/before_and_after_hooks.feature index 6110a9819e..07a9f7b5cd 100644 --- a/features/hooks/before_and_after_hooks.feature +++ b/features/hooks/before_and_after_hooks.feature @@ -253,7 +253,7 @@ Feature: `before` and `after` hooks .after context """ - Scenario: `before`/after` blocks defined in configuration are run in order + Scenario: `before`/`after` blocks defined in configuration are run in order Given a file named "configuration_spec.rb" with: """ruby require "rspec/expectations" From 52c374764146cd9711bebd5045b1cf0508f7772a Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Thu, 12 Mar 2020 21:05:53 +0000 Subject: [PATCH 06/18] Merge pull request #2703 from rspec/ensure-exception-presenter-ignores-invalid-cause Prevent invalid cause from breaking exception presenter --- Changelog.md | 3 ++ .../core/formatters/exception_presenter.rb | 9 ++-- .../formatters/exception_presenter_spec.rb | 48 +++++++++++++++---- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/Changelog.md b/Changelog.md index 1598f0e4a1..78970eb5df 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,9 @@ Bug Fixes: * Emit a warning when `around` hook is used with `:context` scope (Phil Pirozhkov, #2687) +* Prevent invalid implementations of `Exception#cause` from being treated as a + valid cause (and causing strange errors) in `RSpec::Core::Formatters::ExceptionPresenter`. + (Jon Rowe, #2703) ### 3.9.1 / 2019-12-28 [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.0...v3.9.1) diff --git a/lib/rspec/core/formatters/exception_presenter.rb b/lib/rspec/core/formatters/exception_presenter.rb index 9ad6503e17..db612e8858 100644 --- a/lib/rspec/core/formatters/exception_presenter.rb +++ b/lib/rspec/core/formatters/exception_presenter.rb @@ -43,7 +43,7 @@ def formatted_backtrace(exception=@exception) if RSpec::Support::RubyFeatures.supports_exception_cause? def formatted_cause(exception) - last_cause = final_exception(exception) + last_cause = final_exception(exception, [exception]) cause = [] if exception.cause @@ -55,7 +55,9 @@ def formatted_cause(exception) cause << " #{line}" end - cause << (" #{backtrace_formatter.format_backtrace(last_cause.backtrace, example.metadata).first}") + unless last_cause.backtrace.empty? + cause << (" #{backtrace_formatter.format_backtrace(last_cause.backtrace, example.metadata).first}") + end end cause @@ -96,7 +98,8 @@ def fully_formatted_lines(failure_number, colorizer) def final_exception(exception, previous=[]) cause = exception.cause - if cause && !previous.include?(cause) + + if cause && Exception === cause && !previous.include?(cause) previous << cause final_exception(cause, previous) else diff --git a/spec/rspec/core/formatters/exception_presenter_spec.rb b/spec/rspec/core/formatters/exception_presenter_spec.rb index 347524cc26..104673fa5b 100644 --- a/spec/rspec/core/formatters/exception_presenter_spec.rb +++ b/spec/rspec/core/formatters/exception_presenter_spec.rb @@ -11,7 +11,22 @@ module RSpec::Core before do allow(example.execution_result).to receive(:exception) { exception } example.metadata[:absolute_file_path] = __FILE__ - allow(exception).to receive(:cause) if RSpec::Support::RubyFeatures.supports_exception_cause? + end + + # This is a slightly more realistic exception than our instance_double + # created, as this will behave correctly with `Exception#===`, note we + # monkey patch the backtrace / cause in because these are not public + # api but we need specific values for our fakes. + class FakeException < Exception + def initialize(message, backtrace = [], cause = nil) + super(message) + @backtrace = backtrace + @cause = cause + end + attr_reader :backtrace + if RSpec::Support::RubyFeatures.supports_exception_cause? + attr_accessor :cause + end end describe "#fully_formatted" do @@ -25,7 +40,7 @@ module RSpec::Core line_num = __LINE__ + 1 # The failure happened here! Handles encoding too! ЙЦ end - let(:exception) { instance_double(Exception, :message => "Boom\nBam", :backtrace => [ "#{__FILE__}:#{line_num}"]) } + let(:exception) { FakeException.new("Boom\nBam", [ "#{__FILE__}:#{line_num}"]) } it "formats the exception with all the normal details" do expect(presenter.fully_formatted(1)).to eq(<<-EOS.gsub(/^ +\|/, '')) @@ -159,16 +174,14 @@ module RSpec::Core EOS end - let(:the_exception) { instance_double(Exception, :cause => second_exception, :message => "Boom\nBam", :backtrace => [ "#{__FILE__}:#{line_num}"]) } + let(:the_exception) { FakeException.new("Boom\nBam", [ "#{__FILE__}:#{line_num}"], second_exception) } let(:second_exception) do - instance_double(Exception, :cause => first_exception, :message => "Second\nexception", :backtrace => ["#{__FILE__}:#{__LINE__}"]) + FakeException.new("Second\nexception", ["#{__FILE__}:#{__LINE__}"], first_exception) end - caused_by_line_num = __LINE__ + 2 - let(:first_exception) do - instance_double(Exception, :cause => nil, :message => "Real\nculprit", :backtrace => ["#{__FILE__}:#{__LINE__}"]) - end + caused_by_line_num = __LINE__ + 1 + let(:first_exception) { FakeException.new("Real\nculprit", ["#{__FILE__}:#{__LINE__}"]) } it 'includes the first exception that caused the failure', :if => RSpec::Support::RubyFeatures.supports_exception_cause? do the_presenter = Formatters::ExceptionPresenter.new(the_exception, example) @@ -211,8 +224,9 @@ module RSpec::Core it 'wont produce a stack error when the cause is an older exception', :if => RSpec::Support::RubyFeatures.supports_exception_cause? do allow(the_exception).to receive(:cause) do - instance_double(Exception, :cause => the_exception, :message => "A loop", :backtrace => the_exception.backtrace) + FakeException.new("A loop", the_exception.backtrace, the_exception) end + the_presenter = Formatters::ExceptionPresenter.new(the_exception, example) expect(the_presenter.fully_formatted(1)).to eq(<<-EOS.gsub(/^ +\|/, '')) @@ -230,6 +244,22 @@ module RSpec::Core EOS end + it 'will work when cause is incorrectly overridden', :if => RSpec::Support::RubyFeatures.supports_exception_cause? do + incorrect_cause_exception = FakeException.new("A badly implemented exception", [], "An incorrect cause") + + the_presenter = Formatters::ExceptionPresenter.new(incorrect_cause_exception, example) + + expect(the_presenter.fully_formatted(1)).to eq(<<-EOS.gsub(/^ +\|/, '')) + | + | 1) Example + | Failure/Error: Unable to find matching line from backtrace + | A badly implemented exception + | # ------------------ + | # --- Caused by: --- + | # A badly implemented exception + EOS + end + it "adds extra failure lines from the example metadata" do extra_example = example.clone failure_line = 'http://www.example.com/job_details/123' From 664283fee46bfeac30176701feba25032144202e Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Wed, 18 Mar 2020 20:35:25 +0000 Subject: [PATCH 07/18] Merge pull request #2704 from marcandre/rspec_opt_array Fixes when given an array as `rspec_opt` --- lib/rspec/core/rake_task.rb | 2 +- spec/rspec/core/rake_task_spec.rb | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/rspec/core/rake_task.rb b/lib/rspec/core/rake_task.rb index 7f01eab4f3..8cf474a94f 100644 --- a/lib/rspec/core/rake_task.rb +++ b/lib/rspec/core/rake_task.rb @@ -122,7 +122,7 @@ def file_inclusion_specification if ENV['SPEC'] FileList[ENV['SPEC']].sort elsif String === pattern && !File.exist?(pattern) - return if rspec_opts =~ /--pattern/ + return if [*rspec_opts].any? { |opt| opt =~ /--pattern/ } "--pattern #{escape pattern}" else # Before RSpec 3.1, we used `FileList` to get the list of matched diff --git a/spec/rspec/core/rake_task_spec.rb b/spec/rspec/core/rake_task_spec.rb index 06a28e7f6b..576b8637d0 100644 --- a/spec/rspec/core/rake_task_spec.rb +++ b/spec/rspec/core/rake_task_spec.rb @@ -62,15 +62,26 @@ def spec_command end context "with rspec_opts" do + include RSpec::Core::ShellEscape + it "adds the rspec_opts" do task.rspec_opts = "-Ifoo" - expect(spec_command).to match(/#{task.rspec_path}.*-Ifoo/) + expect(spec_command).to match(/#{task.rspec_path}.*-Ifoo/).and( + include(escape(RSpec::Core::RakeTask::DEFAULT_PATTERN)) # sanity check for following specs + ) end it 'correctly excludes the default pattern if rspec_opts includes --pattern' do task.rspec_opts = "--pattern some_specs" expect(spec_command).to include("--pattern some_specs").and( - exclude(RSpec::Core::RakeTask::DEFAULT_PATTERN) + exclude(escape(RSpec::Core::RakeTask::DEFAULT_PATTERN)) + ) + end + + it 'behaves properly if rspec_opts is an array' do + task.rspec_opts = %w[--pattern some_specs] + expect(spec_command).to include("--pattern some_specs").and( + exclude(escape(RSpec::Core::RakeTask::DEFAULT_PATTERN)) ) end end From 33f15a0e04c354422728f3189fc76f139d430dea Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Wed, 18 Mar 2020 20:49:25 +0000 Subject: [PATCH 08/18] Changelog for #2704 --- Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.md b/Changelog.md index 78970eb5df..e331552cb0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,8 @@ Bug Fixes: * Prevent invalid implementations of `Exception#cause` from being treated as a valid cause (and causing strange errors) in `RSpec::Core::Formatters::ExceptionPresenter`. (Jon Rowe, #2703) +* Correctly detect patterns when `rspec_opts` is an array in `RSpec::Core::RakeTask`. + (Marc-André Lafortune, #2704) ### 3.9.1 / 2019-12-28 [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.0...v3.9.1) From 87fe9a2b39ca17939487e954c157cd80ac3b02a1 Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Wed, 8 Apr 2020 12:45:02 +0200 Subject: [PATCH 09/18] Prevent list from not being formatted by markdown parser in yard --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index e331552cb0..473f0f9ce2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -24,6 +24,7 @@ Bug Fixes: [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.2...v3.9.0) Enhancements: + * Improve the handling of errors during loading support files, if a file errors before loading specs, RSpec will now skip loading the specs. (David Rodríguez, #2568) From edd1054c56f65990923b21c25a71d9fa3ed1198c Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Wed, 8 Apr 2020 18:09:04 +0200 Subject: [PATCH 10/18] Prevent list from not being formatted by markdown parser in yard --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 473f0f9ce2..4e467cd326 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2142,6 +2142,7 @@ Bug fixes [Full Changelog](http://github.com/rspec/rspec-core/compare/v2.2.0...v2.2.1) Bug fixes + * alias_method instead of override Kernel#method_missing (John Wilger) * changed --autotest to --tty in generated command (MIKAMI Yoshiyuki) * revert change to debugger (had introduced conflict with Rails) From 4803790c0c334a5d14282cc47631e380ebb5b19e Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Sat, 2 May 2020 20:26:36 +0100 Subject: [PATCH 11/18] Sync build with master --- .rubocop_rspec_base.yml | 2 +- .travis.yml | 10 +++++----- Gemfile | 8 ++++---- appveyor.yml | 2 +- script/clone_all_rspec_repos | 2 +- script/functions.sh | 3 +-- script/predicate_functions.sh | 20 ++------------------ script/run_build | 2 +- script/travis_functions.sh | 2 +- script/update_rubygems_and_install_bundler | 2 +- spec/rspec/core/example_spec.rb | 4 +++- spec/rspec/core/rake_task_spec.rb | 2 +- spec/support/helper_methods.rb | 5 +++-- 13 files changed, 25 insertions(+), 39 deletions(-) diff --git a/.rubocop_rspec_base.yml b/.rubocop_rspec_base.yml index 852893b2a8..a98671e063 100644 --- a/.rubocop_rspec_base.yml +++ b/.rubocop_rspec_base.yml @@ -1,4 +1,4 @@ -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. # This file contains defaults for RSpec projects. Individual projects diff --git a/.travis.yml b/.travis.yml index 41253a3efe..8fdc4348b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. # In order to install old Rubies, we need to use old Ubuntu distibution. @@ -22,10 +22,10 @@ rvm: - 2.1 - 2.2.10 - 2.3.8 - - 2.4.9 - - 2.5.7 - - 2.6.5 - - 2.7.0 + - 2.4.10 + - 2.5.8 + - 2.6.6 + - 2.7.1 - ruby-head - ree - rbx-3 diff --git a/Gemfile b/Gemfile index 22e791c05d..b781ec5cdf 100644 --- a/Gemfile +++ b/Gemfile @@ -12,12 +12,12 @@ branch = File.read(File.expand_path("../maintenance-branch", __FILE__)).chomp end end -if RUBY_VERSION >= '2.0.0' - gem 'rake', '>= 10.0.0' -elsif RUBY_VERSION >= '1.9.3' +if RUBY_VERSION < '1.9.3' + gem 'rake', '< 11.0.0' # rake 11 requires Ruby 1.9.3 or later +elsif RUBY_VERSION < '2.0.0' gem 'rake', '< 12.0.0' # rake 12 requires Ruby 2.0.0 or later else - gem 'rake', '< 11.0.0' # rake 11 requires Ruby 1.9.3 or later + gem 'rake', '> 12.3.2' end gem 'yard', '~> 0.9.24', :require => false diff --git a/appveyor.yml b/appveyor.yml index d5eb832c73..496e421529 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. version: "{build}" diff --git a/script/clone_all_rspec_repos b/script/clone_all_rspec_repos index bd137b3a77..9a741818c5 100755 --- a/script/clone_all_rspec_repos +++ b/script/clone_all_rspec_repos @@ -1,5 +1,5 @@ #!/bin/bash -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e diff --git a/script/functions.sh b/script/functions.sh index 545a18b86c..713b9fb2e7 100644 --- a/script/functions.sh +++ b/script/functions.sh @@ -1,4 +1,4 @@ -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" @@ -187,7 +187,6 @@ function run_all_spec_suites { fold "rspec-core specs" run_spec_suite_for "rspec-core" fold "rspec-expectations specs" run_spec_suite_for "rspec-expectations" fold "rspec-mocks specs" run_spec_suite_for "rspec-mocks" - if rspec_rails_compatible; then fold "rspec-rails specs" run_spec_suite_for "rspec-rails" fi diff --git a/script/predicate_functions.sh b/script/predicate_functions.sh index 17516df418..b733b725bb 100644 --- a/script/predicate_functions.sh +++ b/script/predicate_functions.sh @@ -1,4 +1,4 @@ -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. function is_mri { @@ -73,18 +73,6 @@ function is_ruby_25_plus { fi } -function is_mri_27 { - if is_mri; then - if ruby -e "exit(RUBY_VERSION.to_f == 2.7)"; then - return 0 - else - return 1 - fi - else - return 1 - fi -} - function rspec_rails_compatible { if is_ruby_25_plus; then return 0 @@ -109,11 +97,7 @@ function additional_specs_available { function documentation_enforced { if [ -x ./bin/yard ]; then if is_mri_2plus; then - if is_mri_27; then - return 1 - else - return 0 - fi + return 0 else return 1 fi diff --git a/script/run_build b/script/run_build index f1b755274f..b5958fb8f2 100755 --- a/script/run_build +++ b/script/run_build @@ -1,5 +1,5 @@ #!/bin/bash -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e diff --git a/script/travis_functions.sh b/script/travis_functions.sh index 9574746a3c..725c1184c5 100644 --- a/script/travis_functions.sh +++ b/script/travis_functions.sh @@ -1,4 +1,4 @@ -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. # Taken from: diff --git a/script/update_rubygems_and_install_bundler b/script/update_rubygems_and_install_bundler index b569ac0aa4..4ceb930cd8 100755 --- a/script/update_rubygems_and_install_bundler +++ b/script/update_rubygems_and_install_bundler @@ -1,5 +1,5 @@ #!/bin/bash -# This file was generated on 2020-01-23T22:37:16+03:00 from the rspec-dev repo. +# This file was generated on 2020-04-03T18:53:21+03:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e diff --git a/spec/rspec/core/example_spec.rb b/spec/rspec/core/example_spec.rb index 81a7cec4a7..325efe91fc 100644 --- a/spec/rspec/core/example_spec.rb +++ b/spec/rspec/core/example_spec.rb @@ -443,7 +443,9 @@ def assert(val) context 'memory leaks, see GH-321, GH-1921' do def self.reliable_gc - 0 != GC.method(:start).arity # older Rubies don't give us options to ensure a full GC + # older Rubies don't give us options to ensure a full GC + # TruffleRuby GC.start arity matches but GC.disable and GC.enable are mock implementations + 0 != GC.method(:start).arity && !(defined?(RUBY_ENGINE) && RUBY_ENGINE == "truffleruby") end def expect_gc(opts) diff --git a/spec/rspec/core/rake_task_spec.rb b/spec/rspec/core/rake_task_spec.rb index 576b8637d0..a1168b6de7 100644 --- a/spec/rspec/core/rake_task_spec.rb +++ b/spec/rspec/core/rake_task_spec.rb @@ -170,7 +170,7 @@ def silence_output(&block) expect { task.with_clean_environment = true - task.ruby_opts = '-e "puts \"Environment: #{ENV.keys}\""' + task.ruby_opts = '-e "puts \"Environment: #{ENV.keys.sort.inspect}\""' task.run_task false }.to avoid_outputting.to_stderr.and output(essential_shell_variables).to_stdout_from_any_process end diff --git a/spec/support/helper_methods.rb b/spec/support/helper_methods.rb index 1ed3d7934c..c4a7027b85 100644 --- a/spec/support/helper_methods.rb +++ b/spec/support/helper_methods.rb @@ -15,8 +15,9 @@ def ignoring_warnings end # In Ruby 2.7 taint was removed and has no effect, whilst SAFE warns that it - # has no effect and will become a normal varible in 3.0. - if RUBY_VERSION >= '2.7' + # has no effect and will become a normal varible in 3.0. Other engines do not + # implement SAFE. + if RUBY_VERSION >= '2.7' || (defined?(RUBY_ENGINE) && RUBY_ENGINE != "ruby") def with_safe_set_to_level_that_triggers_security_errors yield end From abc62115e95e1663c25b6b7ea77bd97d7964a649 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Fri, 27 Mar 2020 08:37:46 +0000 Subject: [PATCH 12/18] Merge pull request #2708 from rspec/add-default-hook-docs Add information about hook defaults to cucumber scenario --- features/hooks/before_and_after_hooks.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/hooks/before_and_after_hooks.feature b/features/hooks/before_and_after_hooks.feature index 07a9f7b5cd..d47bb87d93 100644 --- a/features/hooks/before_and_after_hooks.feature +++ b/features/hooks/before_and_after_hooks.feature @@ -22,6 +22,8 @@ Feature: `before` and `after` hooks after :suite ``` + A bare `before` or `after` hook defaults to the `:example` scope. + `before` and `after` hooks can be defined directly in the example groups they should run in, or in a global `RSpec.configure` block. @@ -231,10 +233,18 @@ Feature: `before` and `after` hooks puts "before example" end + before do + puts "also before example but by default" + end + after(:example) do puts "after example" end + after do + puts "also after example but by default" + end + after(:context) do puts "after context" end @@ -249,6 +259,8 @@ Feature: `before` and `after` hooks """ before context before example + also before example but by default + also after example but by default after example .after context """ From 5853848ede305a39c4514f749fa269d9d2e8d906 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Sat, 4 Apr 2020 17:53:36 +0100 Subject: [PATCH 13/18] Merge pull request #2715 from rspec/scenario-explaining-failures-dont-affect-hooks Add scenario explaining example failures do not affect hooks --- features/hooks/before_and_after_hooks.feature | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/features/hooks/before_and_after_hooks.feature b/features/hooks/before_and_after_hooks.feature index d47bb87d93..82fa55409b 100644 --- a/features/hooks/before_and_after_hooks.feature +++ b/features/hooks/before_and_after_hooks.feature @@ -25,7 +25,8 @@ Feature: `before` and `after` hooks A bare `before` or `after` hook defaults to the `:example` scope. `before` and `after` hooks can be defined directly in the example groups they - should run in, or in a global `RSpec.configure` block. + should run in, or in a global `RSpec.configure` block. Note that the status of + the example does not affect the hooks. **WARNING:** Setting instance variables are not supported in `before(:suite)`. @@ -189,6 +190,29 @@ Feature: `before` and `after` hooks # ./after_context_spec.rb:3 """ + Scenario: A failure in an example does not affect hooks + Given a file named "failure_in_example_spec.rb" with: + """ruby + RSpec.describe "a failing example does not affect hooks" do + before(:context) { puts "before context runs" } + before(:example) { puts "before example runs" } + after(:example) { puts "after example runs" } + after(:context) { puts "after context runs" } + + it "fails the example but runs the hooks" do + raise "An Error" + end + end + """ + When I run `rspec failure_in_example_spec.rb` + Then it should fail with: + """ + before context runs + before example runs + after example runs + Fafter context runs + """ + Scenario: Define `before` and `after` blocks in configuration Given a file named "befores_in_configuration_spec.rb" with: """ruby From ab52c5ab50ec4b9dc4e14f9253cdaf7545685cb0 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Wed, 8 Apr 2020 16:07:07 +0100 Subject: [PATCH 14/18] Merge pull request #2718 from rspec/remove-klass-exec-in-favour-of-rspec-support-class-exec Use shared class_exec fallback from rspec-support --- lib/rspec/core/shared_example_group.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/rspec/core/shared_example_group.rb b/lib/rspec/core/shared_example_group.rb index b6ced2cc1f..3d9efce282 100644 --- a/lib/rspec/core/shared_example_group.rb +++ b/lib/rspec/core/shared_example_group.rb @@ -1,3 +1,5 @@ +RSpec::Support.require_rspec_support "with_keywords_when_needed" + module RSpec module Core # Represents some functionality that is shared with multiple example groups. @@ -33,7 +35,7 @@ def include_in(klass, inclusion_line, args, customization_block) klass.update_inherited_metadata(@metadata) unless @metadata.empty? SharedExampleGroupInclusionStackFrame.with_frame(@description, inclusion_line) do - klass.class_exec(*args, &@definition) + RSpec::Support::WithKeywordsWhenNeeded.class_exec(klass, *args, &@definition) klass.class_exec(&customization_block) if customization_block end end From c99129d059f27b644659469cbdc704040fec0e05 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Fri, 10 Apr 2020 21:39:25 +0100 Subject: [PATCH 15/18] Merge pull request #2719 from rspec/further-improve-kw-args-specs Tweak keyword argument specs for shared examples --- spec/rspec/core/shared_example_group_spec.rb | 53 ++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/spec/rspec/core/shared_example_group_spec.rb b/spec/rspec/core/shared_example_group_spec.rb index 6b897c395e..ca3c34691d 100644 --- a/spec/rspec/core/shared_example_group_spec.rb +++ b/spec/rspec/core/shared_example_group_spec.rb @@ -69,6 +69,59 @@ def find_implementation_block(registry, scope, name) expect(Kernel).to_not respond_to(shared_method_name) end + # These keyword specs cover all 4 of the keyword / keyword like syntax varients + # they should be warning free. + + if RSpec::Support::RubyFeatures.required_kw_args_supported? + it 'supports required keyword arguments' do + binding.eval(<<-CODE, __FILE__, __LINE__) + group.__send__ shared_method_name, "shared context expects keywords" do |foo:| + it "has an expected value" do + expect(foo).to eq("bar") + end + end + + group.__send__ shared_method_name, "shared context expects hash" do |a_hash| + it "has an expected value" do + expect(a_hash[:foo]).to eq("bar") + end + end + + group.it_behaves_like "shared context expects keywords", foo: "bar" + group.it_behaves_like "shared context expects keywords", { foo: "bar" } + + group.it_behaves_like "shared context expects hash", foo: "bar" + group.it_behaves_like "shared context expects hash", { foo: "bar" } + CODE + expect(group.run).to eq true + end + end + + if RSpec::Support::RubyFeatures.kw_args_supported? + it 'supports optional keyword arguments' do + binding.eval(<<-CODE, __FILE__, __LINE__) + group.__send__ shared_method_name, "shared context expects keywords" do |foo: nil| + it "has an expected value" do + expect(foo).to eq("bar") + end + end + + group.__send__ shared_method_name, "shared context expects hash" do |a_hash| + it "has an expected value" do + expect(a_hash[:foo]).to eq("bar") + end + end + + group.it_behaves_like "shared context expects keywords", foo: "bar" + group.it_behaves_like "shared context expects keywords", { foo: "bar" } + + group.it_behaves_like "shared context expects hash", foo: "bar" + group.it_behaves_like "shared context expects hash", { foo: "bar" } + CODE + expect(group.run).to eq true + end + end + it "displays a warning when adding an example group without a block", :unless => RUBY_VERSION == '1.8.7' do expect_warning_with_call_site(__FILE__, __LINE__ + 1) group.send(shared_method_name, 'name but no block') From 16f21bd17030542855c452f15bf11b700e520fa3 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Sat, 2 May 2020 18:24:51 +0100 Subject: [PATCH 16/18] Merge pull request #2723 from agis/gh-2721-world-reset Make World.reset also reset example group counts --- lib/rspec/core/world.rb | 3 ++- spec/integration/filtering_spec.rb | 43 ++++++++++++++++++++++++++++++ spec/rspec/core/world_spec.rb | 8 ++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/rspec/core/world.rb b/lib/rspec/core/world.rb index 1edec7f487..d766424f00 100644 --- a/lib/rspec/core/world.rb +++ b/lib/rspec/core/world.rb @@ -5,7 +5,7 @@ module Core # Internal container for global non-configuration data. class World # @private - attr_reader :example_groups, :filtered_examples + attr_reader :example_groups, :filtered_examples, :example_group_counts_by_spec_file # Used internally to determine what to do when a SIGINT is received. attr_accessor :wants_to_quit @@ -53,6 +53,7 @@ def reset example_groups.clear @sources_by_path.clear if defined?(@sources_by_path) @syntax_highlighter = nil + @example_group_counts_by_spec_file = Hash.new(0) end # @private diff --git a/spec/integration/filtering_spec.rb b/spec/integration/filtering_spec.rb index e8421f2d6b..781b4a96d1 100644 --- a/spec/integration/filtering_spec.rb +++ b/spec/integration/filtering_spec.rb @@ -66,6 +66,49 @@ def run_rerun_command_for_failing_spec end context "passing a line-number filter" do + it "works with different custom runners used in the same process" do + result_counter = Class.new do + RSpec::Core::Formatters.register(self, :example_passed) + + attr_accessor :passed_examples + + def initialize(*) + @passed_examples = 0 + end + + def example_passed(notification) + @passed_examples += 1 + end + end + + spec_file = "spec/filtering_custom_runner_spec.rb" + + write_file_formatted spec_file, " + RSpec.describe 'A group' do + example('ex 1') { } + example('ex 2') { } + end + " + + spec_file_path = expand_path(spec_file) + + formatter = result_counter.new + RSpec.configuration.add_formatter(formatter) + opts = RSpec::Core::ConfigurationOptions.new(["#{spec_file_path}[1:1]"]) + RSpec::Core::Runner.new(opts).run(StringIO.new, StringIO.new) + + expect(formatter.passed_examples).to eq 1 + + RSpec.clear_examples + + formatter = result_counter.new + RSpec.configuration.add_formatter(formatter) + opts = RSpec::Core::ConfigurationOptions.new(["#{spec_file_path}[1:2]"]) + RSpec::Core::Runner.new(opts).run(StringIO.new, StringIO.new) + + expect(formatter.passed_examples).to eq 1 + end + it "trumps exclusions, except for :if/:unless (which are absolute exclusions)" do write_file_formatted 'spec/a_spec.rb', " RSpec.configure do |c| diff --git a/spec/rspec/core/world_spec.rb b/spec/rspec/core/world_spec.rb index c8714633e4..7c0b52a3e4 100644 --- a/spec/rspec/core/world_spec.rb +++ b/spec/rspec/core/world_spec.rb @@ -36,6 +36,14 @@ module RSpec::Core RSpec.world.reset }.to change(RSpec::ExampleGroups, :constants).to([]) end + + it 'clears #example_group_counts_by_spec_file' do + RSpec.describe "group" + + expect { + RSpec.world.reset + }.to change { world.example_group_counts_by_spec_file }.to be_empty + end end describe "#example_groups" do From a1b6ee254b0c779b8a5a55c0823d390bd9759e35 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Sat, 2 May 2020 18:30:18 +0100 Subject: [PATCH 17/18] Changelog for #2723 --- Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.md b/Changelog.md index 4e467cd326..c24aa486a2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,8 @@ Bug Fixes: (Jon Rowe, #2703) * Correctly detect patterns when `rspec_opts` is an array in `RSpec::Core::RakeTask`. (Marc-André Lafortune, #2704) +* Make `RSpec.clear_examples` reset example counts for example groups. This fixes + an issue with re-running specs not matching ids. (Agis Anastasopoulos, #2723) ### 3.9.1 / 2019-12-28 [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.0...v3.9.1) From d89b6920da5aa7b6b9ba48dd3b1d2454a74bfdc7 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Sat, 2 May 2020 21:05:23 +0100 Subject: [PATCH 18/18] Version 3.9.2 --- Changelog.md | 4 ++-- lib/rspec/core/version.rb | 2 +- rspec-core.gemspec | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Changelog.md b/Changelog.md index c24aa486a2..0fe6a23334 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,5 @@ -### Development -[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.1...master) +### 3.9.2 / 2020-05-02 +[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.1...v3.9.2) Bug Fixes: diff --git a/lib/rspec/core/version.rb b/lib/rspec/core/version.rb index 593f6206f4..37d2e21eaf 100644 --- a/lib/rspec/core/version.rb +++ b/lib/rspec/core/version.rb @@ -3,7 +3,7 @@ module Core # Version information for RSpec Core. module Version # Current version of RSpec Core, in semantic versioning format. - STRING = '3.9.1' + STRING = '3.9.2' end end end diff --git a/rspec-core.gemspec b/rspec-core.gemspec index b69b049cf1..f6004a26e3 100644 --- a/rspec-core.gemspec +++ b/rspec-core.gemspec @@ -42,7 +42,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency "rspec-support", "= #{RSpec::Core::Version::STRING}" else # rspec-support must otherwise match our major/minor version - s.add_runtime_dependency "rspec-support", "~> #{RSpec::Core::Version::STRING.split('.')[0..1].concat(['1']).join('.')}" + s.add_runtime_dependency "rspec-support", "~> #{RSpec::Core::Version::STRING.split('.')[0..1].concat(['3']).join('.')}" end s.add_development_dependency "cucumber", "~> 1.3"