1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
module RSpec
module Matchers
RSpec.describe AliasedMatcher do
RSpec::Matchers.define :my_base_matcher do
match { |actual| actual == foo }
def foo
13
end
def description
"my base matcher description"
end
end
RSpec::Matchers.alias_matcher :alias_of_my_base_matcher, :my_base_matcher
it_behaves_like "an RSpec value matcher", :valid_value => 13, :invalid_value => nil do
let(:matcher) { alias_of_my_base_matcher }
end
shared_examples "making a copy" do |copy_method|
context "when making a copy via `#{copy_method}`" do
it "uses a copy of the base matcher" do
base_matcher = include(3)
aliased = AliasedMatcher.new(base_matcher, Proc.new {})
copy = aliased.__send__(copy_method)
expect(copy).not_to equal(aliased)
expect(copy.base_matcher).not_to equal(base_matcher)
expect(copy.base_matcher).to be_a(RSpec::Matchers::BuiltIn::Include)
expect(copy.base_matcher.expected).to eq([3])
end
it "copies custom matchers properly so they can work even though they have singleton behavior" do
base_matcher = my_base_matcher
aliased = AliasedMatcher.new(base_matcher, Proc.new { |a| a })
copy = aliased.__send__(copy_method)
expect(copy).not_to equal(aliased)
expect(copy.base_matcher).not_to equal(base_matcher)
expect(13).to copy
expect { expect(15).to copy }.to fail_with(/expected 15/)
end
end
end
include_examples "making a copy", :dup
include_examples "making a copy", :clone
it 'can get a method object for delegated methods', :if => (RUBY_VERSION.to_f > 1.8) do
matcher = my_base_matcher
decorated = AliasedMatcher.new(matcher, Proc.new {})
expect(decorated.method(:foo).call).to eq(13)
end
it 'can get a method object for `description`' do
matcher = my_base_matcher
decorated = AliasedMatcher.new(matcher, Proc.new { "overridden description" })
expect(decorated.method(:description).call).to eq("overridden description")
end
RSpec::Matchers.alias_matcher :my_overridden_matcher, :my_base_matcher do |desc|
desc + " (overridden)"
end
it 'overrides the description with the provided block' do
matcher = my_overridden_matcher
expect(matcher.description).to eq("my base matcher description (overridden)")
end
RSpec::Matchers.alias_matcher :my_blockless_override, :my_base_matcher
it 'provides a default description override based on the old and new games' do
matcher = my_blockless_override
expect(matcher.description).to eq("my blockless override description")
end
it 'works properly with a chained method off a negated matcher' do
expect {}.to avoid_outputting.to_stdout
expect {
expect { $stdout.puts "a" }.to avoid_outputting.to_stdout
}.to fail
end
if RSpec::Support::RubyFeatures.kw_args_supported?
eval <<-'RUBY', nil, __FILE__, __LINE__ + 1
class MyKeywordMatcher
def initialize(**kwargs); end
def matches?(other); true === other; end
end
RUBY
if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash?
eval <<-'RUBY', nil, __FILE__, __LINE__ + 1
def my_keyword_matcher(...) = MyKeywordMatcher.new(...)
RUBY
else
eval <<-'RUBY', nil, __FILE__, __LINE__ + 1
def my_keyword_matcher(**kw); MyKeywordMatcher.new(**kw); end
RUBY
end
eval <<-'RUBY', nil, __FILE__, __LINE__ + 1
RSpec::Matchers.alias_matcher :my_keyword_override, :my_keyword_matcher
RSpec::Matchers.define_negated_matcher :not_keyword_override, :my_keyword_matcher
it 'works properly with a keyword arguments matcher' do
expect(true).to my_keyword_override(some: :arg)
end
it 'works properly with a negated keyword arguments matcher' do
expect(false).to not_keyword_override(some: :arg)
end
RUBY
end
context "when negating a matcher that does not define `description` (which is an optional part of the matcher protocol)" do
def matcher_without_description
matcher = Object.new
def matcher.matches?(v); v; end
def matcher.failure_message; "match failed"; end
def matcher.chained; self; end
expect(RSpec::Matchers.is_a_matcher?(matcher)).to be true
matcher
end
RSpec::Matchers.define_negated_matcher :negation_of_matcher_without_description, :matcher_without_description
it 'works properly' do
expect(true).to matcher_without_description.chained
expect(false).to negation_of_matcher_without_description.chained
end
end
end
end
end
|