File: aliased_matcher_spec.rb

package info (click to toggle)
ruby-rspec 3.13.0c0e0m0s1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,856 kB
  • sloc: ruby: 70,868; sh: 1,423; makefile: 99
file content (142 lines) | stat: -rw-r--r-- 5,082 bytes parent folder | download
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