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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
|
module RSpec
module Matchers
RSpec.describe 'RSpec::Matchers.define_negated_matcher' do
RSpec::Matchers.define :my_base_non_negated_matcher do
match { |actual| actual == foo }
def foo
13
end
def description
"my base matcher description"
end
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 = AliasedNegatedMatcher.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_non_negated_matcher
aliased = AliasedNegatedMatcher.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(15).to copy
expect { expect(13).to copy }.to fail_with(/expected 13/)
end
end
end
include_examples "making a copy", :dup
include_examples "making a copy", :clone
RSpec::Matchers.define_negated_matcher :an_array_excluding, :include
it_behaves_like "an RSpec value matcher", :valid_value => [1, 3], :invalid_value => [1, 2] do
let(:matcher) { an_array_excluding(2) }
end
it 'works properly when composed' do
list = 1.upto(10).to_a
expect { list.delete(5) }.to change { list }.to(an_array_excluding 5)
end
describe "the failure message" do
context "for a matcher with default failure messages" do
RSpec::Matchers.define(:be_awesome) { match(&:awesome?) }
RSpec::Matchers.define_negated_matcher :be_lame, :be_awesome
context "when failing positively" do
it "uses the phrasing from the provided defined matcher alias" do
expect {
expect(double(:awesome? => true, :inspect => "<Object>")).to be_lame
}.to fail_with("expected <Object> to be lame")
end
end
context "when failing negatively" do
it "uses the phrasing from the provided defined matcher alias" do
expect {
expect(double(:awesome? => false, :inspect => "<Object>")).not_to be_lame
}.to fail_with("expected <Object> not to be lame")
end
end
context "when accessed via an alias that is not included in failure messages" do
alias_method :be_fantastic, :be_awesome
RSpec::Matchers.define_negated_matcher :be_terrible, :be_fantastic
context "when failing positively" do
it "uses the wrapped matcher's `failure_message_when_negated`" do
expect {
expect(double(:awesome? => true, :inspect => "<Object>")).to be_terrible
}.to fail_with("expected <Object> not to be awesome")
end
end
context "when failing negatively" do
it "uses the wrapped matcher's `failure_message`" do
expect {
expect(double(:awesome? => false, :inspect => "<Object>")).not_to be_terrible
}.to fail_with("expected <Object> to be awesome")
end
end
end
end
context "for a matcher with a customized `failure_message_when_negated`" do
RSpec::Matchers.define(:be_tall) do
match(&:tall?)
failure_message_when_negated do |actual|
"expected #{actual.inspect} not to be tall, but was tall"
end
end
RSpec::Matchers.define_negated_matcher :be_short, :be_tall
context "when failing positively" do
it "uses the wrapped matcher's `failure_message_when_negated` since it may include more detail" do
expect {
expect(double(:tall? => true, :inspect => "<Object>")).to be_short
}.to fail_with("expected <Object> not to be tall, but was tall")
end
end
context "when failing negatively" do
it "uses the wrapped matcher's `failure_message` since it may include more detail" do
expect {
expect(double(:tall? => false, :inspect => "<Object>")).not_to be_short
}.to fail_with("expected <Object> to be tall")
end
end
end
end
context 'when no block is passed' do
RSpec::Matchers.define :be_an_odd_number do
match { |actual| actual.odd? }
end
RSpec::Matchers.define_negated_matcher :be_an_even_number, :be_an_odd_number
it 'uses the default negated description' do
expect(be_an_even_number.description).to eq("be an even number")
end
context "when matched positively" do
it 'matches values that fail the original matcher' do
expect { expect(22).to be_an_odd_number }.to fail_with("expected 22 to be an odd number")
expect(22).to be_an_even_number
end
it "fails matches against values that pass the original matcher" do
expect(21).to be_an_odd_number
expect { expect(21).to be_an_even_number }.to fail_with("expected 21 to be an even number")
end
end
context "when matched negatively" do
it 'matches values that fail the original matcher' do
expect { expect(21).not_to be_an_odd_number }.to fail_with("expected 21 not to be an odd number")
expect(21).not_to be_an_even_number
end
it "fails matches against values that pass the original matcher" do
expect(22).not_to be_an_odd_number
expect { expect(22).not_to be_an_even_number }.to fail_with("expected 22 not to be an even number")
end
end
end
context 'when the negated description is overridden' do
RSpec::Matchers.define :be_bigger_than_ten do
match { |actual| actual > 10 }
end
RSpec::Matchers.define_negated_matcher :be_smaller_than_ten, :be_bigger_than_ten do |desc|
"#{desc.sub('bigger', 'smaller')} (overridden)"
end
it 'overrides the description with the provided block' do
expect(be_smaller_than_ten.description).to eq("be smaller than ten (overridden)")
end
it 'overrides the failure message with the provided block' do
expect { expect(12).to be_smaller_than_ten }.to fail_with("expected 12 to be smaller than ten (overridden)")
end
end
context "for a matcher that has custom `match_when_negated` logic" do
RSpec::Matchers.define :matcher_with_custom_negation do |match_value|
match { match_value }
match_when_negated { |actual| actual == :does_not_match_true }
end
RSpec::Matchers.define_negated_matcher :negated_matcher_with_custom_negation, :matcher_with_custom_negation
it "uses the `match_when_negated` logic for matching" do
expect(:does_not_match_true).to negated_matcher_with_custom_negation(true)
expect {
expect(:does_not_match_false).to negated_matcher_with_custom_negation(true)
}.to fail
end
it "uses the `match` logic for `expect(..).not_to`" do
expect(:foo).not_to negated_matcher_with_custom_negation(true)
end
end
end
end
end
|