flexmock 2.4.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95477346c9b4f5310e7aab502150273b0473194442fdee505ab366efbbba77bf
4
- data.tar.gz: cf44602d7ddfa3197ff847e476da46adc9b82a07382c100e2eb149abc56ae285
3
+ metadata.gz: 97fdfec71cb9dd687df62403b26eb8d4d24e4b28ec7f35f5e2d5f3ac6ffed943
4
+ data.tar.gz: 8f250a12f731099db17e9fcea78b92e0b92ac523376a34e06b5295f3a17ec996
5
5
  SHA512:
6
- metadata.gz: bc7337acd6e30ede212fbe23f44149c9b76693dacec228e06fac7b4f60bb684d9a641b2fd3b5be3b7fe401cc22bc8eeaff01883808fd594c6d7e6209f9128db5
7
- data.tar.gz: cc11b26a6a3508adae240889c9c1e1c2484876b965f6dc82f54282061c8405bcf52d8e5b6f15a963239c9cf939cd50f9c2c74ad82bf9d469bec1a25d021c1ae8
6
+ metadata.gz: 7672fd90360b33327119a7f135a7db9d05c7b7d41e0dd5299396296e0b68c8bb5175eaa2cf8d334b9b8cc62f52a87af4fe8af8216a4e9283341c909eed5ca196
7
+ data.tar.gz: a2112c506ef7152ba13aef9f67cb9ab5d58a0b566b5f50e7db00e545ff04e663da129f8291109dc25f028b2150ca4a936d96ced1444cbb85b4298534179046dc
@@ -8,7 +8,11 @@ jobs:
8
8
 
9
9
  strategy:
10
10
  matrix:
11
- ruby-version: ["2.7", "2.6", "2.5"]
11
+ ruby-version:
12
+ - "3.2"
13
+ - "3.1"
14
+ - "3.0"
15
+ - "2.7"
12
16
 
13
17
  steps:
14
18
  - uses: actions/checkout@v2
data/README.md CHANGED
@@ -22,6 +22,44 @@ Only significant changes (new APIs, deprecated APIs or backward-compatible
22
22
  changes) are documented here, a.k.a. minor or major version bumps. If you want a
23
23
  detailed changelog, go over the commit log in github (it's pretty low-traffic)
24
24
 
25
+ 3.0.0:
26
+ - Added keyword argument and explicit proc support. Keyword argument support
27
+ is Ruby 3.0+ only, getting the support to work on Ruby 2.7 deemed to be too
28
+ complicated. See the release notes for 2.4 below for information about how
29
+ migration can be done smoothly
30
+ - `with` now expects all expected keyword arguments to be explicitly given in a
31
+ natural way, for instance:
32
+
33
+ ```
34
+ mock.should_receive(:m).with("some", "args", with: 42)
35
+ ```
36
+
37
+ The values given to the arguments can be any matcher valid for the positional
38
+ arguments
39
+ - note that not giving any keyword arguments to `with` is interpreted as a
40
+ negative (no keyword arguments are expected), and will fail if some arguments
41
+ are given. Call `with_any_kw_args` after the `with` if you do not desire
42
+ validation of keyword arguments:
43
+
44
+ ```
45
+ mock.should_receive(:m).with("some", "args").with_any_kw_args
46
+ ```
47
+
48
+ - for more complex matches, pass a match object to the `with_kw_args` method.
49
+ For instance, to match only some keyword arguments, do
50
+
51
+ ```
52
+ mock.should_receive(:m).with("some", "args").with_kw_args(hsh(with: 42))
53
+ ```
54
+
55
+ - this release also makes matching procs explicit. Instead of passing Proc at
56
+ the end of `with` as in 2.x, call `with_block` or `with_no_block`. If neither
57
+ are called, flexmock won't validate either way (ignore whether or not a block
58
+ was given). The default is to not match blocks, that is working
59
+ - The default is to assume that blocks are optional (i.e. flexmock will match
60
+ either way). Nonetheless, the method `with_optional_block` is implemented
61
+ to help migration from flexmock 2.4.0 (but is a no-op).
62
+
25
63
  2.4.0:
26
64
  - forward-compatible implementation of `with_kw_args`, `with_any_kw_args`,
27
65
  `with_block` and `with_no_block`. The objective of this release is to ensure
