rspec-sleeping_king_studios 2.3.0 → 2.4.0.rc.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.
Files changed (25) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +40 -2
  3. data/DEVELOPMENT.md +48 -28
  4. data/README.md +55 -7
  5. data/lib/rspec/sleeping_king_studios.rb +7 -0
  6. data/lib/rspec/sleeping_king_studios/concerns/example_constants.rb +14 -3
  7. data/lib/rspec/sleeping_king_studios/concerns/focus_examples.rb +1 -1
  8. data/lib/rspec/sleeping_king_studios/configuration.rb +20 -17
  9. data/lib/rspec/sleeping_king_studios/examples/property_examples/class_properties.rb +32 -22
  10. data/lib/rspec/sleeping_king_studios/examples/property_examples/constants.rb +8 -0
  11. data/lib/rspec/sleeping_king_studios/examples/property_examples/predicates.rb +8 -4
  12. data/lib/rspec/sleeping_king_studios/examples/property_examples/private_properties.rb +29 -24
  13. data/lib/rspec/sleeping_king_studios/examples/property_examples/properties.rb +52 -27
  14. data/lib/rspec/sleeping_king_studios/matchers/core/have_changed.rb +16 -0
  15. data/lib/rspec/sleeping_king_studios/matchers/core/have_changed_matcher.rb +222 -0
  16. data/lib/rspec/sleeping_king_studios/matchers/core/have_constant.rb +2 -0
  17. data/lib/rspec/sleeping_king_studios/matchers/core/have_constant_matcher.rb +29 -27
  18. data/lib/rspec/sleeping_king_studios/matchers/core/have_predicate.rb +1 -0
  19. data/lib/rspec/sleeping_king_studios/matchers/core/have_predicate_matcher.rb +1 -1
  20. data/lib/rspec/sleeping_king_studios/matchers/core/have_property.rb +1 -0
  21. data/lib/rspec/sleeping_king_studios/matchers/core/have_reader.rb +1 -0
  22. data/lib/rspec/sleeping_king_studios/matchers/core/have_writer.rb +1 -0
  23. data/lib/rspec/sleeping_king_studios/support/value_spy.rb +67 -0
  24. data/lib/rspec/sleeping_king_studios/version.rb +3 -3
  25. metadata +24 -53
@@ -26,7 +26,9 @@ module RSpec::SleepingKingStudios::Examples
26
26
  end # if-else
27
27
  end # it
28
28
  end # shared_examples
29
+ alias_shared_examples 'defines constant', 'should have constant'
29
30
  alias_shared_examples 'has constant', 'should have constant'
31
+ alias_shared_examples 'should define constant', 'should have constant'
30
32
 
31
33
  shared_examples 'should have immutable constant' do |constant_name, expected_value = UNDEFINED_VALUE_EXPECTATION|
32
34
  it "should have immutable constant :#{constant_name}" do
@@ -45,7 +47,13 @@ module RSpec::SleepingKingStudios::Examples
45
47
  end # if-else
46
48
  end # it
47
49
  end # shared_examples
50
+ alias_shared_examples 'defines frozen constant', 'should have immutable constant'
51
+ alias_shared_examples 'defines immutable constant', 'should have immutable constant'
52
+ alias_shared_examples 'has frozen constant', 'should have immutable constant'
48
53
  alias_shared_examples 'has immutable constant', 'should have immutable constant'
54
+ alias_shared_examples 'should define frozen constant', 'should have immutable constant'
55
+ alias_shared_examples 'should define immutable constant', 'should have immutable constant'
56
+ alias_shared_examples 'should have frozen constant', 'should have immutable constant'
49
57
  end # module
50
58
  end # module
51
59
  end # module
@@ -9,20 +9,24 @@ module RSpec::SleepingKingStudios::Examples
9
9
  module Predicates
10
10
  extend RSpec::SleepingKingStudios::Concerns::SharedExampleGroup
11
11
 
12
- shared_examples 'should have predicate' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION|
13
- it "should have predicate :#{property}?" do
12
+ shared_examples 'should have predicate' do |property_name, expected_value = UNDEFINED_VALUE_EXPECTATION|
13
+ property_name = property_name.to_s.sub(/\?\z/, '')
14
+
15
+ it "should have predicate :#{property_name}?" do
14
16
  object = defined?(instance) ? instance : subject
15
17
 
16
18
  if expected_value == UNDEFINED_VALUE_EXPECTATION
