rspec-change_to_now 1.0.3 → 1.1.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
  SHA1:
3
- metadata.gz: 91fa21b5de7d035ade4c3e75449d2aa869666083
4
- data.tar.gz: 966af72e0e054cf7592dc580530b90c36a4974c2
3
+ metadata.gz: f8e18de5f1c633f028730dd7600213ac9aa54f21
4
+ data.tar.gz: 169e4f56eb8ace773989ca34e3a6bd101fd3b5bf
5
5
  SHA512:
6
- metadata.gz: 2fbd80b7b3881e4368adc39d4fdbf2d60e72457ac2406b9d05e8b0db2739a55bf06ffad3cd31275e8f2e5b759db32535ac265c4a908396c520ed7f8e794a8b8a
7
- data.tar.gz: 39d7852e10fa38a23c0ae6c6e9bc0aeef36ddd91582518071a77b1dce5575188a3bab82ff8cc651c523e544e6436dab4be3aed4e290f8f470029d5fd97dff148
6
+ metadata.gz: 9d2aa3673096f3e9c1d5df8ecf08f1e27aa9661265be953b56d12eedbd1d154235166ec55c1c9acef28fa302c37ef5b36ef419d82cd2814113a0dade8d3eaac3
7
+ data.tar.gz: f3da15d21ad66436057d4aa174546a8450d68825c9d0b145770c99b3ba8226138c2fdff3abe33d986a50be11f3216bdd7c359b4352d4d605fbe820512e5026be
data/Changelog.md CHANGED
@@ -1,3 +1,8 @@
1
+ ### 1.1.0
2
+
3
+ * Add `with_final_result` matcher that doesn't do precondition test
4
+ * Correctly support `to_now` alongside `from`
5
+
1
6
  ### 1.0.3
2
7
 
3
8
  Refer to 'detect' instead of 'include' in messages for detect matcher.
data/README.md CHANGED
@@ -23,6 +23,39 @@ Also supported are aliases for those who don't want to split their infinitives a
23
23
  * `to_now` can also be called as `now_to`
24
24
  * `not_to_now` can also be called `not_to`, `to_not`, `to_not_now` and `not_now_to`
25
25
 
26
+ ## Overriding default RSpec behavior
27
+
28
+ You can force the rspec `change` matcher to always use `to_now` instead of `to` by setting:
29
+
30
+ ```ruby
31
+ RSpec::Matchers::ChangeToNow.override_to = true
32
+ ```
33
+
34
+
35
+ ## Testing without preconditions
36
+
37
+ There are a couple of ways to prevent precondition checks if you don't want them for a particular expectation:
38
+
39
+ 1. Use `with_final_result` instead of `to_now` to check your results. e.g.
40
+
41
+ ```ruby
42
+ it "initializes an empty list" do
43
+ list = nil
44
+ expect { list = [] }.with_final_result satisfy(&:empty)
45
+ end
46
+ ```
47
+
48
+ 1. Explicitly specify a `from` value or matcher, either before or after your `to_now` statement:
49
+
50
+ ```ruby
51
+ it "initializes an empty list" do
52
+ list = nil
53
+ expect { list = [] }.from(nil).to_now satisfy(&:empty)
54
+ list = nil
55
+ expect { list = [] }.to_now satisfy(&:empty).from(nil)
56
+ end
57
+ ```
58
+
26
59
  ## Installation
27
60
 
28
61
  Add this line to your application's Gemfile:
@@ -14,16 +14,47 @@ Feature: expecting a matcher to change
14
14
  When I run rspec
15
15
  Then the examples should all pass
16
16
 
17
- Scenario: failures are correctly reported
17
+ Scenario: the result of a change block can be tested with `with_final_result` without invoking the precondition test
18
+ Given a file named "example_spec.rb" with:
19
+ """ruby
20
+
21
+ describe "creating a list" do
22
+ it "creates an empty list" do
23
+ list = nil
24
+ expect { list = [] }.to change { list }.with_final_result satisfy(&:empty?)
25
+ end
26
+ end
27
+ """
28
+ When I run rspec
29
+ Then the examples should all pass
30
+
31
+ Scenario: precondition failures are correctly reported
18
32
  Given a file named "example_spec.rb" with:
