rspec-change_to_now 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: