rspec-sleeping_king_studios 2.4.1 → 2.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/DEVELOPMENT.md +17 -13
- data/README.md +62 -0
- data/lib/rspec/sleeping_king_studios/examples/rspec_matcher_examples.rb +4 -0
- data/lib/rspec/sleeping_king_studios/matchers/core/be_a_uuid.rb +17 -0
- data/lib/rspec/sleeping_king_studios/matchers/core/be_a_uuid_matcher.rb +81 -0
- data/lib/rspec/sleeping_king_studios/matchers/core/deep_match.rb +11 -0
- data/lib/rspec/sleeping_king_studios/matchers/core/deep_matcher.rb +219 -0
- data/lib/rspec/sleeping_king_studios/matchers/core/have_changed_matcher.rb +5 -3
- data/lib/rspec/sleeping_king_studios/support/value_spy.rb +32 -7
- data/lib/rspec/sleeping_king_studios/version.rb +9 -9
- metadata +29 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e854f91985c71006beaaa55711a807e4074b58a6a56e1740e85d76400bb5ad05
|
|
4
|
+
data.tar.gz: 0603c970cca0d9f995ef901ad6e98a844e3423a77bc25c9b74422f8d516f2aed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8f1a4abd6c237cc396fc955165b66b26387760d22ea361eceec439f8aa9148768fb4d0570daafa1bfb5e1f5e536c4642c634e7ebc2f82e7f4bb29bb6b201b2cd
|
|
7
|
+
data.tar.gz: b774a8555643bebcb1604576db9c12058ef27e93f3511e4ac7de80c7d87959a376f9c928c4705e8c3e161b856fe3b52ce504f861b33629997355c44a3bac115b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.5.0
|
|
4
|
+
|
|
5
|
+
Added support for Ruby 2.6, dropped support for Ruby 2.3.
|
|
6
|
+
|
|
7
|
+
### Matchers
|
|
8
|
+
|
|
9
|
+
Implemented the BeAUuidMatcher, which expects the value to be a UUID string.
|
|
10
|
+
|
|
11
|
+
Implemented the DeepMatcher, which recursively compares data structures.
|
|
12
|
+
|
|
13
|
+
expect(response).to deep_match(
|
|
14
|
+
status: 200,
|
|
15
|
+
body: {
|
|
16
|
+
order: {
|
|
17
|
+
id: an_instance_of(Integer),
|
|
18
|
+
total: '9.99'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
Improved the HaveChangedMatcher to check the before and after `hash` value. This detects when an object is replaced by different but equal object, or when the initial object is a nested data structure (e.g. an Array of Hashes) and the internal elements are modified.
|
|
24
|
+
|
|
25
|
+
Improved failure message of the HaveChangedMatcher when given a receiver and message.
|
|
26
|
+
|
|
3
27
|
## 2.4.1
|
|
4
28
|
|
|
5
29
|
Added support for RSpec 3.8.
|
data/DEVELOPMENT.md
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
# Development Notes
|
|
2
2
|
|
|
3
|
-
## Version 2.
|
|
3
|
+
## Version 2.5
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### Maintenance
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- Refactor all macro specs from spec/rspec/sleeping_king_studios/matchers/macros to the directories corresponding to the source files.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Version 2.6
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- Also alias shared examples.
|
|
13
|
-
- Alias `have_constant` as `define_constant`.
|
|
14
|
-
- Alias #immutable as #frozen.
|
|
15
|
-
- Also alias shared examples.
|
|
11
|
+
### Features - Matchers
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
- RespondToMatcher: |
|
|
14
|
+
update to match core respond_to matcher
|
|
15
|
+
- uses the signature from initialize to validate checks for new
|
|
16
|
+
- see https://github.com/rspec/rspec-expectations/blob/master/Changelog.md
|
|
17
|
+
subclass BeConstructibleMatcher from RespondTo ?
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## Version 2.6+
|
|
20
|
+
|
|
21
|
+
- DeepMatcher: |
|
|
22
|
+
- indifferent - symbol/string keys
|
|
23
|
+
- ordered - pre-sort arrays?
|
|
24
|
+
- only homogenous arrays?
|
|
25
|
+
- odd results unless equality comparison
|
|
20
26
|
|
|
21
27
|
## Version 3.0
|
|
22
28
|
|
|
@@ -58,8 +64,6 @@
|
|
|
58
64
|
|
|
59
65
|
- BeImmutableMatcher (NEW):
|
|
60
66
|
- Implement be_immutable matcher.
|
|
61
|
-
- HaveChangedMatcher (NEW):
|
|
62
|
-
- Add spy+matcher for expect(my_object, :my_method).to have_changed ?
|
|
63
67
|
- RespondToMatcher:
|
|
64
68
|
- Implement RespondToMatcher#with_optional_keywords, #with_required_keywords.
|
|
65
69
|
- Implement RespondToMatcher#with_at_least(N).arguments, equivalent to with(N).arguments.and_unlimited_arguments.
|
data/README.md
CHANGED
|
@@ -447,6 +447,22 @@ Checks if the object aliases the specified method with the specified other name.
|
|
|
447
447
|
|
|
448
448
|
* **`#as`:** Required. Expects one String or Symbol, which is the name of the generated method.
|
|
449
449
|
|
|
450
|
+
#### `#be_a_uuid` Matcher
|
|
451
|
+
|
|
452
|
+
require 'rspec/sleeping_king_studios/matchers/core/be_a_uuid'
|
|
453
|
+
|
|
454
|
+
**Aliases:** `#a_uuid`.
|
|
455
|
+
|
|
456
|
+
**How To Use:**
|
|
457
|
+
|
|
458
|
+
# With an object comparison.
|
|
459
|
+
expect(string).to be_a_uuid
|
|
460
|
+
|
|
461
|
+
# Inside a composable matcher.
|
|
462
|
+
expect(array).to include(a_uuid)
|
|
463
|
+
|
|
464
|
+
**Parameters:** None.
|
|
465
|
+
|
|
450
466
|
#### `#be_boolean` Matcher
|
|
451
467
|
|
|
452
468
|
require 'rspec/sleeping_king_studios/matchers/core/be_boolean'
|
|
@@ -488,6 +504,52 @@ Verifies that the actual object can be constructed using `::new`. Can take an op
|
|
|
488
504
|
* **`#with_keywords`:** (also `and_keywords`) Expects one or more String or Symbol arguments. Verifies that the class's constructor accepts each provided keyword or has a variadic keyword of the form `**params`. As of 2.1.0 and required keywords, verifies that all required keywords are provided.
|
|
489
505
|
* **`#with_arbitrary_keywords`:** (also `and_arbitrary_keywords`) No parameters. Verifies that the class's constructor accepts any keyword arguments via a variadic keyword of the form `**params`.
|
|
490
506
|
|
|
507
|
+
#### `#deep_match` Matcher
|
|
508
|
+
|
|
509
|
+
require 'rspec/sleeping_king_studios/matchers/core/deep_match'
|
|
510
|
+
|
|
511
|
+
Performs a recursive comparison between two object or data structures. Also supports using RSpec matchers as values in the expected object.
|
|
512
|
+
|
|
513
|
+
**How To Use:**
|
|
514
|
+
|
|
515
|
+
expected = {
|
|
516
|
+
status: 200,
|
|
517
|
+
body: {
|
|
518
|
+
order: {
|
|
519
|
+
id: an_instance_of(Integer),
|
|
520
|
+
total: '9.99'
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
expect(response).to deep_match(expected)
|
|
525
|
+
|
|
526
|
+
When the value does not match the expectation, the failure message will provide a detailed diff showing added, missing, and changed values.
|
|
527
|
+
|
|
528
|
+
response = {
|
|
529
|
+
status: 400,
|
|
530
|
+
body: {
|
|
531
|
+
order: {
|
|
532
|
+
fulfilled: false,
|
|
533
|
+
total: '19.99'
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
errors: ['Insufficient funds']
|
|
537
|
+
}
|
|
538
|
+
expect(response).to deep_match(expected)
|
|
539
|
+
# Failure/Error: expect(response).to deep_match(expected)
|
|
540
|
+
#
|
|
541
|
+
# expected: == {:body=>{:order=>{:id=>an instance of Integer, :total=>"9.99"}}, :status=>200}
|
|
542
|
+
# got: {:status=>400, :body=>{:order=>{:fulfilled=>false, :total=>"19.99"}}, :errors=>["Insufficient funds"]}
|
|
543
|
+
#
|
|
544
|
+
# (compared using HashDiff)
|
|
545
|
+
#
|
|
546
|
+
# Diff:
|
|
547
|
+
# + :body.:order.:fulfilled => got false
|
|
548
|
+
# - :body.:order.:id => expected an instance of Integer
|
|
549
|
+
# ~ :body.:order.:total => expected "9.99", got "19.99"
|
|
550
|
+
# + :errors => got ["Insufficient funds"]
|
|
551
|
+
# ~ :status => expected 200, got 400
|
|
552
|
+
|
|
491
553
|
#### `#delegate_method` Matcher
|
|
492
554
|
|
|
493
555
|
require 'rspec/sleeping_king_studios/matchers/core/delegate_method'
|
|
@@ -29,6 +29,10 @@ module RSpec::SleepingKingStudios::Examples::RSpecMatcherExamples
|
|
|
29
29
|
end # when
|
|
30
30
|
end # method compare_message
|
|
31
31
|
|
|
32
|
+
private def format_expected(object)
|
|
33
|
+
RSpec::Support::ObjectFormatter.format(object)
|
|
34
|
+
end
|
|
35
|
+
|
|
32
36
|
private def handle_missing_failure_message message
|
|
33
37
|
case config.examples.handle_missing_failure_message_with
|
|
34
38
|
when :pending
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literals: true
|
|
2
|
+
|
|
3
|
+
require 'rspec/sleeping_king_studios/matchers/core/be_a_uuid_matcher'
|
|
4
|
+
require 'rspec/sleeping_king_studios/matchers/macros'
|
|
5
|
+
|
|
6
|
+
module RSpec::SleepingKingStudios::Matchers::Macros
|
|
7
|
+
# @see RSpec::SleepingKingStudios::Matchers::Core::BeAUuidMatcher#matches?
|
|
8
|
+
def be_a_uuid
|
|
9
|
+
RSpec::SleepingKingStudios::Matchers::Core::BeAUuidMatcher.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @!method a_uuid
|
|
13
|
+
# @see RSpec::SleepingKingStudios::Matchers::Core::BeBooleanMatcher#matches?
|
|
14
|
+
alias_matcher :a_uuid, :be_a_uuid do |description|
|
|
15
|
+
'a UUID'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literals: true
|
|
2
|
+
|
|
3
|
+
require 'rspec/sleeping_king_studios/matchers/base_matcher'
|
|
4
|
+
require 'rspec/sleeping_king_studios/matchers/core'
|
|
5
|
+
|
|
6
|
+
module RSpec::SleepingKingStudios::Matchers::Core
|
|
7
|
+
# Matcher for testing whether an object is a UUID string.
|
|
8
|
+
#
|
|
9
|
+
# @since 2.5.0
|
|
10
|
+
class BeAUuidMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
|
|
11
|
+
# (see BaseMatcher#description)
|
|
12
|
+
def description
|
|
13
|
+
'be a UUID'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# (see BaseMatcher#failure_message)
|
|
17
|
+
def failure_message
|
|
18
|
+
message = super() + ', but '
|
|
19
|
+
|
|
20
|
+
return message + 'was not a String' unless string?
|
|
21
|
+
|
|
22
|
+
return message + 'was too short' if too_short?
|
|
23
|
+
|
|
24
|
+
return message + 'was too long' if too_long?
|
|
25
|
+
|
|
26
|
+
return message + 'has invalid characters' if invalid_characters?
|
|
27
|
+
|
|
28
|
+
return message + 'the format is invalid' unless valid_format?
|
|
29
|
+
|
|
30
|
+
message
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Checks if the object is a UUID string.
|
|
34
|
+
#
|
|
35
|
+
# @param [Object] actual The object to check.
|
|
36
|
+
#
|
|
37
|
+
# @return [Boolean] true if the object is a string with the correct format;
|
|
38
|
+
# otherwise false.
|
|
39
|
+
def matches?(actual)
|
|
40
|
+
super
|
|
41
|
+
|
|
42
|
+
string? && valid_length? && valid_characters? && valid_format?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def invalid_characters?
|
|
48
|
+
@invalid_characters ||= @actual.match?(/[^A-Fa-f0-9\-]/)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def string?
|
|
52
|
+
@string ||= @actual.is_a?(String)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def too_long?
|
|
56
|
+
@too_long ||= @actual.length > 36
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def too_short?
|
|
60
|
+
@too_short ||= @actual.length < 36
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def uuid_format
|
|
64
|
+
chars = '[A-Fa-f0-9\-]'
|
|
65
|
+
|
|
66
|
+
/\A#{chars}{8}-#{chars}{4}-#{chars}{4}-#{chars}{4}-#{chars}{12}\z/
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def valid_characters?
|
|
70
|
+
!invalid_characters?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def valid_format?
|
|
74
|
+
@valid_format || @actual.match?(uuid_format)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def valid_length?
|
|
78
|
+
!too_short? && !too_long?
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literals: true
|
|
2
|
+
|
|
3
|
+
require 'rspec/sleeping_king_studios/matchers/core/deep_matcher'
|
|
4
|
+
require 'rspec/sleeping_king_studios/matchers/macros'
|
|
5
|
+
|
|
6
|
+
module RSpec::SleepingKingStudios::Matchers::Macros
|
|
7
|
+
# @see RSpec::SleepingKingStudios::Matchers::Core::BeBooleanMatcher#matches?
|
|
8
|
+
def deep_match(expected)
|
|
9
|
+
RSpec::SleepingKingStudios::Matchers::Core::DeepMatcher.new(expected)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# frozen_string_literals: true
|
|
2
|
+
|
|
3
|
+
require 'hashdiff'
|
|
4
|
+
|
|
5
|
+
require 'rspec/sleeping_king_studios/matchers/base_matcher'
|
|
6
|
+
require 'rspec/sleeping_king_studios/matchers/core'
|
|
7
|
+
|
|
8
|
+
module RSpec::SleepingKingStudios::Matchers::Core
|
|
9
|
+
# Matcher for performing a deep comparison between two objects.
|
|
10
|
+
#
|
|
11
|
+
# @since 2.5.0
|
|
12
|
+
class DeepMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
|
|
13
|
+
# @param [Object] expected The expected object.
|
|
14
|
+
def initialize(expected)
|
|
15
|
+
@expected = expected
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# (see BaseMatcher#description)
|
|
19
|
+
def description
|
|
20
|
+
"match #{format_expected(@expected)}"
|
|
21
|
+
end # method description
|
|
22
|
+
|
|
23
|
+
# Inverse of #matches? method.
|
|
24
|
+
#
|
|
25
|
+
# @param [Object] actual The object to check.
|
|
26
|
+
#
|
|
27
|
+
# @return [Boolean] true if the actual object does not match the
|
|
28
|
+
# expectation, otherwise true.
|
|
29
|
+
#
|
|
30
|
+
# @see #matches?
|
|
31
|
+
def does_not_match? actual
|
|
32
|
+
super
|
|
33
|
+
|
|
34
|
+
if matcher?(@expected)
|
|
35
|
+
delegate_to_negated_matcher(@expected)
|
|
36
|
+
elsif @expected.is_a?(Array) && actual.is_a?(Array)
|
|
37
|
+
diff_arrays_negated
|
|
38
|
+
elsif @expected.is_a?(Hash) && actual.is_a?(Hash)
|
|
39
|
+
diff_hashes_negated
|
|
40
|
+
else
|
|
41
|
+
delegate_to_negated_matcher(equality_matcher)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
!@matches
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# (see BaseMatcher#failure_message)
|
|
48
|
+
def failure_message
|
|
49
|
+
@failure_message
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# (see BaseMatcher#failure_message_when_negated)
|
|
53
|
+
def failure_message_when_negated
|
|
54
|
+
@failure_message_when_negated
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Performs a deep comparison between the actual object and the expected
|
|
58
|
+
# object. The type of comparison depends on the type of the expected object:
|
|
59
|
+
#
|
|
60
|
+
# - If the expected object is an RSpec matcher, the #matches? method on the
|
|
61
|
+
# matcher is called with the expected object.
|
|
62
|
+
# - If the expected object is an Array, then each item is compared based on
|
|
63
|
+
# the type of the expected item.
|
|
64
|
+
# - If the expected object is a Hash, then the keys must match and each
|
|
65
|
+
# value is compared based on the type of the expected value.
|
|
66
|
+
# - Otherwise, the two objects are compared using an equality comparison.
|
|
67
|
+
#
|
|
68
|
+
# @param [Object] actual The object to check.
|
|
69
|
+
#
|
|
70
|
+
# @return [Boolean] true if the actual object matches the expectation,
|
|
71
|
+
# otherwise false.
|
|
72
|
+
def matches?(actual)
|
|
73
|
+
super
|
|
74
|
+
|
|
75
|
+
if matcher?(@expected)
|
|
76
|
+
delegate_to_matcher(@expected)
|
|
77
|
+
elsif @expected.is_a?(Array) && actual.is_a?(Array)
|
|
78
|
+
diff_arrays
|
|
79
|
+
elsif @expected.is_a?(Hash) && actual.is_a?(Hash)
|
|
80
|
+
diff_hashes
|
|
81
|
+
else
|
|
82
|
+
delegate_to_matcher(equality_matcher)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@matches
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def compare_arrays(expected, actual)
|
|
91
|
+
compare_hashes({ _ary: expected }, { _ary: actual })
|
|
92
|
+
.map { |(char, path, *values)| [char, path[1..-1], *values] }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def compare_hashes(expected, actual)
|
|
96
|
+
HashDiff.diff(expected, actual, array_path: true, use_lcs: false) \
|
|
97
|
+
do |path, exp, act|
|
|
98
|
+
# Handle missing keys with matcher values.
|
|
99
|
+
next nil unless nested_key?(actual, path)
|
|
100
|
+
|
|
101
|
+
next exp.matches?(act) if matcher?(exp)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def delegate_to_matcher(matcher)
|
|
106
|
+
@matches = matcher.matches?(actual)
|
|
107
|
+
|
|
108
|
+
return if @matches
|
|
109
|
+
|
|
110
|
+
@failure_message = matcher.failure_message
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def delegate_to_negated_matcher(matcher)
|
|
114
|
+
@matches =
|
|
115
|
+
if matcher.respond_to?(:does_not_match?)
|
|
116
|
+
!matcher.does_not_match?(actual)
|
|
117
|
+
else
|
|
118
|
+
matcher.matches?(actual)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
return unless @matches
|
|
122
|
+
|
|
123
|
+
@failure_message_when_negated = matcher.failure_message_when_negated
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def diff_arrays
|
|
127
|
+
diff = compare_arrays(@expected, actual)
|
|
128
|
+
@matches = diff.empty?
|
|
129
|
+
|
|
130
|
+
@failure_message = format_message(diff)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def diff_arrays_negated
|
|
134
|
+
diff = compare_arrays(@expected, actual)
|
|
135
|
+
@matches = diff.empty?
|
|
136
|
+
|
|
137
|
+
@failure_message_when_negated =
|
|
138
|
+
"`expect(#{format_expected(@expected)}).not_to be == #{actual.inspect}`"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def diff_hashes
|
|
142
|
+
diff = compare_hashes(@expected, actual)
|
|
143
|
+
@matches = diff.empty?
|
|
144
|
+
|
|
145
|
+
@failure_message = format_message(diff)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def diff_hashes_negated
|
|
149
|
+
diff = compare_hashes(@expected, actual)
|
|
150
|
+
@matches = diff.empty?
|
|
151
|
+
|
|
152
|
+
@failure_message_when_negated =
|
|
153
|
+
"`expect(#{format_expected(@expected)}).not_to be == #{actual.inspect}`"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def equality_matcher
|
|
157
|
+
matchers_delegate.be == @expected
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def format_diff(diff)
|
|
161
|
+
diff
|
|
162
|
+
.sort_by { |(char, path, *_values)| [path.map(&:to_s)] }
|
|
163
|
+
.map { |item| format_diff_item(*item) }
|
|
164
|
+
.join "\n"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def format_diff_item(char, path, *values)
|
|
168
|
+
"#{char} #{format_diff_path(path)} => #{format_diff_values(char, values)}"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def format_diff_path(path)
|
|
172
|
+
path.map(&:inspect).join('.')
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def format_diff_values(char, values)
|
|
176
|
+
case char
|
|
177
|
+
when '-'
|
|
178
|
+
"expected #{format_expected(values.first)}"
|
|
179
|
+
when '~'
|
|
180
|
+
"expected #{format_expected(values.first)}, got #{values.last.inspect}"
|
|
181
|
+
when '+'
|
|
182
|
+
"got #{values.last.inspect}"
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def format_expected(object)
|
|
187
|
+
RSpec::Support::ObjectFormatter.format(object)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def format_message(diff)
|
|
191
|
+
"expected: == #{format_expected(@expected)}\n" \
|
|
192
|
+
" got: #{@actual.inspect}\n" \
|
|
193
|
+
"\n" \
|
|
194
|
+
"(compared using HashDiff)\n" \
|
|
195
|
+
"\n" \
|
|
196
|
+
"Diff:\n" \
|
|
197
|
+
"#{format_diff(diff)}"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def matcher?(object)
|
|
201
|
+
%i[description failure_message failure_message_when_negated matches?]
|
|
202
|
+
.all? { |method_name| object.respond_to?(method_name) }
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def matchers_delegate
|
|
206
|
+
Object.new.extend RSpec::Matchers
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def nested_key?(object, path)
|
|
210
|
+
key = path.last
|
|
211
|
+
object = object.dig(*path[0...-1]) if path.size > 1
|
|
212
|
+
|
|
213
|
+
return object.key?(key) if object.is_a?(Hash)
|
|
214
|
+
return object.size > key if object.is_a?(Array)
|
|
215
|
+
|
|
216
|
+
false
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literals: true
|
|
2
|
+
|
|
1
3
|
require 'rspec/sleeping_king_studios/matchers/base_matcher'
|
|
2
4
|
require 'rspec/sleeping_king_studios/matchers/core'
|
|
3
5
|
require 'rspec/sleeping_king_studios/support/value_spy'
|
|
@@ -76,7 +78,7 @@ module RSpec::SleepingKingStudios::Matchers::Core
|
|
|
76
78
|
unless @match_initial_value.nil? || @match_initial_value
|
|
77
79
|
return "expected #{value_spy.description} to have initially " \
|
|
78
80
|
"been #{@expected_initial_value.inspect}, but was " \
|
|
79
|
-
"#{
|
|
81
|
+
"#{value_spy.initial_inspect}"
|
|
80
82
|
end
|
|
81
83
|
|
|
82
84
|
message = "expected #{value_spy.description} to have changed"
|
|
@@ -107,13 +109,13 @@ module RSpec::SleepingKingStudios::Matchers::Core
|
|
|
107
109
|
unless @match_initial_value.nil? || @match_initial_value
|
|
108
110
|
return "expected #{value_spy.description} to have initially " \
|
|
109
111
|
"been #{@expected_initial_value.inspect}, but was " \
|
|
110
|
-
"#{
|
|
112
|
+
"#{value_spy.initial_inspect}"
|
|
111
113
|
end
|
|
112
114
|
|
|
113
115
|
message = "expected #{value_spy.description} not to have changed"
|
|
114
116
|
|
|
115
117
|
message <<
|
|
116
|
-
", but did change from #{
|
|
118
|
+
", but did change from #{value_spy.initial_inspect} to " <<
|
|
117
119
|
current_value.inspect
|
|
118
120
|
|
|
119
121
|
message
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literals: true
|
|
2
|
+
|
|
1
3
|
require 'rspec/sleeping_king_studios/support'
|
|
2
4
|
|
|
3
5
|
module RSpec::SleepingKingStudios::Support
|
|
@@ -23,8 +25,8 @@ module RSpec::SleepingKingStudios::Support
|
|
|
23
25
|
# value.initial_value #=> 4
|
|
24
26
|
# value.current_value #=> 3
|
|
25
27
|
class ValueSpy
|
|
26
|
-
# @overload initialize(
|
|
27
|
-
# @param [Object]
|
|
28
|
+
# @overload initialize(receiver, method_name)
|
|
29
|
+
# @param [Object] receiver The object to watch.
|
|
28
30
|
#
|
|
29
31
|
# @param [Symbol, String] method_name The name of the method to watch.
|
|
30
32
|
#
|
|
@@ -32,23 +34,34 @@ module RSpec::SleepingKingStudios::Support
|
|
|
32
34
|
# @yield The value to watch. The block will be called each time the value
|
|
33
35
|
# is requested, and the return value of the block will be given as the
|
|
34
36
|
# current value.
|
|
35
|
-
def initialize(
|
|
37
|
+
def initialize(receiver = nil, method_name = nil, &block)
|
|
36
38
|
@observed_block = if block_given?
|
|
37
39
|
block
|
|
38
40
|
else
|
|
39
41
|
@method_name = method_name
|
|
40
42
|
|
|
41
|
-
-> {
|
|
43
|
+
-> { receiver.send(method_name) }
|
|
42
44
|
end
|
|
43
45
|
|
|
44
|
-
@
|
|
46
|
+
@receiver = receiver
|
|
47
|
+
@initial_hash = current_value.hash
|
|
48
|
+
@initial_inspect = current_value.inspect
|
|
49
|
+
@initial_value = current_value
|
|
45
50
|
end
|
|
46
51
|
|
|
52
|
+
# @return [Integer] the hash of the watched value at the time the spy was
|
|
53
|
+
# initialized.
|
|
54
|
+
attr_reader :initial_hash
|
|
55
|
+
|
|
56
|
+
# @return [String] the string representation of the watched value at the
|
|
57
|
+
# time the spy was initialized
|
|
58
|
+
attr_reader :initial_inspect
|
|
59
|
+
|
|
47
60
|
# @return [Object] the watched value at the time the spy was initialized.
|
|
48
61
|
attr_reader :initial_value
|
|
49
62
|
|
|
50
63
|
def changed?
|
|
51
|
-
|
|
64
|
+
initial_value != current_value || initial_hash != current_value.hash
|
|
52
65
|
end
|
|
53
66
|
|
|
54
67
|
# @return [Object] the watched value when #current_value is called.
|
|
@@ -61,7 +74,19 @@ module RSpec::SleepingKingStudios::Support
|
|
|
61
74
|
def description
|
|
62
75
|
return 'result' unless @method_name
|
|
63
76
|
|
|
64
|
-
|
|
77
|
+
format_message
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
attr_reader :method_name
|
|
83
|
+
|
|
84
|
+
attr_reader :receiver
|
|
85
|
+
|
|
86
|
+
def format_message
|
|
87
|
+
return "#{receiver}.#{method_name}" if receiver.is_a?(Module)
|
|
88
|
+
|
|
89
|
+
"#{receiver.class}##{method_name}"
|
|
65
90
|
end
|
|
66
91
|
end
|
|
67
92
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literals: true
|
|
2
2
|
|
|
3
3
|
module RSpec
|
|
4
4
|
module SleepingKingStudios
|
|
@@ -11,13 +11,13 @@ module RSpec
|
|
|
11
11
|
# Major version.
|
|
12
12
|
MAJOR = 2
|
|
13
13
|
# Minor version.
|
|
14
|
-
MINOR =
|
|
14
|
+
MINOR = 5
|
|
15
15
|
# Patch version.
|
|
16
|
-
PATCH =
|
|
16
|
+
PATCH = 0
|
|
17
17
|
# Prerelease version.
|
|
18
|
-
PRERELEASE =
|
|
18
|
+
PRERELEASE = :rc
|
|
19
19
|
# Build metadata.
|
|
20
|
-
BUILD =
|
|
20
|
+
BUILD = 0
|
|
21
21
|
|
|
22
22
|
# Generates the gem version string from the Version constants.
|
|
23
23
|
#
|
|
@@ -36,9 +36,9 @@ module RSpec
|
|
|
36
36
|
str << ".#{build}" unless build.nil? || (build.respond_to?(:empty?) && build.empty?)
|
|
37
37
|
|
|
38
38
|
str
|
|
39
|
-
end
|
|
40
|
-
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
41
|
|
|
42
42
|
VERSION = Version.to_gem_version
|
|
43
|
-
end
|
|
44
|
-
end
|
|
43
|
+
end
|
|
44
|
+
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rspec-sleeping_king_studios
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.5.0.rc.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rob "Merlin" Smith
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2019-02-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: hashdiff
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.3.8
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.3.8
|
|
13
27
|
- !ruby/object:Gem::Dependency
|
|
14
28
|
name: rspec
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -84,22 +98,22 @@ dependencies:
|
|
|
84
98
|
name: thor
|
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
|
86
100
|
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0.20'
|
|
90
101
|
- - ">="
|
|
91
102
|
- !ruby/object:Gem::Version
|
|
92
103
|
version: 0.19.4
|
|
104
|
+
- - "~>"
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: '0.20'
|
|
93
107
|
type: :development
|
|
94
108
|
prerelease: false
|
|
95
109
|
version_requirements: !ruby/object:Gem::Requirement
|
|
96
110
|
requirements:
|
|
97
|
-
- - "~>"
|
|
98
|
-
- !ruby/object:Gem::Version
|
|
99
|
-
version: '0.20'
|
|
100
111
|
- - ">="
|
|
101
112
|
- !ruby/object:Gem::Version
|
|
102
113
|
version: 0.19.4
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0.20'
|
|
103
117
|
- !ruby/object:Gem::Dependency
|
|
104
118
|
name: sleeping_king_studios-tasks
|
|
105
119
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -217,10 +231,14 @@ files:
|
|
|
217
231
|
- lib/rspec/sleeping_king_studios/matchers/core/alias_method.rb
|
|
218
232
|
- lib/rspec/sleeping_king_studios/matchers/core/alias_method_matcher.rb
|
|
219
233
|
- lib/rspec/sleeping_king_studios/matchers/core/all.rb
|
|
234
|
+
- lib/rspec/sleeping_king_studios/matchers/core/be_a_uuid.rb
|
|
235
|
+
- lib/rspec/sleeping_king_studios/matchers/core/be_a_uuid_matcher.rb
|
|
220
236
|
- lib/rspec/sleeping_king_studios/matchers/core/be_boolean.rb
|
|
221
237
|
- lib/rspec/sleeping_king_studios/matchers/core/be_boolean_matcher.rb
|
|
222
238
|
- lib/rspec/sleeping_king_studios/matchers/core/construct.rb
|
|
223
239
|
- lib/rspec/sleeping_king_studios/matchers/core/construct_matcher.rb
|
|
240
|
+
- lib/rspec/sleeping_king_studios/matchers/core/deep_match.rb
|
|
241
|
+
- lib/rspec/sleeping_king_studios/matchers/core/deep_matcher.rb
|
|
224
242
|
- lib/rspec/sleeping_king_studios/matchers/core/delegate_method.rb
|
|
225
243
|
- lib/rspec/sleeping_king_studios/matchers/core/delegate_method_matcher.rb
|
|
226
244
|
- lib/rspec/sleeping_king_studios/matchers/core/have_changed.rb
|
|
@@ -259,12 +277,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
259
277
|
version: '0'
|
|
260
278
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
261
279
|
requirements:
|
|
262
|
-
- - "
|
|
280
|
+
- - ">"
|
|
263
281
|
- !ruby/object:Gem::Version
|
|
264
|
-
version:
|
|
282
|
+
version: 1.3.1
|
|
265
283
|
requirements: []
|
|
266
|
-
|
|
267
|
-
rubygems_version: 2.7.6
|
|
284
|
+
rubygems_version: 3.0.1
|
|
268
285
|
signing_key:
|
|
269
286
|
specification_version: 4
|
|
270
287
|
summary: A collection of RSpec patches and custom matchers.
|