diff --git a/Changelog.md b/Changelog.md index 1e20275bb..dfe34ce06 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,10 +1,18 @@ ### 3.0.0.beta2 Development [full changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.0.beta1...v3.0.0.beta2) -Ehancements: +Enhancements: * Simplify the failure message of the `be` matcher when matching against: `true`, `false` and `nil`. (Sam Phippen) +* Update matcher protocol and custom matcher DSL to better align + with the newer `expect` syntax. If you want your matchers to + maintain compatibility with multiple versions of RSpec, you can + alias the new names to the old. (Myron Marston) + * `failure_message_for_should` => `failure_message` + * `failure_message_for_should_not` => `failure_message_when_negated` + * `match_for_should` => `match` + * `match_for_should_not` => `match_when_negated` Breaking Changes for 3.0.0: @@ -17,6 +25,12 @@ Bug Fixes: * Fix wrong matcher descriptions with falsey expected value (yujinakayama) +Deprecations: + +* Retain support for RSpec 2 matcher protocol (e.g. for matchers + in 3rd party extension gems like `shoulda`), but it will print + a deprecation warning. (Myron Marston) + ### 3.0.0.beta1 / 2013-11-07 [full changelog](http://github.com/rspec/rspec-expectations/compare/v2.99.0.beta1...v3.0.0.beta1) diff --git a/README.md b/README.md index 67074df63..98273337e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# RSpec Expectations [![Build Status](https://secure.travis-ci.org/rspec/rspec-expectations.png?branch=master)](http://travis-ci.org/rspec/rspec-expectations) [![Code Climate](https://codeclimate.com/github/rspec/rspec-expectations.png)](https://codeclimate.com/github/rspec/rspec-expectations) [![Coverage Status](https://coveralls.io/repos/rspec/rspec-expectations/badge.png?branch=master)](https://coveralls.io/r/rspec/rspec-expectations?branch=master) +# RSpec Expectations [![Build Status](https://secure.travis-ci.org/rspec/rspec-expectations.png?branch=master)](http://travis-ci.org/rspec/rspec-expectations) [![Code Climate](https://codeclimate.com/github/rspec/rspec-expectations.png)](https://codeclimate.com/github/rspec/rspec-expectations) RSpec::Expectations lets you express expected outcomes on an object in an example. diff --git a/features/README.md b/features/README.md index ee19128b6..aed501f5d 100644 --- a/features/README.md +++ b/features/README.md @@ -26,12 +26,12 @@ Note: You can also use `expect(..).to_not` instead of `expect(..).not_to`. A Matcher is any object that responds to the following methods: matches?(actual) - failure_message_for_should + failure_message These methods are also part of the matcher protocol, but are optional: does_not_match?(actual) - failure_message_for_should_not + failure_message_when_negated description RSpec ships with a number of built-in matchers and a DSL for writing custom diff --git a/features/custom_matchers/define_matcher.feature b/features/custom_matchers/define_matcher.feature index 6e2d6912d..d22739432 100644 --- a/features/custom_matchers/define_matcher.feature +++ b/features/custom_matchers/define_matcher.feature @@ -46,7 +46,7 @@ Feature: define matcher And the output should contain "expected 9 to be a multiple of 4" And the output should contain "expected 9 not to be a multiple of 3" - Scenario: overriding the failure_message_for_should + Scenario: overriding the failure_message Given a file named "matcher_with_failure_message_spec.rb" with: """ruby require 'rspec/expectations' @@ -55,7 +55,7 @@ Feature: define matcher match do |actual| actual % expected == 0 end - failure_message_for_should do |actual| + failure_message do |actual| "expected that #{actual} would be a multiple of #{expected}" end end @@ -70,7 +70,7 @@ Feature: define matcher And the stdout should contain "1 example, 1 failure" And the stdout should contain "expected that 9 would be a multiple of 4" - Scenario: overriding the failure_message_for_should_not + Scenario: overriding the failure_message_when_negated Given a file named "matcher_with_failure_for_message_spec.rb" with: """ruby require 'rspec/expectations' @@ -79,7 +79,7 @@ Feature: define matcher match do |actual| actual % expected == 0 end - failure_message_for_should_not do |actual| + failure_message_when_negated do |actual| "expected that #{actual} would not be a multiple of #{expected}" end end @@ -261,11 +261,11 @@ Feature: define matcher Given a file named "matcher_with_separate_should_not_logic_spec.rb" with: """ruby RSpec::Matchers.define :contain do |*expected| - match_for_should do |actual| + match do |actual| expected.all? { |e| actual.include?(e) } end - match_for_should_not do |actual| + match_when_negated do |actual| expected.none? { |e| actual.include?(e) } end end diff --git a/lib/rspec/expectations.rb b/lib/rspec/expectations.rb index a6b5c0e66..85516c8b6 100644 --- a/lib/rspec/expectations.rb +++ b/lib/rspec/expectations.rb @@ -11,31 +11,40 @@ require 'rspec/expectations/diff_presenter' module RSpec - # RSpec::Expectations adds two instance methods to every object: + # RSpec::Expectations provides a simple, readable API to express + # the expected outcomes in a code example. To express an expected + # outcome, wrap an object or block in `expect`, call `to` or `to_not` + # (aliased as `not_to`) and pass it a matcher object: # - # should(matcher=nil) - # should_not(matcher=nil) + # expect(order.total).to eq(Money.new(5.55, :USD)) + # expect(list).to include(user) + # expect(message).not_to match(/foo/) + # expect { do_something }.to raise_error # - # Both methods take an optional matcher object (See - # [RSpec::Matchers](../RSpec/Matchers)). When `should` is invoked with a - # matcher, it turns around and calls `matcher.matches?(self)`. For example, + # The last form (the block form) is needed to match against ruby constructs + # that are not objects, but can only be observed when executing a block + # of code. This includes raising errors, throwing symbols, yielding, + # and changing values. + # + # When `expect(...).to` is invoked with a matcher, it turns around + # and calls `matcher.matches?()`. For example, # in the expression: # - # order.total.should eq(Money.new(5.55, :USD)) + # expect(order.total).to eq(Money.new(5.55, :USD)) # - # the `should` method invokes the equivalent of `eq.matches?(order.total)`. If - # `matches?` returns true, the expectation is met and execution continues. If - # `false`, then the spec fails with the message returned by - # `eq.failure_message_for_should`. + # ...`eq(Money.new(5.55, :USD))` returns a matcher object, and it results + # in the equivalent of `eq.matches?(order.total)`. If `matches?` returns + # `true`, the expectation is met and execution continues. If `false`, then + # the spec fails with the message returned by `eq.failure_message`. # # Given the expression: # - # order.entries.should_not include(entry) + # expet(order.entries).not_to include(entry) # - # the `should_not` method invokes the equivalent of + # ...the `not_to` method (also available as `to_not`) invokes the equivalent of # `include.matches?(order.entries)`, but it interprets `false` as success, and # `true` as a failure, using the message generated by - # `eq.failure_message_for_should_not`. + # `eq.failure_message_when_negated`. # # rspec-expectations ships with a standard set of useful matchers, and writing # your own matchers is quite simple. diff --git a/lib/rspec/expectations/handler.rb b/lib/rspec/expectations/handler.rb index 27dc88d5f..82cae9fc3 100644 --- a/lib/rspec/expectations/handler.rb +++ b/lib/rspec/expectations/handler.rb @@ -1,6 +1,7 @@ module RSpec module Expectations + # @api private class ExpectationHandler def self.check_message(msg) unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call) @@ -11,24 +12,25 @@ def self.check_message(msg) ].join end end - end - class PositiveExpectationHandler < ExpectationHandler + # Returns an RSpec-3+ compatible matcher, wrapping a legacy one + # in an adapter if necessary. + # + # @api private + def self.modern_matcher_from(matcher) + LegacyMacherAdapter::RSpec2.wrap(matcher) || + LegacyMacherAdapter::RSpec1.wrap(matcher) || matcher + end - def self.handle_matcher(actual, matcher, message=nil, &block) + def self.handle_matcher(matcher, message, failure_message_method) check_message(message) - ::RSpec::Matchers.last_should = :should + matcher = modern_matcher_from(matcher) ::RSpec::Matchers.last_matcher = matcher - return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) if matcher.nil? - match = matcher.matches?(actual, &block) - return match if match + yield message = message.call if message.respond_to?(:call) - - message ||= matcher.respond_to?(:failure_message_for_should) ? - matcher.failure_message_for_should : - matcher.failure_message + message ||= matcher.__send__(failure_message_method) if matcher.respond_to?(:diffable?) && matcher.diffable? ::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual @@ -38,28 +40,112 @@ def self.handle_matcher(actual, matcher, message=nil, &block) end end + # @api private + class PositiveExpectationHandler < ExpectationHandler + def self.handle_matcher(actual, matcher, message=nil, &block) + super(matcher, message, :failure_message) do + ::RSpec::Matchers.last_should = :should + return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) if matcher.nil? + + match = matcher.matches?(actual, &block) + return match if match + end + end + end + + # @api private class NegativeExpectationHandler < ExpectationHandler def self.handle_matcher(actual, matcher, message=nil, &block) - check_message(message) - ::RSpec::Matchers.last_should = :should_not - ::RSpec::Matchers.last_matcher = matcher - return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) if matcher.nil? + super(matcher, message, :failure_message_when_negated) do + ::RSpec::Matchers.last_should = :should_not + return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) if matcher.nil? - match = matcher.respond_to?(:does_not_match?) ? - !matcher.does_not_match?(actual, &block) : - matcher.matches?(actual, &block) - return match unless match + match = if matcher.respond_to?(:does_not_match?) + !matcher.does_not_match?(actual, &block) + else + matcher.matches?(actual, &block) + end + return match unless match + end + end + end - message = message.call if message.respond_to?(:call) + # Wraps a matcher written against one of the legacy protocols in + # order to present the current protocol. + # + # @api private + class LegacyMacherAdapter < defined?(::BasicObject) ? ::BasicObject : ::Object + attr_reader :matcher - message ||= matcher.respond_to?(:failure_message_for_should_not) ? - matcher.failure_message_for_should_not : - matcher.negative_failure_message + def initialize(matcher) + @matcher = matcher - if matcher.respond_to?(:diffable?) && matcher.diffable? - ::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual - else - ::RSpec::Expectations.fail_with message + ::RSpec.warn_deprecation(<<-EOS.gsub(/^\s+\|/, '')) + |-------------------------------------------------------------------------- + |#{matcher.class.name || matcher.inspect} implements a legacy RSpec matcher + |protocol. For the current protocol you should expose the failure messages + |via the `failure_message` and `failure_message_when_negated` methods. + |(Used from #{CallerFilter.first_non_rspec_line}) + |-------------------------------------------------------------------------- + EOS + end + + def method_missing(name, *args, &block) + @matcher.__send__(name, *args, &block) + end + + def respond_to?(name, *args) + super || @matcher.respond_to?(name, *args) + end + + def self.wrap(matcher) + new(matcher) if interface_matches?(matcher) + end + + # Starting in RSpec 1.2 (and continuing through all 2.x releases), + # the failure message protocol was: + # * `failure_message_for_should` + # * `failure_message_for_should_not` + # @api private + class RSpec2 < self + def failure_message + matcher.failure_message_for_should + end + + def failure_message_when_negated + matcher.failure_message_for_should_not + end + + def self.interface_matches?(matcher) + ( + !matcher.respond_to?(:failure_message) && + matcher.respond_to?(:failure_message_for_should) + ) || ( + !matcher.respond_to?(:failure_message_when_negated) && + matcher.respond_to?(:failure_message_for_should_not) + ) + end + end + + # Before RSpec 1.2, the failure message protocol was: + # * `failure_message` + # * `negative_failure_message` + # @api private + class RSpec1 < self + def failure_message + matcher.failure_message + end + + def failure_message_when_negated + matcher.negative_failure_message + end + + # Note: `failure_message` is part of the RSpec 3 protocol + # (paired with `failure_message_when_negated`), so we don't check + # for `failure_message` here. + def self.interface_matches?(matcher) + !matcher.respond_to?(:failure_message_when_negated) && + matcher.respond_to?(:negative_failure_message) end end end diff --git a/lib/rspec/matchers.rb b/lib/rspec/matchers.rb index bfa15272d..0ca41c487 100644 --- a/lib/rspec/matchers.rb +++ b/lib/rspec/matchers.rb @@ -6,7 +6,6 @@ require 'rspec/matchers/generated_descriptions' require 'rspec/matchers/method_missing' -require 'rspec/matchers/compatibility' require 'rspec/matchers/dsl' require 'rspec/matchers/test_unit_integration' @@ -15,12 +14,12 @@ module RSpec # expectations. A matcher is any object that responds to the following: # # matches?(actual) - # failure_message_for_should + # failure_message # # These methods are also part of the matcher protocol, but are optional: # # does_not_match?(actual) - # failure_message_for_should_not + # failure_message_when_negated # description # # ## Predicates @@ -98,11 +97,11 @@ module RSpec # player.in_zone?(zone) # end # - # failure_message_for_should do |player| + # failure_message do |player| # # generate and return the appropriate string. # end # - # failure_message_for_should_not do |player| + # failure_message_when_negated do |player| # # generate and return the appropriate string. # end # @@ -113,8 +112,8 @@ module RSpec # # Each of the message-generation methods has access to the block arguments # passed to the create method (in this case, zone). The - # failure message methods (failure_message_for_should and - # failure_message_for_should_not) are passed the actual value (the + # failure message methods (failure_message and + # failure_message_when_negated) are passed the actual value (the # receiver of expect(..) or expect(..).not_to). # # ### Custom Matcher from scratch @@ -131,11 +130,11 @@ module RSpec # @target.current_zone.eql?(Zone.new(@expected)) # end # - # def failure_message_for_should + # def failure_message # "expected #{@target.inspect} to be in Zone #{@expected}" # end # - # def failure_message_for_should_not + # def failure_message_when_negated # "expected #{@target.inspect} not to be in Zone #{@expected}" # end # end @@ -178,7 +177,8 @@ def self.is_a_matcher?(obj) return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher) return false unless obj.respond_to?(:matches?) - obj.respond_to?(:failure_message_for_should) || obj.respond_to?(:failure_message) + obj.respond_to?(:failure_message) || + obj.respond_to?(:failure_message_for_should) # support legacy matchers end # Passes if actual is truthy (anything but false or nil) @@ -276,8 +276,8 @@ def be_within(delta) # but not both. # # When passing a block, it must use the { ... } format, not - # do/end, as { ... } binds to the +change+ method, whereas do/end - # would errantly bind to the +expect(..)+ or +expect(..).not_to+ method. + # do/end, as { ... } binds to the `change` method, whereas do/end + # would errantly bind to the `expect(..).to` or `expect(...).not_to` method. # # @example # @@ -379,7 +379,7 @@ def eq(expected) BuiltIn::Eq.new(expected) end - # Passes if +actual.eql?(expected)+ + # Passes if `actual.eql?(expected)` # # See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more # information about equality in Ruby. diff --git a/lib/rspec/matchers/built_in/base_matcher.rb b/lib/rspec/matchers/built_in/base_matcher.rb index 89fa31686..d696e3c34 100644 --- a/lib/rspec/matchers/built_in/base_matcher.rb +++ b/lib/rspec/matchers/built_in/base_matcher.rb @@ -37,12 +37,12 @@ def match_unless_raises(*exceptions) end end - def failure_message_for_should + def failure_message assert_ivars :@actual "expected #{@actual.inspect} to #{name_to_sentence}#{expected_to_sentence}" end - def failure_message_for_should_not + def failure_message_when_negated assert_ivars :@actual "expected #{@actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}" end diff --git a/lib/rspec/matchers/built_in/be.rb b/lib/rspec/matchers/built_in/be.rb index c2b0d87fa..97dc5d47a 100644 --- a/lib/rspec/matchers/built_in/be.rb +++ b/lib/rspec/matchers/built_in/be.rb @@ -8,11 +8,11 @@ def match(_, actual) !!actual end - def failure_message_for_should + def failure_message "expected: truthy value\n got: #{actual.inspect}" end - def failure_message_for_should_not + def failure_message_when_negated "expected: falsey value\n got: #{actual.inspect}" end end @@ -22,11 +22,11 @@ def match(_, actual) !actual end - def failure_message_for_should + def failure_message "expected: falsey value\n got: #{actual.inspect}" end - def failure_message_for_should_not + def failure_message_when_negated "expected: truthy value\n got: #{actual.inspect}" end end @@ -36,11 +36,11 @@ def match(_, actual) actual.nil? end - def failure_message_for_should + def failure_message "expected: nil\n got: #{actual.inspect}" end - def failure_message_for_should_not + def failure_message_when_negated "expected: not nil\n got: nil" end end @@ -80,11 +80,11 @@ def match(_, actual) !!actual end - def failure_message_for_should + def failure_message "expected #{@actual.inspect} to evaluate to true" end - def failure_message_for_should_not + def failure_message_when_negated "expected #{@actual.inspect} to evaluate to false" end @@ -106,11 +106,11 @@ def matches?(actual) @actual.__send__ @operator, @expected end - def failure_message_for_should + def failure_message "expected: #{@operator} #{@expected.inspect}\n got: #{@operator.to_s.gsub(/./, ' ')} #{@actual.inspect}" end - def failure_message_for_should_not + def failure_message_when_negated message = <<-MESSAGE `#{negative_expectation_expression}` not only FAILED, it is a bit confusing. @@ -161,11 +161,11 @@ def matches?(actual) alias === matches? - def failure_message_for_should + def failure_message "expected #{predicate}#{args_to_s} to return true, got #{@result.inspect}" end - def failure_message_for_should_not + def failure_message_when_negated "expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}" end diff --git a/lib/rspec/matchers/built_in/be_within.rb b/lib/rspec/matchers/built_in/be_within.rb index c46c54ab7..7ac8596ed 100644 --- a/lib/rspec/matchers/built_in/be_within.rb +++ b/lib/rspec/matchers/built_in/be_within.rb @@ -28,11 +28,11 @@ def percent_of(expected) self end - def failure_message_for_should + def failure_message "expected #{@actual} to #{description}" end - def failure_message_for_should_not + def failure_message_when_negated "expected #{@actual} not to #{description}" end diff --git a/lib/rspec/matchers/built_in/change.rb b/lib/rspec/matchers/built_in/change.rb index 1acd86d2d..40725ccea 100644 --- a/lib/rspec/matchers/built_in/change.rb +++ b/lib/rspec/matchers/built_in/change.rb @@ -35,7 +35,7 @@ def evaluate_value_proc end end - def failure_message_for_should + def failure_message if @eval_before && !expected_matches_actual?(@expected_before, @actual_before) "#{message} should have initially been #{@expected_before.inspect}, but was #{@actual_before.inspect}" elsif @eval_after && !expected_matches_actual?(@expected_after, @actual_after) @@ -55,7 +55,7 @@ def actual_delta @actual_after - @actual_before end - def failure_message_for_should_not + def failure_message_when_negated "#{message} should not have changed, but did change from #{@actual_before.inspect} to #{@actual_after.inspect}" end diff --git a/lib/rspec/matchers/built_in/eq.rb b/lib/rspec/matchers/built_in/eq.rb index c6f6c3e7a..c29b50249 100644 --- a/lib/rspec/matchers/built_in/eq.rb +++ b/lib/rspec/matchers/built_in/eq.rb @@ -6,11 +6,11 @@ def match(expected, actual) actual == expected end - def failure_message_for_should + def failure_message "\nexpected: #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n" end - def failure_message_for_should_not + def failure_message_when_negated "\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n" end diff --git a/lib/rspec/matchers/built_in/eql.rb b/lib/rspec/matchers/built_in/eql.rb index fb4424aaf..67817afef 100644 --- a/lib/rspec/matchers/built_in/eql.rb +++ b/lib/rspec/matchers/built_in/eql.rb @@ -6,11 +6,11 @@ def match(expected, actual) actual.eql? expected end - def failure_message_for_should + def failure_message "\nexpected: #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n" end - def failure_message_for_should_not + def failure_message_when_negated "\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n" end diff --git a/lib/rspec/matchers/built_in/equal.rb b/lib/rspec/matchers/built_in/equal.rb index 396926e3d..9e9bf855c 100644 --- a/lib/rspec/matchers/built_in/equal.rb +++ b/lib/rspec/matchers/built_in/equal.rb @@ -6,7 +6,7 @@ def match(expected, actual) actual.equal? expected end - def failure_message_for_should + def failure_message if expected_is_a_literal_singleton? simple_failure_message else @@ -14,7 +14,7 @@ def failure_message_for_should end end - def failure_message_for_should_not + def failure_message_when_negated return <<-MESSAGE expected not #{inspect_object(actual)} diff --git a/lib/rspec/matchers/built_in/has.rb b/lib/rspec/matchers/built_in/has.rb index befe0970a..1c51a9a71 100644 --- a/lib/rspec/matchers/built_in/has.rb +++ b/lib/rspec/matchers/built_in/has.rb @@ -11,11 +11,11 @@ def matches?(actual) end alias == matches? - def failure_message_for_should + def failure_message "expected ##{predicate(@expected)}#{failure_message_args_description} to return true, got false" end - def failure_message_for_should_not + def failure_message_when_negated "expected ##{predicate(@expected)}#{failure_message_args_description} to return false, got true" end diff --git a/lib/rspec/matchers/built_in/match_array.rb b/lib/rspec/matchers/built_in/match_array.rb index 78b6b9dc2..38ada3bbf 100644 --- a/lib/rspec/matchers/built_in/match_array.rb +++ b/lib/rspec/matchers/built_in/match_array.rb @@ -9,7 +9,7 @@ def match(expected, actual) @extra_items.empty? & @missing_items.empty? end - def failure_message_for_should + def failure_message if actual.respond_to? :to_ary message = "expected collection contained: #{safe_sort(expected).inspect}\n" message += "actual collection contained: #{safe_sort(actual).inspect}\n" @@ -22,7 +22,7 @@ def failure_message_for_should message end - def failure_message_for_should_not + def failure_message_when_negated "Matcher does not support should_not" end diff --git a/lib/rspec/matchers/built_in/raise_error.rb b/lib/rspec/matchers/built_in/raise_error.rb index 782a3e4bb..bf094ddf5 100644 --- a/lib/rspec/matchers/built_in/raise_error.rb +++ b/lib/rspec/matchers/built_in/raise_error.rb @@ -87,11 +87,11 @@ def verify_message end end - def failure_message_for_should + def failure_message @eval_block ? @actual_error.message : "expected #{expected_error}#{given_error}" end - def failure_message_for_should_not + def failure_message_when_negated "expected no #{expected_error}#{given_error}" end diff --git a/lib/rspec/matchers/built_in/respond_to.rb b/lib/rspec/matchers/built_in/respond_to.rb index 53c5d2f2e..98430b36c 100644 --- a/lib/rspec/matchers/built_in/respond_to.rb +++ b/lib/rspec/matchers/built_in/respond_to.rb @@ -16,12 +16,12 @@ def does_not_match?(actual) find_failing_method_names(actual, :select).empty? end - def failure_message_for_should + def failure_message "expected #{@actual.inspect} to respond to #{@failing_method_names.collect {|name| name.inspect }.join(', ')}#{with_arity}" end - def failure_message_for_should_not - failure_message_for_should.sub(/to respond to/, 'not to respond to') + def failure_message_when_negated + failure_message.sub(/to respond to/, 'not to respond to') end def description diff --git a/lib/rspec/matchers/built_in/satisfy.rb b/lib/rspec/matchers/built_in/satisfy.rb index 9aa738817..45fea63da 100644 --- a/lib/rspec/matchers/built_in/satisfy.rb +++ b/lib/rspec/matchers/built_in/satisfy.rb @@ -13,11 +13,11 @@ def matches?(actual, &block) end alias == matches? - def failure_message_for_should + def failure_message "expected #{@actual} to satisfy block" end - def failure_message_for_should_not + def failure_message_when_negated "expected #{@actual} not to satisfy block" end diff --git a/lib/rspec/matchers/built_in/start_and_end_with.rb b/lib/rspec/matchers/built_in/start_and_end_with.rb index 558404c9d..86f72f6a1 100644 --- a/lib/rspec/matchers/built_in/start_and_end_with.rb +++ b/lib/rspec/matchers/built_in/start_and_end_with.rb @@ -15,11 +15,11 @@ def matches?(actual) end end - def failure_message_for_should + def failure_message "expected #{@actual.inspect} to #{self.class.name.split('::').last.sub(/With/,'').downcase} with #{@expected.inspect}" end - def failure_message_for_should_not + def failure_message_when_negated "expected #{@actual.inspect} not to #{self.class.name.split('::').last.sub(/With/,'').downcase} with #{@expected.inspect}" end end diff --git a/lib/rspec/matchers/built_in/throw_symbol.rb b/lib/rspec/matchers/built_in/throw_symbol.rb index 6108c3ed4..7808c810a 100644 --- a/lib/rspec/matchers/built_in/throw_symbol.rb +++ b/lib/rspec/matchers/built_in/throw_symbol.rb @@ -53,11 +53,11 @@ def matches?(given_proc) end alias == matches? - def failure_message_for_should + def failure_message "expected #{expected} to be thrown, got #{caught}" end - def failure_message_for_should_not + def failure_message_when_negated "expected #{expected('no Symbol')}#{' not' if @expected_symbol} to be thrown, got #{caught}" end diff --git a/lib/rspec/matchers/built_in/yield.rb b/lib/rspec/matchers/built_in/yield.rb index 8ce4182d4..370f07aa9 100644 --- a/lib/rspec/matchers/built_in/yield.rb +++ b/lib/rspec/matchers/built_in/yield.rb @@ -110,13 +110,13 @@ def times self end - def failure_message_for_should + def failure_message 'expected given block to yield control'.tap do |failure_message| failure_message << relativity_failure_message end end - def failure_message_for_should_not + def failure_message_when_negated 'expected given block not to yield control'.tap do |failure_message| failure_message << relativity_failure_message end @@ -162,11 +162,11 @@ def matches?(block) @probe.yielded_once?(:yield_with_no_args) && @probe.single_yield_args.empty? end - def failure_message_for_should + def failure_message "expected given block to yield with no arguments, but #{failure_reason}" end - def failure_message_for_should_not + def failure_message_when_negated "expected given block not to yield with no arguments, but did" end @@ -193,11 +193,11 @@ def matches?(block) end alias == matches? - def failure_message_for_should + def failure_message "expected given block to yield with arguments, but #{positive_failure_reason}" end - def failure_message_for_should_not + def failure_message_when_negated "expected given block not to yield with arguments, but #{negative_failure_reason}" end @@ -263,13 +263,13 @@ def matches?(block) end alias == matches? - def failure_message_for_should + def failure_message "expected given block to yield successively with arguments, but yielded with unexpected arguments" + "\nexpected: #{@expected.inspect}" + "\n got: #{@actual.inspect} (compared using === and ==)" end - def failure_message_for_should_not + def failure_message_when_negated "expected given block not to yield successively with arguments, but yielded with expected arguments" + "\nexpected not: #{@expected.inspect}" + "\n got: #{@actual.inspect} (compared using === and ==)" diff --git a/lib/rspec/matchers/compatibility.rb b/lib/rspec/matchers/compatibility.rb deleted file mode 100644 index 6857243e9..000000000 --- a/lib/rspec/matchers/compatibility.rb +++ /dev/null @@ -1,14 +0,0 @@ -RSpec::Matchers.constants.each do |c| - if Class === (klass = RSpec::Matchers.const_get(c)) - if klass.public_instance_methods.any? {|m| ['failure_message_for_should',:failure_message_for_should].include?(m)} - klass.class_exec do - alias_method :failure_message, :failure_message_for_should - end - end - if klass.public_instance_methods.any? {|m| ['failure_message_for_should_not',:failure_message_for_should_not].include?(m)} - klass.class_exec do - alias_method :negative_failure_message, :failure_message_for_should_not - end - end - end -end diff --git a/lib/rspec/matchers/matcher.rb b/lib/rspec/matchers/matcher.rb index 4e319a64f..a181cc578 100644 --- a/lib/rspec/matchers/matcher.rb +++ b/lib/rspec/matchers/matcher.rb @@ -12,9 +12,6 @@ module Macros # passes. Similarly, when the matcher is passed to `expect(...).not_to` and the # block returns `false`, then the expectation passes. # - # Use `match_for_should` when used in conjunction with - # `match_for_should_not`. - # # @example # # RSpec::Matchers.define :be_even do @@ -39,7 +36,6 @@ def match(&match_block) end end end - alias match_for_should match # Use this to define the block for a negative expectation (`expect(...).not_to`) # when the positive and negative forms require different handling. This @@ -47,7 +43,7 @@ def match(&match_block) # asynchronous processes that require different timeouts. # # @yield [Object] actual the actual value (i.e. the value wrapped by `expect`) - def match_for_should_not(&match_block) + def match_when_negated(&match_block) define_user_override(:does_not_match?, match_block) do |actual| @actual = actual super(*actual_arg_for(match_block)) @@ -90,13 +86,13 @@ def match_unless_raises(expected_exception=Exception, &match_block) # RSpec::Matchers.define :have_strength do |expected| # match { your_match_logic } # - # failure_message_for_should do |actual| + # failure_message do |actual| # "Expected strength of #{expected}, but had #{actual.strength}" # end # end # # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`) - def failure_message_for_should(&definition) + def failure_message(&definition) define_user_override(__method__, definition) end @@ -109,13 +105,13 @@ def failure_message_for_should(&definition) # RSpec::Matchers.define :have_strength do |expected| # match { your_match_logic } # - # failure_message_for_should_not do |actual| + # failure_message_when_negated do |actual| # "Expected not to have strength of #{expected}, but did" # end # end # # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`) - def failure_message_for_should_not(&definition) + def failure_message_when_negated(&definition) define_user_override(__method__, definition) end @@ -192,6 +188,34 @@ def define_user_override(method_name, user_def, &our_def) our_def ||= lambda { super(*actual_arg_for(user_def)) } define_method(method_name, &our_def) end + + # Defines deprecated macro methods from RSpec 2 for backwards compatibility. + # @deprecated Use the methods from {Macros} instead. + module Deprecated + # @deprecated Use {Macros#match} instead. + def match_for_should(&definition) + RSpec.deprecate("`match_for_should`", :replacement => "`match`") + match(&definition) + end + + # @deprecated Use {Macros#match_when_negated} instead. + def match_for_should_not(&definition) + RSpec.deprecate("`match_for_should_not`", :replacement => "`match_when_negated`") + match_when_negated(&definition) + end + + # @deprecated Use {Macros#failure_message} instead. + def failure_message_for_should(&definition) + RSpec.deprecate("`failure_message_for_should`", :replacement => "`failure_message`") + failure_message(&definition) + end + + # @deprecated Use {Macros#failure_message_when_negated} instead. + def failure_message_for_should_not(&definition) + RSpec.deprecate("`failure_message_for_should_not`", :replacement => "`failure_message_when_negated`") + failure_message_when_negated(&definition) + end + end end # Defines default implementations of the matcher @@ -211,12 +235,12 @@ def description end # The default failure message for positive expectations. - def failure_message_for_should + def failure_message "expected #{actual.inspect} to #{name_to_sentence}#{expected_to_sentence}" end # The default failure message for negative expectations. - def failure_message_for_should_not + def failure_message_when_negated "expected #{actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}" end end @@ -237,6 +261,7 @@ class Matcher # Makes the macro methods available to an `RSpec::Matchers.define` block. extend Macros + extend Macros::Deprecated attr_reader :expected, :actual, :rescued_exception attr_accessor :matcher_execution_context diff --git a/rspec-expectations.gemspec b/rspec-expectations.gemspec index 4591bef16..a8f222406 100644 --- a/rspec-expectations.gemspec +++ b/rspec-expectations.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |s| s.email = "rspec@googlegroups.com" s.homepage = "http://github.com/rspec/rspec-expectations" s.summary = "rspec-expectations-#{RSpec::Expectations::Version::STRING}" - s.description = "rspec expectations (should[_not] and matchers)" + s.description = "rspec-expectations provides a simple, readable API to express expected outcomes of a code example." s.rubyforge_project = "rspec" diff --git a/spec/rspec/expectations/extensions/kernel_spec.rb b/spec/rspec/expectations/extensions/kernel_spec.rb index 2f8a3c6db..00dcb4bd4 100644 --- a/spec/rspec/expectations/extensions/kernel_spec.rb +++ b/spec/rspec/expectations/extensions/kernel_spec.rb @@ -5,7 +5,7 @@ @target = "target" @matcher = double("matcher") allow(@matcher).to receive(:matches?).and_return(true) - allow(@matcher).to receive(:failure_message_for_should) + allow(@matcher).to receive(:failure_message) end it "accepts and interacts with a matcher" do @@ -13,9 +13,9 @@ expect(@target).to @matcher end - it "asks for a failure_message_for_should when matches? returns false" do + it "asks for a failure_message when matches? returns false" do expect(@matcher).to receive(:matches?).with(@target).and_return(false) - expect(@matcher).to receive(:failure_message_for_should).and_return("the failure message") + expect(@matcher).to receive(:failure_message).and_return("the failure message") expect { expect(@target).to @matcher }.to fail_with("the failure message") @@ -52,14 +52,14 @@ def method_missing(name, *args) it "accepts and interacts with a matcher" do expect(@matcher).to receive(:matches?).with(@target).and_return(false) - allow(@matcher).to receive(:failure_message_for_should_not) + allow(@matcher).to receive(:failure_message_when_negated) expect(@target).not_to @matcher end - it "asks for a failure_message_for_should_not when matches? returns true" do + it "asks for a failure_message_when_negated when matches? returns true" do expect(@matcher).to receive(:matches?).with(@target).and_return(true) - expect(@matcher).to receive(:failure_message_for_should_not).and_return("the failure message for should not") + expect(@matcher).to receive(:failure_message_when_negated).and_return("the failure message for should not") expect { expect(@target).not_to @matcher }.to fail_with("the failure message for should not") diff --git a/spec/rspec/expectations/handler_spec.rb b/spec/rspec/expectations/handler_spec.rb index e46819623..af81e4f87 100644 --- a/spec/rspec/expectations/handler_spec.rb +++ b/spec/rspec/expectations/handler_spec.rb @@ -25,13 +25,13 @@ def failure_message "expected #{@expected}, got #{@target}" end - def negative_failure_message + def failure_message_when_negated "expected not #{@expected}, got #{@target}" end end class PositiveOnlyMatcher < ArbitraryMatcher - undef negative_failure_message rescue nil + undef failure_message_when_negated rescue nil end def arbitrary_matcher(*args, &block) @@ -62,8 +62,8 @@ module Expectations expect(RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher)).to eq :this_value end - it "calls failure_message_for_should if the matcher implements it" do - matcher = double("matcher", :failure_message_for_should => "message", :matches? => false) + it "calls failure_message if the matcher implements it" do + matcher = double("matcher", :failure_message => "message", :matches? => false) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("message") @@ -74,7 +74,7 @@ module Expectations it "calls fail if matcher.diffable?" do matcher = double("matcher", :diffable? => true, - :failure_message_for_should => "message", + :failure_message => "message", :matches? => false, :expected => 1, :actual => 2 @@ -86,7 +86,7 @@ module Expectations RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher) end - it "calls failure_message if the matcher does not implement failure_message_for_should" do + it "calls failure_message if the matcher does not implement failure_message" do matcher = double("matcher", :failure_message => "message", :matches? => false) actual = Object.new @@ -97,7 +97,7 @@ module Expectations end it "uses the custom failure message when one is provided" do - matcher = double("matcher", :failure_message_for_should => "message", :matches? => false) + matcher = double("matcher", :failure_message => "message", :matches? => false) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("custom") @@ -106,7 +106,7 @@ module Expectations end it "uses the custom failure message when one is provided as a callable object" do - matcher = double("matcher", :failure_message_for_should => "message", :matches? => false) + matcher = double("matcher", :failure_message => "message", :matches? => false) actual = Object.new failure_message = double("failure message", :call => "custom") @@ -121,7 +121,7 @@ module Expectations describe NegativeExpectationHandler do describe "#handle_matcher" do it "asks the matcher if it doesn't match when the matcher responds to #does_not_match?" do - matcher = double("matcher", :does_not_match? => true, :negative_failure_message => nil) + matcher = double("matcher", :does_not_match? => true, :failure_message_when_negated => nil) actual = Object.new expect(matcher).to receive(:does_not_match?).with(actual).and_return(true) RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher) @@ -130,7 +130,7 @@ module Expectations it "asks the matcher if it matches when the matcher doesn't respond to #does_not_match?" do matcher = double("matcher") actual = Object.new - allow(matcher).to receive(:negative_failure_message) + allow(matcher).to receive(:failure_message_when_negated) expect(matcher).to receive(:matches?).with(actual).and_return(false) RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher) end @@ -139,36 +139,14 @@ module Expectations matcher = double("matcher") actual = Object.new expect(matcher).to receive(:matches?).with(actual).and_return(false) - allow(matcher).to receive(:negative_failure_message).and_return("ignore") + allow(matcher).to receive(:failure_message_when_negated).and_return("ignore") expect(RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher)).to be_falsey end - - it "calls failure_message_for_should_not if the matcher implements it" do - matcher = double("matcher", :failure_message_for_should_not => "message", :matches? => true) - actual = Object.new - - expect(::RSpec::Expectations).to receive(:fail_with).with("message") - - RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher) - - end - - it "calls negative_failure_message if the matcher does not implement failure_message_for_should_not" do - matcher = double("matcher", :negative_failure_message => "message", :matches? => true) - actual = Object.new - - expect(::RSpec::Expectations).to receive(:fail_with).with("message") - - RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher) - - end - - it "calls fail if matcher.diffable?" do matcher = double("matcher", :diffable? => true, - :failure_message_for_should_not => "message", + :failure_message_when_negated => "message", :matches? => true, :expected => 1, :actual => 2 @@ -181,7 +159,7 @@ module Expectations end it "uses the custom failure message when one is provided" do - matcher = double("matcher", :failure_message_for_should_not => "message", :matches? => true) + matcher = double("matcher", :failure_message_when_negated => "message", :matches? => true) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("custom") @@ -190,7 +168,7 @@ module Expectations end it "uses the custom failure message when one is provided as a callable object" do - matcher = double("matcher", :failure_message_for_should_not => "message", :matches? => true) + matcher = double("matcher", :failure_message_when_negated => "message", :matches? => true) actual = Object.new failure_message = double("failure message", :call => "custom") diff --git a/spec/rspec/matchers/base_matcher_spec.rb b/spec/rspec/matchers/base_matcher_spec.rb index 2c52b6c65..133846567 100644 --- a/spec/rspec/matchers/base_matcher_spec.rb +++ b/spec/rspec/matchers/base_matcher_spec.rb @@ -39,7 +39,7 @@ module RSpec::Matchers::BuiltIn end - describe "#failure_message_for_should" do + describe "#failure_message" do context "when the parameter to .new is omitted" do it "describes what was expected" do matcher_class = Class.new(BaseMatcher) do @@ -55,7 +55,7 @@ def match(expected, actual) matcher = matcher_class.new matcher.name = "be something" matcher.matches?("foo") - expect(matcher.failure_message_for_should).to eq('expected "foo" to be something') + expect(matcher.failure_message).to eq('expected "foo" to be something') end end end diff --git a/spec/rspec/matchers/description_generation_spec.rb b/spec/rspec/matchers/description_generation_spec.rb index 0a4d09db0..e63af761e 100644 --- a/spec/rspec/matchers/description_generation_spec.rb +++ b/spec/rspec/matchers/description_generation_spec.rb @@ -106,7 +106,7 @@ def object.has_taste_for?(*args); true; end it "expect(...).to include(x) when x responds to description and is a matcher" do matcher = double(:description => "description", :matches? => true, - :failure_message_for_should => "") + :failure_message => "") expect([matcher]).to include(matcher) expect(RSpec::Matchers.generated_description).to eq "should include description" end diff --git a/spec/rspec/matchers/eq_spec.rb b/spec/rspec/matchers/eq_spec.rb index 783494876..ff19e666d 100644 --- a/spec/rspec/matchers/eq_spec.rb +++ b/spec/rspec/matchers/eq_spec.rb @@ -40,13 +40,13 @@ module Matchers it "provides message, expected and actual on #failure_message" do matcher = eq("1") matcher.matches?(1) - expect(matcher.failure_message_for_should).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using ==)\n" + expect(matcher.failure_message).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using ==)\n" end it "provides message, expected and actual on #negative_failure_message" do matcher = eq(1) matcher.matches?(1) - expect(matcher.failure_message_for_should_not).to eq "\nexpected: value != 1\n got: 1\n\n(compared using ==)\n" + expect(matcher.failure_message_when_negated).to eq "\nexpected: value != 1\n got: 1\n\n(compared using ==)\n" end it 'fails properly when the actual is an array of multiline strings' do diff --git a/spec/rspec/matchers/eql_spec.rb b/spec/rspec/matchers/eql_spec.rb index 156effe90..187fa56b9 100644 --- a/spec/rspec/matchers/eql_spec.rb +++ b/spec/rspec/matchers/eql_spec.rb @@ -28,13 +28,13 @@ module Matchers it "provides message, expected and actual on #failure_message" do matcher = eql("1") matcher.matches?(1) - expect(matcher.failure_message_for_should).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using eql?)\n" + expect(matcher.failure_message).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using eql?)\n" end it "provides message, expected and actual on #negative_failure_message" do matcher = eql(1) matcher.matches?(1) - expect(matcher.failure_message_for_should_not).to eq "\nexpected: value != 1\n got: 1\n\n(compared using eql?)\n" + expect(matcher.failure_message_when_negated).to eq "\nexpected: value != 1\n got: 1\n\n(compared using eql?)\n" end end end diff --git a/spec/rspec/matchers/equal_spec.rb b/spec/rspec/matchers/equal_spec.rb index 9bad77733..1daeb8155 100644 --- a/spec/rspec/matchers/equal_spec.rb +++ b/spec/rspec/matchers/equal_spec.rb @@ -111,7 +111,7 @@ def string.equal?(other) expected = actual = "1" matcher = equal(expected) matcher.matches?(actual) - expect(matcher.failure_message_for_should_not).to eq <<-MESSAGE + expect(matcher.failure_message_when_negated).to eq <<-MESSAGE expected not #{inspect_object(expected)} got #{inspect_object(actual)} diff --git a/spec/rspec/matchers/include_spec.rb b/spec/rspec/matchers/include_spec.rb index a3c9ab4d9..8f9c61e16 100644 --- a/spec/rspec/matchers/include_spec.rb +++ b/spec/rspec/matchers/include_spec.rb @@ -458,7 +458,7 @@ def matches?(url) }.to fail_matching("expected [#{domain.new("rspec.info").inspect}] to include") end - it 'works with an old-style matcher that implements failure_message rather than failure_message_for_should' do + it 'works with an old-style matcher that implements failure_message rather than failure_message' do a_multiple_of = Class.new do def initialize(expected) @expected = expected diff --git a/spec/rspec/matchers/legacy_spec.rb b/spec/rspec/matchers/legacy_spec.rb new file mode 100644 index 000000000..733c29aa4 --- /dev/null +++ b/spec/rspec/matchers/legacy_spec.rb @@ -0,0 +1,94 @@ +require 'spec_helper' + +module RSpec + module Matchers + describe "Legacy matchers" do + shared_examples_for "a matcher written against a legacy protocol" do |matcher_class| + matcher = matcher_class.new + before { allow_deprecation } + + backwards_compat_matcher = Class.new(matcher_class) do + def failure_message; "failure when positive"; end + def failure_message_when_negated; "failure when negative"; end + end.new + + it 'is still considered to be a matcher' do + expect(Matchers.is_a_matcher?(matcher)).to be true + end + + context 'when matched positively' do + it 'returns the positive expectation failure message' do + expect { + expect(false).to matcher + }.to fail_with("failure when positive") + end + + it 'warns about the deprecated protocol' do + expect_warn_deprecation_with_call_site(__FILE__, __LINE__ + 1, /legacy\s+RSpec\s+matcher/) + expect(true).to matcher + end + + it 'does not warn when it also defines the current methods (i.e. to be compatible on multiple RSpec versions)' do + expect_no_deprecations + + expect { + expect(false).to backwards_compat_matcher + }.to fail_with("failure when positive") + end + end + + context 'when matched negatively' do + it 'returns the negative expectation failure message' do + expect { + expect(true).not_to matcher + }.to fail_with("failure when negative") + end + + it 'warns about the deprecated protocol' do + expect_warn_deprecation_with_call_site(__FILE__, __LINE__ + 1, /legacy\s+RSpec\s+matcher/) + expect(false).not_to matcher + end + + it 'does not warn when it also defines the current methods (i.e. to be compatible on multiple RSpec versions)' do + expect_no_deprecations + + expect { + expect(true).not_to backwards_compat_matcher + }.to fail_with("failure when negative") + end + + it 'calls `does_not_match?` if it is defined on the matcher' do + called = false + with_does_not_match = Class.new(matcher_class) do + define_method(:does_not_match?) { |actual| called = true; !actual } + end.new + + expect(false).not_to with_does_not_match + expect(called).to be true + end + end + end + + context "written using the RSpec 2.x `failure_message_for_should` and `failure_message_for_should_not` protocol" do + matcher_class = Class.new do + def matches?(actual); actual; end + def failure_message_for_should; "failure when positive"; end + def failure_message_for_should_not; "failure when negative"; end + end + + it_behaves_like "a matcher written against a legacy protocol", matcher_class + end + + context "written using the older `failure_message` and `negative_failure_message` protocol" do + matcher_class = Class.new do + def matches?(actual); actual; end + def failure_message; "failure when positive"; end + def negative_failure_message; "failure when negative"; end + end + + it_behaves_like "a matcher written against a legacy protocol", matcher_class + end + end + end +end + diff --git a/spec/rspec/matchers/match_spec.rb b/spec/rspec/matchers/match_spec.rb index f314b87b8..1f002ad95 100644 --- a/spec/rspec/matchers/match_spec.rb +++ b/spec/rspec/matchers/match_spec.rb @@ -28,7 +28,7 @@ it "provides message, expected and actual on failure" do matcher = match(/rings/) matcher.matches?("string") - expect(matcher.failure_message_for_should).to eq "expected \"string\" to match /rings/" + expect(matcher.failure_message).to eq "expected \"string\" to match /rings/" end it "provides a diff on failure" do @@ -69,6 +69,6 @@ it "provides message, expected and actual on failure" do matcher = match(/tri/) matcher.matches?("string") - expect(matcher.failure_message_for_should_not).to eq "expected \"string\" not to match /tri/" + expect(matcher.failure_message_when_negated).to eq "expected \"string\" not to match /tri/" end end diff --git a/spec/rspec/matchers/matcher_spec.rb b/spec/rspec/matchers/matcher_spec.rb index d5a335f0c..121cbb58f 100644 --- a/spec/rspec/matchers/matcher_spec.rb +++ b/spec/rspec/matchers/matcher_spec.rb @@ -44,6 +44,90 @@ def new_matcher(name, *expected, &block) expect(m2.matches?(2)).to be_truthy end + context 'using deprecated APIs' do + before { allow_deprecation } + + describe "failure_message_for_should" do + let(:matcher) do + new_matcher(:foo) do + match { false } + failure_message_for_should { "failed" } + end + end + line = __LINE__ - 3 + + it 'defines the failure message for a positive expectation' do + expect { + expect(nil).to matcher + }.to fail_with("failed") + end + + it 'prints a deprecation warning' do + expect_deprecation_with_call_site(__FILE__, line, /failure_message_for_should/) + matcher + end + end + + describe "failure_message_for_should_not" do + let(:matcher) do + new_matcher(:foo) do + match { true } + failure_message_for_should_not { "failed" } + end + end + line = __LINE__ - 3 + + it 'defines the failure message for a negative expectation' do + expect { + expect(nil).not_to matcher + }.to fail_with("failed") + end + + it 'prints a deprecation warning' do + expect_deprecation_with_call_site(__FILE__, line, /failure_message_for_should_not/) + matcher + end + end + + describe "match_for_should" do + let(:matcher) do + new_matcher(:foo) do + match_for_should { |arg| arg } + end + end + line = __LINE__ - 3 + + it 'defines the positive expectation match logic' do + expect(true).to matcher + expect { expect(false).to matcher }.to fail_with(/foo/) + end + + it 'prints a deprecation warning' do + expect_deprecation_with_call_site(__FILE__, line, /match_for_should/) + matcher + end + end + + describe "match_for_should_not" do + let(:matcher) do + new_matcher(:foo) do + match_for_should_not { |arg| !arg } + end + end + line = __LINE__ - 3 + + it 'defines the positive expectation match logic' do + expect(false).not_to matcher + expect { expect(true).not_to matcher }.to fail_with(/foo/) + end + + it 'prints a deprecation warning' do + expect_deprecation_with_call_site(__FILE__, line, /match_for_should_not/) + matcher + end + end + end + context "with an included module" do let(:matcher) do new_matcher(:be_a_greeting) do @@ -86,52 +170,52 @@ def new_matcher(name, *expected, &block) expect(matcher.description).to eq "be a multiple of 3" end - it "provides a default failure message for #should" do + it "provides a default positive expectation failure message" do matcher.matches?(8) - expect(matcher.failure_message_for_should).to eq "expected 8 to be a multiple of 3" + expect(matcher.failure_message).to eq "expected 8 to be a multiple of 3" end - it "provides a default failure message for #should_not" do + it "provides a default negative expectation failure message" do matcher.matches?(9) - expect(matcher.failure_message_for_should_not).to eq "expected 9 not to be a multiple of 3" + expect(matcher.failure_message_when_negated).to eq "expected 9 not to be a multiple of 3" end end - context "with separate match logic for should and should not" do + context "with separate match logic for positive and negative expectations" do let(:matcher) do new_matcher(:to_be_composed_of, 7, 11) do |a, b| - match_for_should do |actual| + match do |actual| actual == a * b end - match_for_should_not do |actual| + match_when_negated do |actual| actual == a + b end end end - it "invokes the match_for_should block for #matches?" do + it "invokes the match block for #matches?" do expect(matcher.matches?(77)).to be_truthy expect(matcher.matches?(18)).to be_falsey end - it "invokes the match_for_should_not block for #does_not_match?" do + it "invokes the match_when_negated block for #does_not_match?" do expect(matcher.does_not_match?(77)).to be_falsey expect(matcher.does_not_match?(18)).to be_truthy end - it "provides a default failure message for #should_not" do + it "provides a default failure message for negative expectations" do matcher.does_not_match?(77) - expect(matcher.failure_message_for_should_not).to eq "expected 77 not to to be composed of 7 and 11" + expect(matcher.failure_message_when_negated).to eq "expected 77 not to to be composed of 7 and 11" end - it 'can access helper methods from `match_for_should_not`' do + it 'can access helper methods from `match_when_negated`' do matcher = new_matcher(:be_foo) do def foo :foo end - match_for_should_not do |actual| + match_when_negated do |actual| actual != foo end end @@ -229,9 +313,9 @@ def foo expect(matcher.matches?(4)).to be_falsey end - it 'provides actual when `match_for_should_not` is used' do + it 'provides actual when `match_when_negated` is used' do matcher = new_matcher(:name, 'expected string') do - match_for_should_not {|actual|} + match_when_negated {|actual|} end matcher.does_not_match?('actual string') @@ -239,9 +323,9 @@ def foo expect(matcher.actual).to eq 'actual string' end - it 'allows an early `return` to be used from a `match_for_should_not` block' do + it 'allows an early `return` to be used from a `match_when_negated` block' do matcher = new_matcher(:with_return, 5) do |expected| - match_for_should_not { |actual| return true if expected != actual } + match_when_negated { |actual| return true if expected != actual } end expect(matcher.does_not_match?(5)).to be_falsey @@ -313,10 +397,10 @@ def foo description do |actual| "be the boolean #{boolean} (actual was #{actual})" end - failure_message_for_should do |actual| + failure_message do |actual| "expected #{actual} to be the boolean #{boolean}" end - failure_message_for_should_not do |actual| + failure_message_when_negated do |actual| "expected #{actual} not to be the boolean #{boolean}" end end @@ -335,14 +419,14 @@ def foo expect(matcher.description).to eq "be the boolean true (actual was true)" end - it "overrides the failure message for #should" do + it "overrides the failure message for positive expectations" do matcher.matches?(false) - expect(matcher.failure_message_for_should).to eq "expected false to be the boolean true" + expect(matcher.failure_message).to eq "expected false to be the boolean true" end - it "overrides the failure message for #should_not" do + it "overrides the failure message for negative expectations" do matcher.matches?(true) - expect(matcher.failure_message_for_should_not).to eq "expected true not to be the boolean true" + expect(matcher.failure_message_when_negated).to eq "expected true not to be the boolean true" end it 'can access helper methods from `description`' do @@ -354,22 +438,22 @@ def subdesc() "sub description" end expect(matcher.description).to eq("Desc (sub description)") end - it 'can access helper methods from `failure_message_for_should`' do + it 'can access helper methods from `failure_message`' do matcher = new_matcher(:positive_failure_message) do def helper() "helper" end - failure_message_for_should { helper } + failure_message { helper } end - expect(matcher.failure_message_for_should).to eq("helper") + expect(matcher.failure_message).to eq("helper") end - it 'can access helper methods from `failure_message_for_should_not`' do + it 'can access helper methods from `failure_message_when_negated`' do matcher = new_matcher(:negative_failure_message) do def helper() "helper" end - failure_message_for_should_not { helper } + failure_message_when_negated { helper } end - expect(matcher.failure_message_for_should_not).to eq("helper") + expect(matcher.failure_message_when_negated).to eq("helper") end it 'can exit early with a `return` from `description` just like in a method' do @@ -380,20 +464,20 @@ def helper() "helper" end expect(matcher.description).to eq("Desc") end - it 'can exit early with a `return` from `failure_message_for_should` just like in a method' do + it 'can exit early with a `return` from `failure_message` just like in a method' do matcher = new_matcher(:positive_failure_message) do - failure_message_for_should { return "msg" } + failure_message { return "msg" } end - expect(matcher.failure_message_for_should).to eq("msg") + expect(matcher.failure_message).to eq("msg") end - it 'can exit early with a `return` from `failure_message_for_should_not` just like in a method' do + it 'can exit early with a `return` from `failure_message_when_negated` just like in a method' do matcher = new_matcher(:negative_failure_message) do - failure_message_for_should_not { return "msg" } + failure_message_when_negated { return "msg" } end - expect(matcher.failure_message_for_should_not).to eq("msg") + expect(matcher.failure_message_when_negated).to eq("msg") end end @@ -515,8 +599,8 @@ def second_word RSpec::Matchers.define(:be_like_a) do |expected| match { |actual| actual == expected } description { "be like a #{expected}" } - failure_message_for_should { "expected to be like a #{expected}" } - failure_message_for_should_not { "expected not to be like a #{expected}" } + failure_message { "expected to be like a #{expected}" } + failure_message_when_negated { "expected not to be like a #{expected}" } end # Note: these bugs were only exposed when creating both instances @@ -532,13 +616,13 @@ def second_word end it 'allows them to use the expected value in the positive failure message' do - expect(moose.failure_message_for_should).to eq("expected to be like a moose") - expect(horse.failure_message_for_should).to eq("expected to be like a horse") + expect(moose.failure_message).to eq("expected to be like a moose") + expect(horse.failure_message).to eq("expected to be like a horse") end it 'allows them to use the expected value in the negative failure message' do - expect(moose.failure_message_for_should_not).to eq("expected not to be like a moose") - expect(horse.failure_message_for_should_not).to eq("expected not to be like a horse") + expect(moose.failure_message_when_negated).to eq("expected not to be like a moose") + expect(horse.failure_message_when_negated).to eq("expected not to be like a horse") end it 'allows them to match separately' do diff --git a/spec/rspec/matchers/throw_symbol_spec.rb b/spec/rspec/matchers/throw_symbol_spec.rb index b96be7242..cb0e558e3 100644 --- a/spec/rspec/matchers/throw_symbol_spec.rb +++ b/spec/rspec/matchers/throw_symbol_spec.rb @@ -21,11 +21,11 @@ module RSpec::Matchers::BuiltIn end it "provides a failure message" do @matcher.matches?(lambda{}) - expect(@matcher.failure_message_for_should).to eq "expected a Symbol to be thrown, got nothing" + expect(@matcher.failure_message).to eq "expected a Symbol to be thrown, got nothing" end it "provides a negative failure message" do @matcher.matches?(lambda{ throw :sym}) - expect(@matcher.failure_message_for_should_not).to eq "expected no Symbol to be thrown, got :sym" + expect(@matcher.failure_message_when_negated).to eq "expected no Symbol to be thrown, got :sym" end end @@ -46,15 +46,15 @@ module RSpec::Matchers::BuiltIn end it "provides a failure message when no Symbol is thrown" do @matcher.matches?(lambda{}) - expect(@matcher.failure_message_for_should).to eq "expected :sym to be thrown, got nothing" + expect(@matcher.failure_message).to eq "expected :sym to be thrown, got nothing" end it "provides a failure message when wrong Symbol is thrown" do @matcher.matches?(lambda{ throw :other_sym }) - expect(@matcher.failure_message_for_should).to eq "expected :sym to be thrown, got :other_sym" + expect(@matcher.failure_message).to eq "expected :sym to be thrown, got :other_sym" end it "provides a negative failure message" do @matcher.matches?(lambda{ throw :sym }) - expect(@matcher.failure_message_for_should_not).to eq "expected :sym not to be thrown, got :sym" + expect(@matcher.failure_message_when_negated).to eq "expected :sym not to be thrown, got :sym" end it "only matches NameErrors raised by uncaught throws" do expect { @@ -83,23 +83,23 @@ module RSpec::Matchers::BuiltIn end it "provides a failure message when no Symbol is thrown" do @matcher.matches?(lambda{}) - expect(@matcher.failure_message_for_should).to eq %q[expected :sym with "a" to be thrown, got nothing] + expect(@matcher.failure_message).to eq %q[expected :sym with "a" to be thrown, got nothing] end it "provides a failure message when wrong Symbol is thrown" do @matcher.matches?(lambda{ throw :other_sym }) - expect(@matcher.failure_message_for_should).to eq %q[expected :sym with "a" to be thrown, got :other_sym] + expect(@matcher.failure_message).to eq %q[expected :sym with "a" to be thrown, got :other_sym] end it "provides a failure message when wrong arg is thrown" do @matcher.matches?(lambda{ throw :sym, "b" }) - expect(@matcher.failure_message_for_should).to eq %q[expected :sym with "a" to be thrown, got :sym with "b"] + expect(@matcher.failure_message).to eq %q[expected :sym with "a" to be thrown, got :sym with "b"] end it "provides a failure message when no arg is thrown" do @matcher.matches?(lambda{ throw :sym }) - expect(@matcher.failure_message_for_should).to eq %q[expected :sym with "a" to be thrown, got :sym with no argument] + expect(@matcher.failure_message).to eq %q[expected :sym with "a" to be thrown, got :sym with no argument] end it "provides a negative failure message" do @matcher.matches?(lambda{ throw :sym }) - expect(@matcher.failure_message_for_should_not).to eq %q[expected :sym with "a" not to be thrown, got :sym with no argument] + expect(@matcher.failure_message_when_negated).to eq %q[expected :sym with "a" not to be thrown, got :sym with no argument] end it "only matches NameErrors raised by uncaught throws" do expect { diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 89f307e87..aa9247a20 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,18 +1,10 @@ -begin - old_verbose, $VERBOSE = $VERBOSE, false - require 'simplecov' +require 'rspec/support/spec' - SimpleCov.start do - add_filter "bundle" - minimum_coverage 97 - end -rescue LoadError -ensure - $VERBOSE = old_verbose -end unless ENV['NO_COVERAGE'] || RUBY_VERSION < '1.9.3' +RSpec::Support::Spec.setup_simplecov do + minimum_coverage 97 +end Dir['./spec/support/**/*'].each {|f| require f} -require 'rspec/support/spec' RSpec::configure do |config| config.color_enabled = true