17
- expect(object).to have_predicate(property)
19
+ expect(object).to have_predicate(property_name)
18
20
  else
19
21
  expected_value = format_expected_value(expected_value)
20
22
 
21
- expect(object).to have_predicate(property).with_value(expected_value)
23
+ expect(object).to have_predicate(property_name).with_value(expected_value)
22
24
  end # if-else
23
25
  end # it
24
26
  end # shared_examples
27
+ alias_shared_examples 'defines predicate', 'should have predicate'
25
28
  alias_shared_examples 'has predicate', 'should have predicate'
29
+ alias_shared_examples 'should define predicate', 'should have predicate'
26
30
  end # module
27
31
  end # module
28
32
  end # module
@@ -8,23 +8,47 @@ module RSpec::SleepingKingStudios::Examples
8
8
  module PrivateProperties
9
9
  extend RSpec::SleepingKingStudios::Concerns::SharedExampleGroup
10
10
 
11
+ shared_examples 'should have private property' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION|
12
+ writer_name = :"#{property.to_s.sub(/=\z/, '')}="
13
+
14
+ it "should have private property :#{property}" do
15
+ object = defined?(instance) ? instance : subject
16
+ matcher = have_property(property, :allow_private => true)
17
+
18
+ expect(object).not_to respond_to(property)
19
+ expect(object).not_to respond_to(writer_name)
20
+
21
+ if expected_value == UNDEFINED_VALUE_EXPECTATION
22
+ expect(object).to have_property(property, allow_private: true)
23
+ else
24
+ expected_value = format_expected_value(expected_value)
25
+
26
+ expect(object).to have_property(property, allow_private: true).with_value(expected_value)
27
+ end # if-else
28
+ end # it
29
+ end # shared_examples
30
+ alias_shared_examples 'defines private property', 'should have private property'
31
+ alias_shared_examples 'has private property', 'should have private property'
32
+ alias_shared_examples 'should define private property', 'should have private property'
33
+
11
34
  shared_examples 'should have private reader' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION|
12
35
  it "should have private reader :#{property}" do
13
36
  object = defined?(instance) ? instance : subject
14
- matcher = have_reader(property, :allow_private => true)
15
37
 
16
38
  expect(object).not_to respond_to(property)
17
39
 
18
40
  if expected_value == UNDEFINED_VALUE_EXPECTATION
19
- expect(object).to matcher
41
+ expect(object).to have_reader(property, allow_private: true)
20
42
  else
21
43
  expected_value = format_expected_value(expected_value)
22
44
 
23
- expect(object).to matcher.with_value(expected_value)
45
+ expect(object).to have_reader(property, allow_private: true).with_value(expected_value)
24
46
  end # if-else
25
47
  end # it
26
48
  end # shared_examples
49
+ alias_shared_examples 'defines private reader', 'should have private reader'
27
50
  alias_shared_examples 'has private reader', 'should have private reader'
51
+ alias_shared_examples 'should define private reader', 'should have private reader'
28
52
 
29
53
  shared_examples 'should have private writer' do |property|
30
54
  writer_name = :"#{property.to_s.sub(/=\z/, '')}="
@@ -37,28 +61,9 @@ module RSpec::SleepingKingStudios::Examples
37
61
  expect(object).to have_writer(writer_name, :allow_private => true)
38
62
  end # it
39
63
  end # shared_examples
64
+ alias_shared_examples 'defines private writer', 'should have private writer'
40
65
  alias_shared_examples 'has private writer', 'should have private writer'
41
-
42
- shared_examples 'should have private property' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION|
43
- writer_name = :"#{property.to_s.sub(/=\z/, '')}="
44
-
45
- it "should have private property :#{property}" do
46
- object = defined?(instance) ? instance : subject
47
- matcher = have_property(property, :allow_private => true)
48
-
49
- expect(object).not_to respond_to(property)
50
- expect(object).not_to respond_to(writer_name)
51
-
52
- if expected_value == UNDEFINED_VALUE_EXPECTATION
53
- expect(object).to matcher
54
- else
55
- expected_value = format_expected_value(expected_value)
56
-
57
- expect(object).to matcher.with_value(expected_value)
58
- end # if-else
59
- end # it
60
- end # shared_examples
61
- alias_shared_examples 'has private property', 'should have private property'
66
+ alias_shared_examples 'should define private writer', 'should have private writer'
62
67
  end # module
63
68
  end # module
64
69
  end # module
@@ -11,30 +11,56 @@ module RSpec::SleepingKingStudios::Examples
11
11
  module Properties
12
12
  extend RSpec::SleepingKingStudios::Concerns::SharedExampleGroup
13
13
 
14
- shared_examples 'should have reader' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION, allow_private: false|
15
- it "should have reader :#{property}" do
14
+ shared_examples 'should have property' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION, allow_private: false|
15
+ it "should have property :#{property}" do
16
16
  object = defined?(instance) ? instance : subject
17
- matcher = have_reader(property, :allow_private => allow_private)
17
+ matcher = have_property(property, :allow_private => allow_private)
18
18
 
19
19
  if expected_value == UNDEFINED_VALUE_EXPECTATION
20
- expect(object).to matcher
20
+ if allow_private
21
+ expect(object).to have_property(property, allow_private: true)
22
+ else
23
+ expect(object).to have_property(property)
24
+ end
21
25
  else
22
26
  expected_value = format_expected_value(expected_value)
23
27
 
24
- expect(object).to matcher.with_value(expected_value)
28
+ if allow_private
29
+ expect(object).to have_property(property, allow_private: true).with_value(expected_value)
30
+ else
31
+ expect(object).to have_property(property).with_value(expected_value)
32
+ end
25
33
  end # if-else
26
34
  end # it
27
35
  end # shared_examples
28
- alias_shared_examples 'has reader', 'should have reader'
36
+ alias_shared_examples 'defines property', 'should have property'
37
+ alias_shared_examples 'has property', 'should have property'
38
+ alias_shared_examples 'should define property', 'should have property'
29
39
 
30
- shared_examples 'should not have reader' do |property, allow_private: false|
31
- it "should not have reader :#{property}" do
32
- object = defined?(instance) ? instance : subject
40
+ shared_examples 'should have reader' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION, allow_private: false|
41
+ it "should have reader :#{property}" do
42
+ object = defined?(instance) ? instance : subject
33
43
 
34
- expect(object).not_to have_reader(property, :allow_private => allow_private)
44
+ if expected_value == UNDEFINED_VALUE_EXPECTATION
45
+ if allow_private
46
+ expect(object).to have_reader(property, allow_private: true)
47
+ else
48
+ expect(object).to have_reader(property)
49
+ end
50
+ else
51
+ expected_value = format_expected_value(expected_value)
52
+
53
+ if allow_private
54
+ expect(object).to have_reader(property, allow_private: true).with_value(expected_value)
55
+ else
56
+ expect(object).to have_reader(property).with_value(expected_value)
57
+ end
58
+ end # if-else
35
59
  end # it
36
60
  end # shared_examples
37
- alias_shared_examples 'does not have reader', 'should not have reader'
61
+ alias_shared_examples 'defines reader', 'should have reader'
62
+ alias_shared_examples 'has reader', 'should have reader'
63
+ alias_shared_examples 'should define reader', 'should have reader'
38
64
 
39
65
  shared_examples 'should have writer' do |property, allow_private: false|
40
66
  writer_name = property.to_s.sub /\=\z/, ''
@@ -45,7 +71,20 @@ module RSpec::SleepingKingStudios::Examples
45
71
  expect(object).to have_writer(property, :allow_private => allow_private)
46
72
  end # it
47
73
  end # shared_examples
74
+ alias_shared_examples 'defines writer', 'should have writer'
48
75
  alias_shared_examples 'has writer', 'should have writer'
76
+ alias_shared_examples 'should define writer', 'should have writer'
77
+
78
+ shared_examples 'should not have reader' do |property, allow_private: false|
79
+ it "should not have reader :#{property}" do
80
+ object = defined?(instance) ? instance : subject
81
+
82
+ expect(object).not_to have_reader(property, :allow_private => allow_private)
83
+ end # it
84
+ end # shared_examples
85
+ alias_shared_examples 'does not define reader', 'should not have reader'
86
+ alias_shared_examples 'does not have reader', 'should not have reader'
87
+ alias_shared_examples 'should not define reader', 'should not have reader'
49
88
 
50
89
  shared_examples 'should not have writer' do |property, allow_private: false|
51
90
  writer_name = property.to_s.sub /\=\z/, ''
@@ -56,23 +95,9 @@ module RSpec::SleepingKingStudios::Examples
56
95
  expect(object).not_to have_writer(property, :allow_private => allow_private)
57
96
  end # it
58
97
  end # shared_examples
98
+ alias_shared_examples 'does not define writer', 'should not have writer'
59
99
  alias_shared_examples 'does not have writer', 'should not have writer'
60
-
61
- shared_examples 'should have property' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION, allow_private: false|
62
- it "should have property :#{property}" do
63
- object = defined?(instance) ? instance : subject
64
- matcher = have_property(property, :allow_private => allow_private)
65
-
66
- if expected_value == UNDEFINED_VALUE_EXPECTATION
67
- expect(object).to matcher
68
- else
69
- expected_value = format_expected_value(expected_value)
70
-
71
- expect(object).to matcher.with_value(expected_value)
72
- end # if-else
73
- end # it
74
- end # shared_examples
75
- alias_shared_examples 'has property', 'should have property'
100
+ alias_shared_examples 'should not define writer', 'should not have writer'
76
101
  end # module
77
102
  end # module
78
103
  end # module
@@ -0,0 +1,16 @@
1
+ require 'rspec/sleeping_king_studios/matchers/core/have_changed_matcher'
2
+ require 'rspec/sleeping_king_studios/matchers/macros'
3
+ require 'rspec/sleeping_king_studios/support/value_spy'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers::Macros
6
+ # @see RSpec::SleepingKingStudios::Matchers::Core::HaveChangedMatcher#matches?
7
+ def have_changed
8
+ RSpec::SleepingKingStudios::Matchers::Core::HaveChangedMatcher.new
9
+ end
10
+
11
+ # @see RSpec::SleepingKingStudios::Support::ValueSpy#initialize
12
+ def watch_value(object = nil, method_name = nil, &block)
13
+ RSpec::SleepingKingStudios::Support::ValueSpy
14
+ .new(object, method_name, &block)
15
+ end
16
+ end
@@ -0,0 +1,222 @@
1
+ require 'rspec/sleeping_king_studios/matchers/base_matcher'
2
+ require 'rspec/sleeping_king_studios/matchers/core'
3
+ require 'rspec/sleeping_king_studios/support/value_spy'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers::Core
6
+ DEFAULT_VALUE = Object.new.freeze
7
+ private_constant :DEFAULT_VALUE
8
+
9
+ # Matcher for testing the change in a value.
10
+ #
11
+ # @since 2.4.0
12
+ class HaveChangedMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
13
+ def initialize
14
+ super
15
+
16
+ @expected_initial_value = DEFAULT_VALUE
17
+ @expected_current_value = DEFAULT_VALUE
18
+ end
19
+
20
+ # Creates an difference expectation between the initial and current values.
21
+ # The matcher will subtract the current value from the initial value and
22
+ # compare the result with the specified value.
23
+ #
24
+ # @param [Object] difference The expected difference between the initial
25
+ # value and the current value.
26
+ #
27
+ # @return [HaveChangedMatcher] the matcher instance.
28
+ def by(difference)
29
+ @expected_difference = difference
30
+
31
+ self
32
+ end
33
+
34
+ # (see BaseMatcher#description)
35
+ def description
36
+ desc = 'have changed'
37
+
38
+ unless @expected_initial_value == DEFAULT_VALUE
39
+ desc << " from #{@expected_initial_value.inspect}"
40
+ end
41
+
42
+ if @expected_difference
43
+ desc << " by #{@expected_difference.inspect}"
44
+ end
45
+
46
+ unless @expected_current_value == DEFAULT_VALUE
47
+ desc << " to #{@expected_current_value.inspect}"
48
+ end
49
+
50
+ desc
51
+ end
52
+
53
+ # (see BaseMatcher#does_not_match?)
54
+ def does_not_match?(actual)
55
+ @actual = actual
56
+
57
+ unless actual.is_a?(RSpec::SleepingKingStudios::Support::ValueSpy)
58
+ raise ArgumentError, 'You must pass a value spy to `expect`.'
59
+ end
60
+
61
+ unless @expected_current_value == DEFAULT_VALUE
62
+ raise NotImplementedError,
63
+ "`expect().not_to have_changed().to()` is not supported"
64
+ end
65
+
66
+ if @expected_difference
67
+ raise NotImplementedError,
68
+ "`expect().not_to have_changed().by()` is not supported"
69
+ end
70
+
71
+ match_initial_value? && !value_has_changed?
72
+ end
73
+
74
+ # (see BaseMatcher#failure_message)
75
+ def failure_message
76
+ unless @match_initial_value.nil? || @match_initial_value
77
+ return "expected #{value_spy.description} to have initially " \
78
+ "been #{@expected_initial_value.inspect}, but was " \
79
+ "#{initial_value.inspect}"
80
+ end
81
+
82
+ message = "expected #{value_spy.description} to have changed"
83
+
84
+ if @expected_difference
85
+ message << " by #{@expected_difference.inspect}"
86
+ end
87
+
88
+ unless @expected_current_value == DEFAULT_VALUE
89
+ message << " to #{@expected_current_value.inspect}"
90
+ end
91
+
92
+ unless @match_difference.nil? || @match_difference
93
+ return message << ", but was changed by #{@actual_difference.inspect}"
94
+ end
95
+
96
+ unless @match_current_value.nil? || @match_current_value
97
+ return message << ", but is now #{current_value.inspect}"
98
+ end
99
+
100
+ message << ", but is still #{current_value.inspect}"
101
+
102
+ message
103
+ end
104
+
105
+ # (see BaseMatcher#failure_message_when_negated)
106
+ def failure_message_when_negated
107
+ unless @match_initial_value.nil? || @match_initial_value
108
+ return "expected #{value_spy.description} to have initially " \
109
+ "been #{@expected_initial_value.inspect}, but was " \
110
+ "#{initial_value.inspect}"
111
+ end
112
+
113
+ message = "expected #{value_spy.description} not to have changed"
114
+
115
+ message <<
116
+ ", but did change from #{initial_value.inspect} to " <<
117
+ current_value.inspect
118
+
119
+ message
120
+ end
121
+
122
+ # Creates an expectation on the initial value. The matcher will compare the
123
+ # initial value from the value spy with the specified value.
124
+ #
125
+ # @param [Object] value The expected initial value.
126
+ #
127
+ # @return [HaveChangedMatcher] the matcher instance.
128
+ def from(value)
129
+ @expected_initial_value = value
130
+
131
+ self
132
+ end
133
+
134
+ # Checks if the observed value has changed.
135
+ #
136
+ # @param [RSpec::SleepingKingStudios::Support::ValueSpy] actual The
137
+ # observed value.
138
+ #
139
+ # @return [Boolean] True if the observed value has changed, otherwise false.
140
+ #
141
+ # @raise ArgumentError unless the actual object is a value spy.
142
+ def matches?(actual)
143
+ super
144
+
145
+ unless actual.is_a?(RSpec::SleepingKingStudios::Support::ValueSpy)
146
+ raise ArgumentError, 'You must pass a value spy to `expect`.'
147
+ end
148
+
149
+ match_initial_value? &&
150
+ value_has_changed? &&
151
+ match_current_value? &&
152
+ match_difference?
153
+ end
154
+
155
+ # Creates an expectation on the current value. The matcher will compare the
156
+ # current value from the value spy with the specified value.
157
+ #
158
+ # @param [Object] value The expected current value.
159
+ #
160
+ # @return [HaveChangedMatcher] the matcher instance.
161
+ def to(value)
162
+ @expected_current_value = value
163
+
164
+ self
165
+ end
166
+
167
+ private
168
+
169
+ alias_method :value_spy, :actual
170
+
171
+ def current_value
172
+ value_spy.current_value
173
+ end
174
+
175
+ def initial_value
176
+ value_spy.initial_value
177
+ end
178
+
179
+ def match_current_value?
180
+ return @match_current_value unless @match_current_value.nil?
181
+
182
+ if @expected_current_value == DEFAULT_VALUE
183
+ return @match_current_value = true
184
+ end
185
+
186
+ @match_current_value = RSpec::Support::FuzzyMatcher.values_match?(
187
+ current_value,
188
+ @expected_current_value
189
+ )
190
+ end
191
+
192
+ def match_difference?
193
+ return @match_difference unless @match_difference.nil?
194
+
195
+ return @match_difference = true unless @expected_difference
196
+
197
+ @actual_difference = current_value - initial_value
198
+
199
+ @match_difference = RSpec::Support::FuzzyMatcher.values_match?(
200
+ @actual_difference,
201
+ @expected_difference
202
+ )
203
+ end
204
+
205
+ def match_initial_value?
206
+ return @match_initial_value unless @match_initial_value.nil?
207
+
208
+ if @expected_initial_value == DEFAULT_VALUE
209
+ return @match_initial_value = true
210
+ end
211
+
212
+ @match_initial_value = RSpec::Support::FuzzyMatcher.values_match?(
213
+ initial_value,
214
+ @expected_initial_value
215
+ )
216
+ end
217
+
218
+ def value_has_changed?
219
+ value_spy.changed?
220
+ end
221
+ end
222
+ end