@@ -556,12 +594,10 @@ determining whether a given expectation matches or not.
556
594
  series. The last value will be repeatably returned if the number of
557
595
  matching calls exceeds the number of values.
558
596
 
559
- * <b>and_return { |<em>args</em>, ...| <em>code</em> ... }</b>
597
+ * <b>and_return { |<em>*args</em>, <em>**kw</em>, <em>&block</em>| <em>code</em> ... }</b>
560
598
 
561
599
  Declares that the expected message will return the yielded value of
562
600
  the block. The block will receive all the arguments in the message.
563
- If the message was provided a block, it will be passed as the last
564
- parameter of the block's argument list.
565
601
 
566
602
  * <b>returns( ... )</b>
567
603
 
@@ -765,13 +801,15 @@ The following rules are used for argument matching:
765
801
 
766
802
  will match any even integer.
767
803
 
768
- * If you wish to match a method call where a block is given, add
769
- `Proc` as the last argument to `with`.
804
+ * By default, flexmock will ignore given blocks, that is it will assume that
805
+ blocks are optional.
806
+
807
+ * If you wish to verify that a method call received a block, use `with_block`
770
808
 
771
809
  Example:
772
810
 
773
811
  ```ruby
774
- m.should_receive(:foo).with(Integer,Proc).and_return(:got_block)
812
+ m.should_receive(:foo).with(Integer).with_block.and_return(:got_block)
775
813
  m.should_receive(:foo).with(Integer).and_return(:no_block)
776
814
  ```
777
815
 
@@ -782,6 +820,22 @@ The following rules are used for argument matching:
782
820
  m.foo(1) => returns :no_block