19
33
  """ruby
20
34
 
21
35
  describe "adding one" do
22
36
  it "adds one" do
23
- x = 1
24
- expect { x += 1 }.to change { x }.to_now eq 3
37
+ x = 2
38
+ expect { x += 1 }.to change { x }.to_now eq 2
39
+ end
40
+ end
41
+ """
42
+ When I run rspec
43
+ Then the output should contain "Failure/Error: expect { x += 1 }.to change { x }.to_now eq 2"
44
+ And the output should contain "expected result to have initially been ~(eq 2), but was 2"
45
+
46
+ Scenario: overriding RSpec `change { }.to` to behave like `change { }.to_now`
47
+ Given a file named "example_spec.rb" with:
48
+ """ruby
49
+ RSpec::Matchers::ChangeToNow.override_to = true
50
+
51
+ describe "adding one" do
52
+ it "adds one" do
53
+ x = 2
54
+ expect { x += 1 }.to change { x }.to eq 2
25
55
  end
26
56
  end
27
57
  """
28
58
  When I run rspec
29
- Then the output should contain "Failure/Error: expect { x += 1 }.to change { x }.to_now eq 3"
59
+ Then the output should contain "Failure/Error: expect { x += 1 }.to change { x }.to eq 2"
60
+ And the output should contain "expected result to have initially been ~(eq 2), but was 2"
@@ -25,4 +25,4 @@ Feature: detect matcher
25
25
  """
26
26
  When I run rspec
27
27
  Then the output should contain "Failure/Error: expect([1]).to detect(&:even?)"
28
- And the output should contain "expected [1] to include (satisfy block)"
28
+ And the output should contain "expected [1] to detect (satisfy block)"
@@ -0,0 +1,21 @@
1
+ require 'rspec/core'
2
+ require 'rspec/expectations'
3
+
4
+ module RSpec
5
+ module Matchers
6
+ # Decorator that wraps a matcher and raises an error if the matcher is not a matcher.
7
+ #
8
+ # @api private
9
+ class VerifyArgumentIsMatcher < MatcherDelegator
10
+ # Forward messages on to the wrapped matcher, first verifying that this really is a matcher.
11
+ def method_missing(method, *args)
12
+ raise SyntaxError, "expects a matcher as an argument but got: #{base_matcher.inspect}" unless Matchers.is_a_matcher?(base_matcher)
13
+ base_matcher.send(method, *args)
14
+ end
15
+
16
+ def description(*args)
17
+ base_matcher.description(*args)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module ChangeToNow
3
- VERSION = "1.0.3"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -1,11 +1,28 @@
1
1
  require 'rspec/change_to_now/version'
2
2
  require 'rspec/change_to_now/detect'
3
3
  require 'rspec/change_to_now/negate'
4
+ require 'rspec/change_to_now/verify_argument_is_matcher'
4
5
  require 'rspec/core'
5
6
  require 'rspec/expectations'
6
7
 
7
8
  module RSpec::Matchers
9
+ module ChangeToNowMatchers
10
+ private
11
+
12
+ # @private
13
+ def negate(matcher)
14
+ RSpec::Matchers::Negate.new(matcher)
15
+ end
16
+
17
+ # @private
18
+ def verify_argument_is_matcher(matcher)
19
+ RSpec::Matchers::VerifyArgumentIsMatcher.new(matcher)
20
+ end
21
+ end
22
+
8
23
  class BuiltIn::Change
24
+ include ChangeToNowMatchers
25
+
9
26
  # @api public
10
27
  # Passes if +matcher+ fails on the result of the change block before the expectation block and passes after.
11
28
  #
@@ -18,7 +35,8 @@ module RSpec::Matchers
18
35
  # change {}.to_now eq(1)
19
36
  # change {}.from(negate(eq(1))).to(eq(1))
20
37
  def to_now(matcher)
21
- RSpec::Matchers::BuiltIn::ChangeToValue.new(@change_details, matcher).from(negate(matcher))
38
+ RSpec::Matchers::BuiltIn::ChangeToValue.new(@change_details, verify_argument_is_matcher(matcher)).
39
+ from(negate(verify_argument_is_matcher(matcher)))
22
40
  end
23
41
 
24
42
  # @api public
@@ -27,7 +45,8 @@ module RSpec::Matchers
27
45
  # @example
28
46
  # expect({ @x = 1 }.to change { @x }.not_to_now eq 1
29
47
  def not_to_now(matcher)
30
- RSpec::Matchers::BuiltIn::ChangeToValue.new(@change_details, negate(matcher)).from(matcher)
48
+ RSpec::Matchers::BuiltIn::ChangeToValue.new(@change_details, negate(verify_argument_is_matcher(matcher))).
49
+ from(verify_argument_is_matcher(matcher))
31
50
  end
32
51
 
33
52
  # @api public
@@ -45,11 +64,52 @@ module RSpec::Matchers
45
64
  # @api public
46
65
  alias_method :to_not_now, :not_to_now
47
66
 
48
- private
67
+ # @private
68
+ alias_method :to_without_to_now, :to
49
69
 
50
70
  # @private
51
- def negate(matcher)
52
- RSpec::Matchers::Negate.new(matcher)
71
+ def to_with_to_now(expected)
72
+ if RSpec::Matchers::ChangeToNow.override_to && RSpec::Matchers.is_a_matcher?(expected)
73
+ to_now(expected)
74
+ else
75
+ to_without_to_now(expected)
76
+ end
77
+ end
78
+
79
+ # @private
80
+ alias_method :to, :to_with_to_now
81
+
82
+ # @api public
83
+ def with_final_result(expected)
84
+ to_without_to_now(expected)
85
+ end
86
+ end
87
+
88
+ class BuiltIn::ChangeFromValue
89
+ include ChangeToNowMatchers
90
+
91
+ def to_now(matcher)
92
+ RSpec::Matchers::BuiltIn::ChangeToValue.new(
93
+ @change_details,
94
+ verify_argument_is_matcher(matcher)
95
+ ).from(@expected_before)
96
+ end
97
+
98
+ def not_to_now(matcher)
99
+ RSpec::Matchers::BuiltIn::ChangeToValue.new(
100
+ @change_details,
101
+ negate(verify_argument_is_matcher(matcher))
102
+ ).from(@expected_before)
103
+ end
104
+
105
+ def with_final_result(expected)
106
+ to_without_to_now(expected)
107
+ end
108
+ end
109
+
110
+ class ChangeToNow
111
+ class << self
112
+ attr_accessor :override_to
53
113
  end
54
114
  end
55
115
  end
@@ -37,27 +37,71 @@ module RSpec
37
37
  }.to change { number }.to_now eq 2
38
38
  }.to fail_matching("expected result to have initially been ~(eq 2), but was 2")
39
39
  end
40
+ it "raises an error when not passed a matcher" do
41
+ number = 1
42
+ expect {
43
+ expect {
44
+ number += 1
45
+ }.to change { }.to_now 2
46
+ }.to raise_error SyntaxError, /expects a matcher as an argument/
47
+ end
48
+
49
+ describe "after #from" do
50
+ it "passes without running the default inverse precondition check" do
51
+ list = nil
52
+ expect {
53
+ list = []
54
+ }.to change { list }.from(nil).to_now satisfy(&:empty?)
55
+ end
56
+
57
+ it "fails if the initial condition does not match" do
58
+ expect {
59
+ list = nil
60
+ expect {
61
+ list = []
62
+ }.to change { list }.from(1).to_now satisfy(&:empty?)
63
+ }.to fail_matching("expected result to have initially been 1, but was nil")
64
+ end
65
+ end
66
+
67
+ describe "before #from" do
68
+ it "passes without running the default inverse precondition check" do
69
+ list = nil
70
+ expect {
71
+ list = []
72
+ }.to change { list }.to_now(satisfy(&:empty?)).from(nil)
73
+ end
74
+
75
+ it "fails if the initial condition does not match" do
76
+ expect {
77
+ list = nil
78
+ expect {
79
+ list = []
80
+ }.to change { list }.to_now(satisfy(&:empty?)).from(1)
81
+ }.to fail_matching("expected result to have initially been 1, but was nil")
82
+ end
83
+ end
40
84
  end
41
85
 
42
- describe "#not_to" do
86
+ describe "#not_to_now" do
43
87
  it "succeeds when the final expectation is met" do
44
88
  number = 1
45
89
  expect {
46
90
  number += 2
47
- }.to change { number }.not_to eq 1
91
+ }.to change { number }.not_to_now eq 1
48
92
  end
49
93
  it "fails when there is no change" do
50
94
  number = 1
51
95
  expect {
52
96
  expect {
53
- }.to change { number }.not_to eq 1
97
+ }.to change { number }.not_to_now eq 1
54
98
  }.to fail_matching("expected result to have changed to ~(eq 1) from eq 1, but did not change")
55
99
  end
56
100
  it "fails when the final expectation is already met" do
57
101
  number = 2
58
102
  expect {
59
103
  expect {
60
- }.to change { number }.not_to eq 1
104
+ }.to change { number }.not_to_now eq 1
61
105
  }.to fail_matching("expected result to have initially been eq 1, but was 2")
62
106
  end
63
107
  it "fails when the final expectation is never met" do
@@ -65,9 +109,53 @@ module RSpec
65
109
  expect {
66
110
  expect {
67
111
  number = 4
68
- }.to change { number }.not_to satisfy(&:even?)
112
+ }.to change { number }.not_to_now satisfy(&:even?)
69
113
  }.to fail_matching("expected result to have changed to ~(satisfy block), but is now 4")
70
114
  end
115
+ it "raises an error when not passed a matcher" do
116
+ number = 1
117
+ expect {
118
+ expect {
119
+ number += 1
120
+ }.to change { }.not_to_now 2
121
+ }.to raise_error SyntaxError, /expects a matcher as an argument/
122
+ end
123
+
124
+ describe "after #from" do
125
+ it "passes without running the default inverse precondition check" do
126
+ list = nil
127
+ expect {
128
+ list = [1]
129
+ }.to change { list }.from(nil).not_to_now satisfy(&:empty?)
130
+ end
131
+
132
+ it "fails if the initial condition does not match" do
133
+ expect {
134
+ list = nil
135
+ expect {
136
+ list = [1]
137
+ }.to change { list }.from(1).not_to_now satisfy(&:empty?)
138
+ }.to fail_matching("expected result to have initially been 1, but was nil")
139
+ end
140
+ end
141
+
142
+ describe "before #from" do
143
+ it "passes without running the default inverse precondition check" do
144
+ list = nil
145
+ expect {
146
+ list = [1]
147
+ }.to change { list }.not_to_now(satisfy(&:empty?)).from(nil)
148
+ end
149
+
150
+ it "fails if the initial condition does not match" do
151
+ expect {
152
+ list = nil
153
+ expect {
154
+ list = [1]
155
+ }.to change { list }.not_to_now(satisfy(&:empty?)).from(1)
156
+ }.to fail_matching("expected result to have initially been 1, but was nil")
157
+ end
158
+ end
71
159
  end
72
160
 
73
161
  describe "aliases" do
@@ -80,7 +168,7 @@ module RSpec
80
168
  end
81
169
 
82
170
  describe "negative cases" do
83
- specify "#to_not is the same as #not_to" do
171
+ specify "#to_not is the same as #not_to_now" do
84
172
  expect { @x = 1 }.to change { @x }.to_not eq nil
85
173
  end
86
174
 
@@ -97,5 +185,109 @@ module RSpec
97
185
  end
98
186
  end
99
187
  end
188
+
189
+ describe "#with_final_result" do
190
+ before do
191
+ @x = nil
192
+ end
193
+
194
+ it "checks only the post condition not the precondition" do
195
+ expect { @x = [] }.to change { @x }.with_final_result satisfy(&:empty?)
196
+ end
197
+ describe "when passed an object" do
198
+ it "passes when the final object equals the result" do
199
+ expect { @x = 1 }.to change { @x }.with_final_result 1
200
+ end
201
+ it "fails when the final object does not equal the result" do
202
+ expect {
203
+ expect { @x = 1 }.to change { @x }.with_final_result 2
204
+ }.to fail_matching("expected result to have changed to 2, but is now 1")
205
+ end
206
+ end
207
+
208
+ it "behaves exactly like the original #to method" do
209
+ matcher = change { @x }
210
+ matcher_mock = double()
211
+ expect(matcher).to receive(:to_without_to_now).with(1).and_return(matcher_mock)
212
+ expect(matcher.with_final_result 1).to eq matcher_mock
213
+ end
214
+
215
+ describe "after #from" do
216
+ it "behaves exactly like the original #to method" do
217
+ matcher = change { @x }.from 0
218
+ matcher_mock = double()
219
+ expect(matcher).to receive(:to_without_to_now).with(1).and_return(matcher_mock)
220
+ expect(matcher.with_final_result 1).to eq matcher_mock
221
+ end
222
+ end
223
+ end
224
+
225
+ describe "when #to has been overridden by the configuration setting" do
226
+ before do
227
+ allow(RSpec::Matchers::ChangeToNow).to receive(:override_to).and_return(true)
228
+ end
229
+
230
+ it "fails when the final expectation is already met" do
231
+ number = 2
232
+ expect {
233
+ expect {
234
+ number += 1
235
+ }.to change { number }.to eq 2
236
+ }.to fail_matching("expected result to have initially been ~(eq 2), but was 2")
237
+ end
238
+
239
+ it "still works with basic object matchers" do
240
+ number = 2
241
+ expect {
242
+ expect {
243
+ number += 1
244
+ }.to change { number }.to 2
245
+ }.to fail_matching("expected result to have changed to 2, but is now 3")
246
+ end
247
+
248
+ describe "if #from is specified first" do
249
+ let(:matcher) { change { @number }.from(1).to(eq 2) }
250
+
251
+ it "fails properly when the precondition is not met" do
252
+ @number = 2
253
+ expect {
254
+ expect {
255
+ @number += 1
256
+ }.to matcher
257
+ }.to fail_matching("expected result to have initially been 1, but was 2")
258
+ end
259
+
260
+ it "runs the change check if the precondition is met" do
261
+ @number = 1
262
+ expect {
263
+ expect {
264
+ @number += 2
265
+ }.to matcher
266
+ }.to fail_matching("expected result to have changed to eq 2, but is now 3")
267
+ end
268
+ end
269
+
270
+ describe "if #from is specified after #to" do
271
+ let(:matcher) { change { @number }.to(eq 2).from(1) }
272
+
273
+ it "fails properly when the precondition is not met" do
274
+ @number = 2
275
+ expect {
276
+ expect {
277
+ @number += 1
278
+ }.to matcher
279
+ }.to fail_matching("expected result to have initially been 1, but was 2")
280
+ end
281
+
282
+ it "runs the change check if the precondition is met" do
283
+ @number = 1
284
+ expect {
285
+ expect {
286
+ @number += 2
287
+ }.to matcher
288
+ }.to fail_matching("expected result to have changed to eq 2, but is now 3")
289
+ end
290
+ end
291
+ end
100
292
  end
101
293
  end
@@ -0,0 +1,19 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe RSpec::Matchers::VerifyArgumentIsMatcher do
4
+ describe "when the argument is a matcher" do
5
+ it "delegates to the matcher" do
6
+ expect {
7
+ expect(1).to RSpec::Matchers::VerifyArgumentIsMatcher.new(eq 2)
8
+ }.to fail_matching(/expected: 2.*got: 1/m)
9
+ end
10
+ end
11
+
12
+ describe "when the argument is not a matcher" do
13
+ it "raises a syntax error when the matcher is evaluated" do
14
+ expect {
15
+ expect(1).to RSpec::Matchers::VerifyArgumentIsMatcher.new(2)
16
+ }.to raise_error SyntaxError, "expects a matcher as an argument but got: 2"
17
+ end
18
+ end
19
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-change_to_now
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew S. Brown
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-02 00:00:00.000000000 Z
11
+ date: 2014-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-core
@@ -175,12 +175,14 @@ files:
175
175
  - lib/rspec/change_to_now.rb
176
176
  - lib/rspec/change_to_now/detect.rb
177
177
  - lib/rspec/change_to_now/negate.rb
178
+ - lib/rspec/change_to_now/verify_argument_is_matcher.rb
178
179
  - lib/rspec/change_to_now/version.rb
179
180
  - rspec-change_to_now.gemspec
180
181
  - script/test_all
181
182
  - spec/rspec/change_to_now_spec.rb
182
183
  - spec/rspec/detect_spec.rb
183
184
  - spec/rspec/negate_spec.rb
185
+ - spec/rspec/verify_argument_is_matcher_spec.rb
184
186
  - spec/spec_helper.rb
185
187
  - spec/support/matchers.rb
186
188
  homepage: https://github.com/dontfidget/rspec-change_to_now
@@ -216,6 +218,7 @@ test_files:
216
218
  - spec/rspec/change_to_now_spec.rb
217
219
  - spec/rspec/detect_spec.rb
218
220
  - spec/rspec/negate_spec.rb
221
+ - spec/rspec/verify_argument_is_matcher_spec.rb
219
222
  - spec/spec_helper.rb
220
223
  - spec/support/matchers.rb
221
224
  has_rdoc: