rspec-json_matchers 0.1.0.alpha.1 → 0.1.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.rubocop.yml +31 -0
- data/Gemfile +1 -1
- data/README.md +36 -0
- data/Rakefile +1 -1
- data/doc/Story.md +129 -0
- data/lib/rspec-json_matchers.rb +1 -1
- data/lib/rspec/json_matchers/comparers/abstract_comparer.rb +111 -77
- data/lib/rspec/json_matchers/comparers/comparison_result.rb +1 -1
- data/lib/rspec/json_matchers/comparers/exact_keys_comparer.rb +6 -6
- data/lib/rspec/json_matchers/comparers/include_keys_comparer.rb +5 -6
- data/lib/rspec/json_matchers/expectation.rb +81 -31
- data/lib/rspec/json_matchers/expectations/abstract.rb +4 -3
- data/lib/rspec/json_matchers/expectations/core.rb +12 -8
- data/lib/rspec/json_matchers/expectations/mixins/built_in.rb +25 -13
- data/lib/rspec/json_matchers/expectations/private.rb +40 -33
- data/lib/rspec/json_matchers/matchers.rb +3 -3
- data/lib/rspec/json_matchers/matchers/be_json_matcher.rb +16 -6
- data/lib/rspec/json_matchers/matchers/be_json_with_sizes_matcher.rb +4 -1
- data/lib/rspec/json_matchers/matchers/be_json_with_something_matcher.rb +51 -37
- data/lib/rspec/json_matchers/utils/collection_keys_extractor.rb +4 -3
- data/lib/rspec/json_matchers/utils/key_path/extraction.rb +149 -0
- data/lib/rspec/json_matchers/utils/key_path/path.rb +18 -12
- data/lib/rspec/json_matchers/version.rb +3 -1
- data/rspec-json_matchers.gemspec +7 -5
- metadata +7 -5
- data/lib/rspec/json_matchers/utils/key_path/extraction_result.rb +0 -22
- data/lib/rspec/json_matchers/utils/key_path/extractor.rb +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8a8d3fdb38106995f0116c157f8a02a915d97de
|
4
|
+
data.tar.gz: d11e9f4fcc661dbb02731398bf306f79304728e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b80c90b32ebd1caabda67697d3922c9085ab8fe680705fc77257bebdfffb6b046e48d9f23eefe0d6b4c31361e4215f4f9d35d1a27c10459ecd07a926e5e3862
|
7
|
+
data.tar.gz: cf832440789cd1f53e82c83bd32446519c2acd6e285da092962a96358676458716f5505a078da5bed0e0bbceb9fc77059aba61f8d3c601735b35218b37c98794
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Style/StringLiterals:
|
2
|
+
EnforcedStyle: double_quotes
|
3
|
+
|
4
|
+
Style/TrailingComma:
|
5
|
+
# If EnforcedStyleForMultiline is comma, the cop requires a comma after the
|
6
|
+
# last item of a list, but only for lists where each item is on its own line.
|
7
|
+
# If EnforcedStyleForMultiline is consistent_comma, the cop requires a comma
|
8
|
+
# after the last item of a list, for all lists.
|
9
|
+
EnforcedStyleForMultiline: comma
|
10
|
+
|
11
|
+
Style/SignalException:
|
12
|
+
EnforcedStyle: only_fail
|
13
|
+
|
14
|
+
# Multi-line method chaining should be done with leading dots.
|
15
|
+
Style/DotPosition:
|
16
|
+
EnforcedStyle: trailing
|
17
|
+
|
18
|
+
Style/MultilineOperationIndentation:
|
19
|
+
EnforcedStyle: indented
|
20
|
+
|
21
|
+
Style/AlignParameters:
|
22
|
+
EnforcedStyle: with_fixed_indentation
|
23
|
+
|
24
|
+
Style/ClosingParenthesisIndentation:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Style/FileName:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Style/PredicateName:
|
31
|
+
Enabled: false
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -18,6 +18,8 @@ This gem provides a collection of RSpec matchers for testing JSON data.
|
|
18
18
|
It aims to make JSON testing flexible & easier, especially for testing multiple properties.
|
19
19
|
It does not and will not have anything related to JSON Schema.
|
20
20
|
|
21
|
+
You can read [the story of this project](https://github.com/PikachuEXE/rspec-json_matchers/blob/master/doc/Story.md) if you have time.
|
22
|
+
|
21
23
|
## Installation
|
22
24
|
|
23
25
|
Add this line to your application's Gemfile:
|
@@ -402,6 +404,30 @@ specify do
|
|
402
404
|
end # => pass
|
403
405
|
|
404
406
|
|
407
|
+
# `NullableOf` is an expectation that works like `AnyOf`
|
408
|
+
# Except it always passes when the subject is `nil`
|
409
|
+
specify do
|
410
|
+
expect({a: 1}.to_json).to be_json.
|
411
|
+
with_content(a: expectations::NullableOf[1])
|
412
|
+
end # => pass
|
413
|
+
specify do
|
414
|
+
expect({a: 1}.to_json).to be_json.
|
415
|
+
with_content(a: expectations::NullableOf[0, 1, 2])
|
416
|
+
end # => pass
|
417
|
+
specify do
|
418
|
+
expect({a: 1}.to_json).to be_json.
|
419
|
+
with_content(a: expectations::NullableOf[false, expectations::Anything, false])
|
420
|
+
end # => pass
|
421
|
+
specify do
|
422
|
+
expect({a: 1}.to_json).to be_json.
|
423
|
+
with_content(a: expectations::NullableOf[false, false, false])
|
424
|
+
end # => fail
|
425
|
+
specify do
|
426
|
+
expect({a: nil}.to_json).to be_json.
|
427
|
+
with_content(a: expectations::NullableOf[false, false, false])
|
428
|
+
end # => fail
|
429
|
+
|
430
|
+
|
405
431
|
# `AnyOf` is an expectation that passes when **any** of "expectations" passed in
|
406
432
|
# "expects" the subject
|
407
433
|
# It will convert non `Expectation` objects into `Expectation` objects,
|
@@ -488,6 +514,16 @@ there is no such matcher.
|
|
488
514
|
Just use `be_json.with_content` with classes.
|
489
515
|
|
490
516
|
|
517
|
+
## Pitfalls
|
518
|
+
|
519
|
+
### Error message colorized output in RubyMine
|
520
|
+
|
521
|
+
Add something like
|
522
|
+
`-rawesome_print -e "AwesomePrint.defaults={plain: true}"` to `Ruby arguments`
|
523
|
+
for `Run/Debug Configurations => Defaults => RSpec`
|
524
|
+
That way you could keep the color when running `rspec` from console
|
525
|
+
|
526
|
+
|
491
527
|
## Contributing
|
492
528
|
|
493
529
|
1. Fork it ( https://github.com/PikachuEXE/rspec-json_matchers/fork )
|
data/Rakefile
CHANGED
data/doc/Story.md
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# Story of the project
|
2
|
+
This file describes the motive of building this project, alternatives and the future.
|
3
|
+
|
4
|
+
## Alternative projects that had been used before
|
5
|
+
The author of this project does his job as a developer mainly on a Ruby on Rails project, which contains endpoints returning responses with JSON data. And he uses RSpec (only) to write tests for those endpoints.
|
6
|
+
|
7
|
+
### `json_spec`
|
8
|
+
|
9
|
+
#### Usage
|
10
|
+
At first he was using [`json_spec`](https://github.com/collectiveidea/json_spec), which was good enough for a endpoints with limited number of properties (e.g. an `object` representing a "resource"). The main matcher methods used was:
|
11
|
+
- `have_json_path` (but actually not used that often)
|
12
|
+
- `have_json_type`
|
13
|
+
- `have_json_size`
|
14
|
+
|
15
|
+
#### Issues
|
16
|
+
However, when trying to create examples to verify the actual values of properties, he was unable to find a matcher method for it. Instead he has to use a "helper method" `parse_json` to parse JSON string into a Ruby `Hash` and extract the value from the sometimes deep-nested `Hash`.
|
17
|
+
|
18
|
+
Besides, when number of properties increases, it started to become annoying to duplicate & modify the examples for each of properties that requires testing.
|
19
|
+
|
20
|
+
### `airborne`
|
21
|
+
|
22
|
+
#### Usage
|
23
|
+
To solve the two issues above, [`airborne`](https://github.com/brooklynDev/airborne) is used. It covers the previous project's features:
|
24
|
+
- `expect_json_types` => `have_json_type`
|
25
|
+
- `expect_json_keys` => `have_json_path`
|
26
|
+
- `expect_json_sizes` => `have_json_size`
|
27
|
+
|
28
|
+
It also solve the two issues of previous project:
|
29
|
+
- It has an additional method `expect_json`
|
30
|
+
This solves the lack of way of verifying the actual values of properties
|
31
|
+
- It allows (and maybe only accepts) `Hash` style of expectation
|
32
|
+
And also accepts an optional "path" to avoid writing deep-nested `Hash` in examples
|
33
|
+
This solves the need to duplicate examples to verify multiple properties of an `object`.
|
34
|
+
|
35
|
+
It has slightly more flexible for type matching, with the following options (copied from its README):
|
36
|
+
* `:int` or `:integer`
|
37
|
+
* `:float`
|
38
|
+
* `:bool` or `:boolean`
|
39
|
+
* `:string`
|
40
|
+
* `:date`
|
41
|
+
* `:object`
|
42
|
+
* `:null`
|
43
|
+
* `:array`
|
44
|
+
* `:array_of_integers` or `:array_of_ints`
|
45
|
+
* `:array_of_floats`
|
46
|
+
* `:array_of_strings`
|
47
|
+
* `:array_of_booleans` or `:array_of_bools`
|
48
|
+
* `:array_of_objects`
|
49
|
+
* `:array_of_arrays`
|
50
|
+
If the properties are optional and may not appear in the response, you can append `_or_null` to the types above.
|
51
|
+
|
52
|
+
#### Issues
|
53
|
+
Sometimes when the symbol was misspelled, a strange error would be raised (seems fixed in recent versions).
|
54
|
+
|
55
|
+
Also `:null` was only added recently, which indicates another issue: the lack of possibility to extend the project without raising Pull Requests. This issue is properly not very serious when the project is actively maintained and still easy enough to add changes to it quickly & cleanly (without monkey-patching).
|
56
|
+
|
57
|
+
|
58
|
+
### Other Project
|
59
|
+
To solve the issues of `airborne`, the author first found other gems, but there are other issues:
|
60
|
+
#### [`rspec-json_matcher`](https://github.com/r7kamura/rspec-json_matcher)
|
61
|
+
|
62
|
+
- It lacks the ability to verify the following things easily
|
63
|
+
- number elements of `array`
|
64
|
+
- the object type/value with logic "or"
|
65
|
+
|
66
|
+
It is possible with the use of `Proc` since the project use `#===` and `Proc#===` is similar to `Proc#call`) but not quite "easy" (requires much typing)
|
67
|
+
- The method focusing non built-in "expectation" could lead to silent false positive results, since the definition of `#===` is unclear, it was only used to allow:
|
68
|
+
- `Regexp`
|
69
|
+
- `Proc`
|
70
|
+
- `Class`
|
71
|
+
- `Range` (not even mentioned in its README)
|
72
|
+
|
73
|
+
There are other classes that define `#===` but with different meanings, remembering/checking the definition of `#===` of classes of custom objects before putting those object as "expectations" (to ensure no false positive result) is not convenient and easy to be forgotten.
|
74
|
+
|
75
|
+
#### [`match_json`](https://github.com/WhitePayments/match_json)
|
76
|
+
- Required to type JSON String as expectations
|
77
|
+
- Lack of ability to verify
|
78
|
+
- the number of elements of `array`
|
79
|
+
- the data type
|
80
|
+
|
81
|
+
It was discovered during the development of this project.
|
82
|
+
|
83
|
+
#### [`json-matchers`](https://github.com/seanpdoyle/json-matchers)
|
84
|
+
It only supports [JSON Schema](http://json-schema.org/).
|
85
|
+
Using JSON Schema to validate JSON lacks the ability to verify the value of property exactly for all data types.
|
86
|
+
Also JSON Schema is not a well known standard and lacks stability (the homepage said it's still a draft)
|
87
|
+
|
88
|
+
#### [`json-schema`](https://github.com/ruby-json-schema/json-schema)
|
89
|
+
Same as `json-matchers`
|
90
|
+
|
91
|
+
|
92
|
+
## This Project
|
93
|
+
|
94
|
+
### Objectives
|
95
|
+
- To implement as many features from previous projects as possible
|
96
|
+
- To solve most issues found in previous projects
|
97
|
+
|
98
|
+
### Development Path
|
99
|
+
- First this project was developed following the pattern of `rspec-json_matcher`, as it has most things required for this project. You can see matcher & comparer classes in this project.
|
100
|
+
- "Path" support was added to support have the feature provided by `json_spec` & `airborne`
|
101
|
+
- "Expectation" classes was added to remove the usage of `#===` following the pattern "contract" classes in [`contracts.ruby`](https://github.com/egonSchiele/contracts.ruby) since the author is a user of that project.
|
102
|
+
- Refactor without the usage of external tool (yet)
|
103
|
+
- Start using [`appraisal`](https://github.com/thoughtbot/appraisal) to test this gem against all `rspec` versions that should be supported. And that did discover a few errors with `rspec` `3.0`.
|
104
|
+
- Prepare config file for [Travis](https://travis-ci.org/) (copy from other existing objects)
|
105
|
+
- Create the first commit (finally)
|
106
|
+
- Setup related services:
|
107
|
+
- [Travis CI](https://travis-ci.org/) to ensure the spec is passed
|
108
|
+
- [Gemnasium](https://gemnasium.com/) to ensure the updated dependencies
|
109
|
+
- [Code Climate](https://codeclimate.com/) to ensure high code quality
|
110
|
+
- [Coveralls](https://coveralls.io/) to ensure high test coverage
|
111
|
+
- [Inch CI](https://inch-ci.org/) to ensure inline doc with quality
|
112
|
+
- [Gitter](https://gitter.im/) for a free chat room for the project
|
113
|
+
- Add badges to README
|
114
|
+
- Refactor according to result from Code Climate & [rubocop](https://github.com/bbatsov/rubocop)
|
115
|
+
- Improve inline doc according to result from running [inch](https://github.com/rrrene/inch) locally
|
116
|
+
- Release an "alpha" version and actually it in real project
|
117
|
+
|
118
|
+
|
119
|
+
# Future
|
120
|
+
In the near future:
|
121
|
+
- Release a "beta" version for public testing and feedback
|
122
|
+
- React according to feedback before the official version release, if any
|
123
|
+
- Add `CONTRIBUTING.md` if appropriate
|
124
|
+
|
125
|
+
There are several features that might be considered to be implemented in the future:
|
126
|
+
- Built-in "expectation" for "type or null"
|
127
|
+
- Built-in "expectation" for "date"
|
128
|
+
- Path matching feature in [`airborne`](https://github.com/brooklynDev/airborne)
|
129
|
+
- `be_json.with_types` which only accepts classes (only? not sure)
|
data/lib/rspec-json_matchers.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative "rspec/json_matchers"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "abstract_class"
|
2
|
+
require "forwardable"
|
2
3
|
require "set"
|
3
4
|
require_relative "../expectation"
|
4
5
|
require_relative "comparison_result"
|
@@ -14,24 +15,28 @@ module RSpec
|
|
14
15
|
# The subclasses only need to implement the behaviour of matching keys
|
15
16
|
# when both expected & actual are same type of collection
|
16
17
|
class AbstractComparer
|
17
|
-
attr_reader
|
18
|
+
attr_reader(*[
|
18
19
|
:actual,
|
19
20
|
:expected,
|
20
21
|
:reasons,
|
21
22
|
:value_matching_proc,
|
22
|
-
]
|
23
|
+
])
|
23
24
|
|
24
|
-
# Creates a comparer that actually use the {value_matching_proc}
|
25
|
+
# Creates a comparer that actually use the {value_matching_proc}
|
26
|
+
# for matching {#actual} and {#expected}
|
25
27
|
# This class is respossible to aggregating
|
26
28
|
# the matching result for each element of {#expected},
|
27
29
|
# and compare the keys/indices as well
|
28
30
|
#
|
29
|
-
# @param actual [Object]
|
30
|
-
#
|
31
|
+
# @param actual [Object]
|
32
|
+
# the actual "thing", should be an {Enumerable}
|
33
|
+
# @param expected [Object]
|
34
|
+
# the expected "thing", should be an {Enumerable}
|
31
35
|
# @param reasons [Array<String>]
|
32
36
|
# failure reasons, mostly the path parts
|
33
37
|
# @param value_matching_proc [Proc]
|
34
|
-
# the proc that actually compares
|
38
|
+
# the proc that actually compares
|
39
|
+
# the expected & actual and returns a boolean
|
35
40
|
def initialize(actual, expected, reasons, value_matching_proc)
|
36
41
|
@actual = actual
|
37
42
|
@expected = expected
|
@@ -43,9 +48,7 @@ module RSpec
|
|
43
48
|
# @return [Boolean]
|
44
49
|
# `true` if #actual & #expected are the same
|
45
50
|
def compare
|
46
|
-
if has_matched_value?
|
47
|
-
return ComparisonResult.new(true, reasons)
|
48
|
-
end
|
51
|
+
return ComparisonResult.new(true, reasons) if has_matched_value?
|
49
52
|
|
50
53
|
has_matched_collection?
|
51
54
|
end
|
@@ -74,16 +77,14 @@ module RSpec
|
|
74
77
|
|
75
78
|
# @note with side effect on `#reasons`
|
76
79
|
def has_matched_keys?
|
77
|
-
|
80
|
+
fail NotImplementedError
|
78
81
|
end
|
79
82
|
|
80
83
|
# @note with side effect on `#reasons`
|
81
84
|
def has_matched_values?
|
82
|
-
comparison_result =
|
83
|
-
|
84
|
-
|
85
|
-
}.fetch(expected.class).
|
86
|
-
new(expected, actual, reasons, value_matching_proc, self.class).
|
85
|
+
comparison_result = EXPECTED_VALUE_CLASS_TO_EXPECTATION_MAPPING.
|
86
|
+
fetch(expected.class).
|
87
|
+
new(self).
|
87
88
|
comparison_result
|
88
89
|
|
89
90
|
comparison_result.matched?.tap do |matched|
|
@@ -91,96 +92,91 @@ module RSpec
|
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
95
|
+
def actual_keys
|
96
|
+
@actual_keys ||= Utils::CollectionKeysExtractor.extract(actual)
|
97
|
+
end
|
98
|
+
|
99
|
+
def expected_keys
|
100
|
+
@expected_keys ||= Utils::CollectionKeysExtractor.extract(expected)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Represents an "expectation" for matching all elements
|
104
|
+
# in {#actual} & {#expected}
|
94
105
|
class HasMatchedValues
|
95
106
|
extend AbstractClass
|
107
|
+
extend Forwardable
|
96
108
|
|
97
|
-
private
|
98
|
-
attr_reader *[
|
99
|
-
:actual,
|
100
|
-
:expected,
|
101
|
-
:reasons,
|
102
|
-
:value_matching_proc,
|
103
|
-
|
104
|
-
:comparer_class,
|
105
|
-
]
|
106
109
|
public
|
107
110
|
|
108
|
-
# Create a "matching" operation object
|
111
|
+
# Create a "matching" operation object
|
112
|
+
# that can return a {Comparers::ComparisonResult}
|
109
113
|
#
|
110
|
-
# @param
|
111
|
-
#
|
112
|
-
|
113
|
-
|
114
|
-
# @param value_matching_proc [Proc]
|
115
|
-
# the proc that actually compares the expected & actual and returns a boolean
|
116
|
-
# @param comparer_class [Class<AbstractComparer>]
|
117
|
-
# the class that should be used recursively
|
118
|
-
def initialize(expected, actual, reasons, value_matching_proc, comparer_class)
|
119
|
-
@actual = actual
|
120
|
-
@expected = expected
|
121
|
-
@reasons = reasons
|
122
|
-
|
123
|
-
@value_matching_proc = value_matching_proc
|
124
|
-
|
125
|
-
@comparer_class = comparer_class
|
114
|
+
# @param comparer [AbstractComparer]
|
115
|
+
# the comparer that creates this object, for fetching values
|
116
|
+
def initialize(comparer)
|
117
|
+
@comparer = comparer
|
126
118
|
end
|
127
119
|
|
128
120
|
def comparison_result
|
129
121
|
each_element_enumerator.each do |element|
|
130
|
-
|
131
|
-
element,
|
132
|
-
expected,
|
133
|
-
actual,
|
134
|
-
reasons,
|
135
|
-
value_matching_proc,
|
136
|
-
comparer_class,
|
137
|
-
).comparison_result
|
122
|
+
result = comparison_result_for_element(element)
|
138
123
|
|
139
|
-
return
|
124
|
+
return result unless result.matched?
|
140
125
|
end
|
141
126
|
|
142
127
|
Comparers::ComparisonResult.new(true, reasons)
|
143
128
|
end
|
144
129
|
|
145
130
|
def each_element_enumerator
|
146
|
-
|
131
|
+
fail NotImplementedError
|
147
132
|
end
|
148
133
|
|
149
134
|
def has_matched_value_class
|
150
|
-
|
135
|
+
fail NotImplementedError
|
151
136
|
end
|
152
137
|
|
153
|
-
|
154
|
-
extend AbstractClass
|
138
|
+
private
|
155
139
|
|
156
|
-
|
157
|
-
|
158
|
-
|
140
|
+
def_delegators(*[
|
141
|
+
:comparer,
|
142
|
+
:expected,
|
143
|
+
:reasons,
|
144
|
+
])
|
159
145
|
|
160
|
-
|
161
|
-
|
162
|
-
|
146
|
+
attr_reader(*[
|
147
|
+
:comparer,
|
148
|
+
])
|
163
149
|
|
164
|
-
|
150
|
+
def comparer_class
|
151
|
+
comparer.class
|
152
|
+
end
|
153
|
+
|
154
|
+
def comparison_result_for_element(element)
|
155
|
+
has_matched_value_class.
|
156
|
+
new(
|
157
|
+
element,
|
158
|
+
comparer,
|
159
|
+
).comparison_result
|
160
|
+
end
|
161
|
+
|
162
|
+
# Represents an "expectation" for matching one element
|
163
|
+
# in {#actual} & {#expected}
|
164
|
+
class HasMatchedValue
|
165
|
+
extend AbstractClass
|
166
|
+
extend Forwardable
|
165
167
|
|
166
|
-
:comparer_class,
|
167
|
-
]
|
168
168
|
public
|
169
169
|
|
170
|
-
# Create a "matching" operation object
|
170
|
+
# Create a "matching" operation object
|
171
|
+
# that can return a {Comparers::ComparisonResult}
|
171
172
|
# Unlike {HasMatchedValues}, this is for an element of `expected`
|
172
173
|
#
|
173
|
-
# @param element [Integer, String, Symbol]
|
174
|
+
# @param element [Integer, String, Symbol]
|
175
|
+
# a index/key from expected (not value)
|
174
176
|
# @param (see HasMatchedValues#initialize)
|
175
|
-
def initialize(element,
|
177
|
+
def initialize(element, comparer)
|
176
178
|
@element = element
|
177
|
-
@
|
178
|
-
@expected = expected
|
179
|
-
@reasons = reasons
|
180
|
-
|
181
|
-
@value_matching_proc = value_matching_proc
|
182
|
-
|
183
|
-
@comparer_class = comparer_class
|
179
|
+
@comparer = comparer
|
184
180
|
end
|
185
181
|
|
186
182
|
def comparison_result
|
@@ -194,6 +190,23 @@ module RSpec
|
|
194
190
|
|
195
191
|
private
|
196
192
|
|
193
|
+
attr_reader(*[
|
194
|
+
:element,
|
195
|
+
:comparer,
|
196
|
+
])
|
197
|
+
|
198
|
+
def_delegators(*[
|
199
|
+
:comparer,
|
200
|
+
:expected,
|
201
|
+
:actual,
|
202
|
+
:reasons,
|
203
|
+
:value_matching_proc,
|
204
|
+
])
|
205
|
+
|
206
|
+
def comparer_class
|
207
|
+
comparer.class
|
208
|
+
end
|
209
|
+
|
197
210
|
def result
|
198
211
|
@result ||= comparer_class.
|
199
212
|
new(
|
@@ -206,22 +219,25 @@ module RSpec
|
|
206
219
|
end
|
207
220
|
|
208
221
|
def actual_contain_element?
|
209
|
-
|
222
|
+
fail NotImplementedError
|
210
223
|
end
|
211
224
|
|
212
225
|
def actual_for_element
|
213
|
-
|
226
|
+
fail NotImplementedError
|
214
227
|
end
|
228
|
+
|
215
229
|
def expected_for_element
|
216
|
-
|
230
|
+
fail NotImplementedError
|
217
231
|
end
|
218
232
|
|
219
233
|
def reason
|
220
|
-
|
234
|
+
fail NotImplementedError
|
221
235
|
end
|
222
236
|
end
|
223
237
|
end
|
224
238
|
|
239
|
+
# (see HasMatchedValues)
|
240
|
+
# {#expected} should be {Array}
|
225
241
|
class HasMatchedArrayValues < HasMatchedValues
|
226
242
|
def each_element_enumerator
|
227
243
|
expected.each_index
|
@@ -231,9 +247,13 @@ module RSpec
|
|
231
247
|
HasMatchedArrayValue
|
232
248
|
end
|
233
249
|
|
250
|
+
# (see HasMatchedValues::HasMatchedValue)
|
251
|
+
# {#expected} should be {Array}
|
234
252
|
class HasMatchedArrayValue < HasMatchedValues::HasMatchedValue
|
235
253
|
private
|
254
|
+
|
236
255
|
alias_method :index, :element
|
256
|
+
|
237
257
|
public
|
238
258
|
|
239
259
|
def actual_contain_element?
|
@@ -243,6 +263,7 @@ module RSpec
|
|
243
263
|
def actual_for_element
|
244
264
|
actual[index]
|
245
265
|
end
|
266
|
+
|
246
267
|
def expected_for_element
|
247
268
|
expected[index]
|
248
269
|
end
|
@@ -253,6 +274,8 @@ module RSpec
|
|
253
274
|
end
|
254
275
|
end
|
255
276
|
|
277
|
+
# (see HasMatchedValues)
|
278
|
+
# {#expected} should be {Hash}
|
256
279
|
class HasMatchedHashValues < HasMatchedValues
|
257
280
|
def each_element_enumerator
|
258
281
|
expected.each_key
|
@@ -262,9 +285,13 @@ module RSpec
|
|
262
285
|
HasMatchedHashValue
|
263
286
|
end
|
264
287
|
|
288
|
+
# (see HasMatchedValues::HasMatchedValue)
|
289
|
+
# {#expected} should be {Array}
|
265
290
|
class HasMatchedHashValue < HasMatchedValues::HasMatchedValue
|
266
291
|
private
|
292
|
+
|
267
293
|
alias_method :key, :element
|
294
|
+
|
268
295
|
public
|
269
296
|
|
270
297
|
def actual_contain_element?
|
@@ -274,6 +301,7 @@ module RSpec
|
|
274
301
|
def actual_for_element
|
275
302
|
actual[key.to_s]
|
276
303
|
end
|
304
|
+
|
277
305
|
def expected_for_element
|
278
306
|
expected[key]
|
279
307
|
end
|
@@ -283,6 +311,12 @@ module RSpec
|
|
283
311
|
end
|
284
312
|
end
|
285
313
|
end
|
314
|
+
|
315
|
+
EXPECTED_VALUE_CLASS_TO_EXPECTATION_MAPPING = {
|
316
|
+
Array => HasMatchedArrayValues,
|
317
|
+
Hash => HasMatchedHashValues,
|
318
|
+
}.freeze
|
319
|
+
private_constant :EXPECTED_VALUE_CLASS_TO_EXPECTATION_MAPPING
|
286
320
|
end
|
287
321
|
end
|
288
322
|
end
|