783
821
  ```
784
822
 
823
+ * If you wish to verify that a method call does not receive a block, use `with_no_block`
824
+
825
+ Example:
826
+
827
+ ```ruby
828
+ m.should_receive(:foo).with(Integer).with_no_block.and_return(:no_block)
829
+ m.should_receive(:foo).with(Integer).and_return(:got_block)
830
+ ```
831
+
832
+ will cause the mock to return the following:
833
+
834
+ ```ruby
835
+ m.foo(1) { } => returns :got_block
836
+ m.foo(1) => returns :no_block
837
+ ```
838
+
785
839
  ### Creating Partial Mocks
786
840
 
787
841
  Sometimes it is useful to mock the behavior of one or two methods in
data/flexmock.gemspec CHANGED
@@ -10,7 +10,7 @@ spec = Gem::Specification.new do |s|
10
10
  interface is simple, it is very flexible.
11
11
  }
12
12
 
13
- s.required_ruby_version = ">= 2.2"
13
+ s.required_ruby_version = ">= 3.0"
14
14
 
15
15
  s.license = 'MIT'
16
16
 
@@ -62,41 +62,11 @@ class FlexMock
62
62
  def ===(target)
63
63
  @hash.all? { |k, v| target[k] == v }
64
64
  end
65
- def inspect
66
- "hsh(#{@hash.inspect})"
67
- end
68
- end
69
-
70
- ####################################################################
71
- # Match hashes that match all the fields of +hash+.
72
- class KwArgsMatcher
73
- def initialize(expected)
74
- @expected = expected
75
- end
76
- def ===(target)
77
- return false unless target.kind_of?(Hash)
78
- matching = @expected.all? do |k, v|
79
- v === target[k] || v == target[k]
80
- end
81
- return false unless matching
82
-
83
- @expected.size == target.size
65
+ def empty?
66
+ @hash.empty?
84
67
  end
85
68
  def inspect
86
- args = @expected.map do |k, v|
87
- k_s = case k
88
- when Symbol
89
- "#{k}: "
90
- else
91
- "#{k.inspect} => "
92
- end
93
-
94
- v_s = FlexMock.forbid_mocking("<recursive call to mocked method in #inspect>") do
95
- v.inspect
96
- end
97
- "#{k_s}#{v_s}"
98
- end
99
- args.join(", ")
69
+ "hsh(#{@hash.inspect})"
100
70
  end
101
71
  end
102
72
 
@@ -113,19 +83,4 @@ class FlexMock
113
83
  "ducktype(#{@methods.map{|m| m.inspect}.join(',')})"
114
84
  end
115
85
  end
116
-
117
- ####################################################################
118
- # Match objects that implement all the methods in +methods+.
119
- class OptionalProcMatcher
120
- def initialize
121
- end
122
- def ===(target)
123
- ArgumentMatching.missing?(target) || Proc === target
124
- end
125
- def inspect
126
- "optional_proc"
127
- end
128
- end
129
- OPTIONAL_PROC_MATCHER = OptionalProcMatcher.new
130
-
131
86
  end
@@ -4,7 +4,13 @@ class FlexMock
4
4
 
5
5
  MISSING_ARG = Object.new
6
6
 
7
- def all_match?(expected_args, actual_args)
7
+ def all_match?(expected_args, expected_kw, expected_block, actual_args, actual_kw, actual_block)
8
+ all_match_args?(expected_args, actual_args) &&
9
+ all_match_kw?(expected_kw, actual_kw) &&
10
+ all_match_block?(expected_block, actual_block)
11
+ end
12
+
13
+ def all_match_args?(expected_args, actual_args)
8
14
  return true if expected_args.nil?
9
15
  return false if actual_args.size > expected_args.size
10
16
  i = 0
@@ -19,6 +25,30 @@ class FlexMock
19
25
  true
20
26
  end
21
27
 
28
+ def all_match_kw?(expected_kw, actual_kw)
29
+ return true if expected_kw.nil?
30
+ return expected_kw === actual_kw if expected_kw.kind_of? HashMatcher
31
+
32
+ matched_expected_k = Set.new
33
+ actual_kw.each do |actual_k, actual_v|
34
+ found_match = expected_kw.find do |k, v|
35
+ match?(k, actual_k) && match?(v, actual_v)
36
+ end
37
+ return false unless found_match
38
+ matched_expected_k << found_match
39
+ end
40
+
41
+ return false unless matched_expected_k.size == expected_kw.keys.size
42
+
43
+ true
44
+ end
45
+
46
+ def all_match_block?(expected_block, actual_block)
47
+ return true if expected_block.nil?
48
+
49
+ !(expected_block ^ actual_block)
50
+ end
51
+
22
52
  # Does the expected argument match the corresponding actual value.
23
53
  def match?(expected, actual)
24
54
  expected === actual ||
@@ -47,10 +47,6 @@ class FlexMock
47
47
  def ducktype(*methods)
48
48
  DuckMatcher.new(methods)
49
49
  end
50
-
51
- def optional_proc
52
- OPTIONAL_PROC_MATCHER
53
- end
54
50
  end
55
51
  extend ArgumentTypes
56
52
 
@@ -11,10 +11,11 @@
11
11
 
12
12
  class FlexMock
13
13
 
14
- CallRecord = Struct.new(:method_name, :args, :block_given, :expectation) do
15
- def matches?(sym, actual_args, options)
14
+ CallRecord = Struct.new(:method_name, :args, :kw, :block, :expectation) do
15
+ def matches?(sym, expected_args, expected_kw, options)
16
16
  method_name == sym &&
17
- ArgumentMatching.all_match?(actual_args, args) &&
17
+ ArgumentMatching.all_match_args?(expected_args, args) &&
18
+ ArgumentMatching.all_match_kw?(expected_kw, kw) &&
18
19
  matches_block?(options[:with_block])
19
20
  end
20
21
 
@@ -22,8 +23,12 @@ class FlexMock
22
23
 
23
24
  def matches_block?(block_option)
24
25
  block_option.nil? ||
25
- (block_option && block_given) ||
26
- (!block_option && !block_given)
26
+ (block_option && block) ||
27
+ (!block_option && !block)
28
+ end
29
+
30
+ def block_given
31
+ block
27
32
  end
28
33
  end
29
34
 
@@ -24,10 +24,10 @@ class FlexMock
24
24
  # * :on_count => n -- If given, the :and validations on only run on the
25
25
  # nth invocation.
26
26
  #
27
- def received?(calls, method_name, args, options)
27
+ def received?(calls, method_name, args, kw, options)
28
28
  count = 0
29
29
  calls.each { |call_record|
30
- if call_record.matches?(method_name, args, options)
30
+ if call_record.matches?(method_name, args, kw, options)
31
31
  count += 1
32
32
  run_additional_validations(call_record, count, options)
33
33
  end
@@ -3,8 +3,7 @@ class FlexMock
3
3
  # A composite expectation allows several expectations to be grouped into a
4
4
  # single composite and then apply the same constraints to all expectations
5
5
  # in the group.
6
- class CompositeExpectation < BasicObject
7
- attr_reader :expectations
6
+ class CompositeExpectation
8
7
 
9
8
  # Initialize the composite expectation.
10
9
  def initialize
@@ -17,9 +16,9 @@ class FlexMock
17
16
  end
18
17
 
19
18
  # Apply the constraint method to all expectations in the composite.
20
- def method_missing(sym, *args, &block)
19
+ def method_missing(sym, *args, **kw, &block)
21
20
  @expectations.each do |expectation|
22
- expectation.send(sym, *args, &block)
21
+ expectation.send(sym, *args, **kw, &block)
23
22
  end
24
23
  self
25
24
  end
@@ -39,9 +38,9 @@ class FlexMock
39
38
 
40
39
  # Start a new method expectation. The following constraints will be
41
40
  # applied to the new expectation.
42
- def should_receive(*args, &block)
41
+ def should_receive(*args, **kw, &block)
43
42
  @expectations.first.mock.
44
- flexmock_define_expectation(caller, *args, &block)
43
+ flexmock_define_expectation(caller, *args, **kw, &block)
45
44
  end
46
45
 
47
46
  # Return a string representations
data/lib/flexmock/core.rb CHANGED
@@ -137,23 +137,22 @@ class FlexMock
137
137
  end
138
138
 
139
139
  # Handle missing methods by attempting to look up a handler.
140
- def method_missing(sym, *args, &block)
140
+ def method_missing(sym, *args, **kw, &block)
141
141
  FlexMock.verify_mocking_allowed!
142
142
 
143
- enhanced_args = block_given? ? args + [block] : args
144
- call_record = CallRecord.new(sym, enhanced_args, block_given?)
143
+ call_record = CallRecord.new(sym, args, kw, block)
145
144
  @calls << call_record
146
145
  flexmock_wrap do
147
146
  if flexmock_closed?
148
147
  FlexMock.undefined
149
148
  elsif exp = flexmock_expectations_for(sym)
150
- exp.call(args, block, call_record)
149
+ exp.call(args, kw, block, call_record)
151
150
  elsif @base_class && @base_class.flexmock_defined?(sym)
152
151
  FlexMock.undefined
153
152
  elsif @ignore_missing
154
153
  FlexMock.undefined
155
154
  else
156
- super(sym, *args, &block)
155
+ super(sym, *args, **kw, &block)
157
156
  end
158
157
  end
159
158
  end
@@ -167,9 +166,9 @@ class FlexMock
167
166
  end
168
167
 
169
168
  # Find the mock expectation for method sym and arguments.
170
- def flexmock_find_expectation(method_name, *args) # :nodoc:
169
+ def flexmock_find_expectation(method_name, *args, **kw, &block) # :nodoc:
171
170
  if exp = flexmock_expectations_for(method_name)
172
- exp.find_expectation(*args)
171
+ exp.find_expectation(args, kw, block)
173
172
  end
174
173
  end
175
174
 
@@ -195,8 +194,8 @@ class FlexMock
195
194
  CALL_VALIDATOR = CallValidator.new
196
195
 
197
196
  # True if the mock received the given method and arguments.
198
- def flexmock_received?(method_name, args, options={})
199
- CALL_VALIDATOR.received?(@calls, method_name, args, options)
197
+ def flexmock_received?(method_name, args, kw, options = {})
198
+ CALL_VALIDATOR.received?(@calls, method_name, args, kw, options)
200
199
  end
201
200
 
202
201
  # Return the list of calls made on this mock. Used in formatting
@@ -207,13 +206,17 @@ class FlexMock
207
206
 
208
207
  # Invocke the original non-mocked functionality for the given
209
208
  # symbol.
210
- def flexmock_invoke_original(method_name, args, orig_block)
209
+ def flexmock_invoke_original(method_name, args, kw = {})
211
210
  return FlexMock.undefined
212
211
  end
213
212
 
214
213
  # Override the built-in +method+ to include the mocked methods.
215
214
  def method(method_name)
216
- flexmock_expectations_for(method_name) || super
215
+ if (expectations = flexmock_expectations_for(method_name))
216
+ ->(*args, **kw, &block) { expectations.call(args, kw, block) }
217
+ else
218
+ super
219
+ end
217
220
  rescue NameError => ex
218
221
  if ignore_missing?
219
222
  proc { FlexMock.undefined }
@@ -241,15 +244,15 @@ class FlexMock
241
244
  #
242
245
  # See Expectation for a list of declarators that can be used.
243
246
  #
244
- def should_receive(*args)
245
- flexmock_define_expectation(caller, *args)
247
+ def should_receive(*args, **kw)
248
+ flexmock_define_expectation(caller, *args, **kw)
246
249
  end
247
250
 
248
251
  ON_RUBY_20 = (RUBY_VERSION =~ /^2\.0\./)
249
252
 
250
253
  # Using +location+, define the expectations specified by +args+.
251
- def flexmock_define_expectation(location, *args)
252
- @last_expectation = EXP_BUILDER.parse_should_args(self, args) do |method_name|
254
+ def flexmock_define_expectation(location, *args, **kw)
255
+ @last_expectation = EXP_BUILDER.parse_should_args(self, args, kw) do |method_name|
253
256
  exp = flexmock_expectations_for(method_name) || ExpectationDirector.new(method_name)
254
257
  @expectations[method_name] = exp
255
258
  result = Expectation.new(self, method_name, location)
@@ -258,7 +261,7 @@ class FlexMock
258
261
 
259
262
  if @base_class && !@base_class.flexmock_defined?(method_name)
260
263
  if !ON_RUBY_20 || !@base_class.ancestors.include?(Class)
261
- result = ExplicitNeeded.new(result, method_name, @base_class)
264
+ result = ExplicitNeeded.new(result, method_name, @base_class)
262
265
  end
263
266
  end
264
267
  result
@@ -298,8 +301,8 @@ class FlexMock
298
301
  # to explicitly invoke the method_missing logic.
299
302
  def override_existing_method(method_name)
300
303
  sclass.class_eval <<-EOS
301
- def #{method_name}(*args, &block)
302
- method_missing(:#{method_name}, *args, &block)
304
+ def #{method_name}(*args, **kw, &block)
305
+ method_missing(:#{method_name}, *args, **kw, &block)
303
306
  end
304
307
  EOS
305
308
  end
@@ -78,35 +78,42 @@ class FlexMock
78
78
 
79
79
  # Class method to format a method name and argument list as a nice
80
80
  # looking string.
81
- def format_call(sym, args) # :nodoc:
82
- "#{sym}(#{format_args(args)})"
81
+ def format_call(sym, args, kw) # :nodoc:
82
+ "#{sym}(#{format_args(args, kw)})"
83
83
  end
84
84
 
85
85
  # Class method to format a list of args (the part between the
86
86
  # parenthesis).
87
- def format_args(args)
88
- if args
89
- args = args.map do |a|
90
- FlexMock.forbid_mocking("<recursive call to mocked method in #inspect>") do
91
- a.inspect
87
+ def format_args(args, kw)
88
+ args =
89
+ if args
90
+ args = args.map do |a|
91
+ FlexMock.forbid_mocking("<recursive call to mocked method in #inspect>") do
92
+ a.inspect
93
+ end
92
94
  end
95
+ args.join(', ')
96
+ else
97
+ "*args"
93
98
  end
94
- args.join(', ')
95
- else
96
- "*args"
97
- end
98
- end
99
99
 
100
- # Class method to format a list of args (the part between the
101
- # parenthesis).
102
- def format_kw_args(args)
103
- if args
104
- FlexMock.forbid_mocking("<recursive call to mocked method in #inspect>") do
105
- args.inspect
100
+ kw =
101
+ if kw.kind_of? HashMatcher
102
+ kw.inspect
103
+ elsif kw && !kw.empty?
104
+ kw = kw.transform_values do |v|
105
+ FlexMock.forbid_mocking("<recursive call to mocked method in #inspect>") do
106
+ v.inspect
107
+ end
108
+ end
109
+ kw.map { |k, v| "#{k}: #{v}" }.join(', ')
110
+ elsif kw.nil?
111
+ # Don't append **kwargs to signature if ruby version < 3
112
+ # in order to not break existing code still on ruby2
113
+ "**kwargs" unless RUBY_VERSION < "3"
106
114
  end
107
- else
108
- "**args"
109
- end
115
+
116
+ [(args unless args.empty?), kw].compact.join(", ")
110
117
  end
111
118
 
112
119
  # Check will assert the block returns true. If it doesn't, an