data_spec 0.0.1 → 0.0.2
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/.travis.yml +4 -0
- data/Gemfile +8 -1
- data/README.md +120 -40
- data/Rakefile +10 -0
- data/data_spec.gemspec +1 -3
- data/features/core.feature +20 -20
- data/features/memory.feature +126 -0
- data/features/readme.feature +95 -0
- data/features/support/env.rb +1 -1
- data/lib/data_spec/cucumber.rb +23 -3
- data/lib/data_spec/helpers.rb +22 -13
- data/lib/data_spec/matchers.rb +6 -13
- data/lib/data_spec/version.rb +1 -1
- data/lib/data_spec.rb +5 -2
- data/spec/data_spec/block_spec.rb +2 -1
- data/spec/data_spec/helpers_spec.rb +9 -0
- data/spec/data_spec/inclusion_spec.rb +4 -4
- data/spec/data_spec/matchers_spec.rb +7 -0
- data/spec/spec_helper.rb +1 -1
- metadata +9 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38a6a7c19a43116b793ccc2565beba91ec40ad58
|
4
|
+
data.tar.gz: 78178e54b3ad7afc932a487ca8ce453104e95a52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebd55fded46197f459fd651d339bcef2798f36681a8a0c5d27e96087f13dd92c3cd61d3788fdb90f840cabe2e24337409f40449921b87d503b8718bb0b915fc2
|
7
|
+
data.tar.gz: 23239a0654bdd2c85c817fcb00ff8b810a63c5f4d0eb77bf39fedd0b0d6495357858128c443416c15bff0bed87e67e6b50bdcd5a130f5900d52ed9b71298f449
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
data_spec
|
2
2
|
========
|
3
3
|
|
4
|
+
[](http://travis-ci.org/narfanator/data_spec) [](https://gemnasium.com/narfanator/data_spec) [](https://codeclimate.com/github/narfanator/data_spec)
|
5
|
+
|
4
6
|
Easily compare hashes and arrays in RSpec and Cucumber
|
5
7
|
|
6
8
|
Originally inspired by collectiveidea's json_spec gem
|
@@ -9,29 +11,29 @@ Installation
|
|
9
11
|
------------
|
10
12
|
|
11
13
|
gem 'data_spec'
|
12
|
-
{cucumber}
|
13
|
-
{rspec}
|
14
14
|
|
15
|
-
Cucumber
|
16
|
-
------------
|
15
|
+
# Cucumber
|
17
16
|
|
18
|
-
|
17
|
+
Setup:
|
18
|
+
------------
|
19
19
|
|
20
|
-
Include `data_spec
|
20
|
+
Include `data_spec` and define `data` in your Cucumber environment:
|
21
21
|
```ruby
|
22
22
|
# features/support/env.rb
|
23
|
-
require "data_spec
|
23
|
+
require "data_spec"
|
24
24
|
|
25
25
|
def data
|
26
26
|
#...
|
27
27
|
end
|
28
28
|
```
|
29
29
|
|
30
|
-
|
30
|
+
Usage:
|
31
|
+
------------
|
32
|
+
**The step `Given the data is:` is not supplied by this gem**
|
31
33
|
|
32
34
|
Use either YAML or JSON:
|
33
35
|
````ruby
|
34
|
-
Given the data is:
|
36
|
+
Given the data is:
|
35
37
|
"""
|
36
38
|
chunky: bacon
|
37
39
|
"""
|
@@ -75,7 +77,7 @@ Then the data includes:
|
|
75
77
|
- 1
|
76
78
|
- 2
|
77
79
|
"""
|
78
|
-
And the data at "even" includes "'in a': hash"
|
80
|
+
And the data at "3/even" includes "'in a': hash"
|
79
81
|
```
|
80
82
|
|
81
83
|
Check types:
|
@@ -86,9 +88,9 @@ Given the data is:
|
|
86
88
|
- 1
|
87
89
|
- 2013-07-06 20:09:32.824102000 -07:00
|
88
90
|
"""
|
89
|
-
Then the data at "0"
|
90
|
-
Then the data at "1"
|
91
|
-
Then the data at "2"
|
91
|
+
Then the data at "0" should be of type String
|
92
|
+
Then the data at "1" should be of type Fixnum
|
93
|
+
Then the data at "2" should be of type Time
|
92
94
|
```
|
93
95
|
|
94
96
|
Use embedded code:
|
@@ -97,80 +99,158 @@ Given the data is:
|
|
97
99
|
"""
|
98
100
|
- `1+1`
|
99
101
|
- '$1e2$'
|
100
|
-
- `
|
102
|
+
- `'bacon'.class`
|
101
103
|
"""
|
102
104
|
Then the data at "0" should be 2
|
103
105
|
Then the data at "1" should be 100
|
104
|
-
Then the data at "2" should be `
|
106
|
+
Then the data at "2" should be `"chunky".class`
|
105
107
|
```
|
106
108
|
(Among other things, this lets you work around Ruby YAML's lack of support for scientific notation)
|
109
|
+
|
107
110
|
**Note: This is done via a raw `eval`, so it's dangerous**
|
108
111
|
|
109
|
-
|
112
|
+
Store data for later use:
|
113
|
+
```ruby
|
114
|
+
Given `@samples` is:
|
115
|
+
"""
|
116
|
+
where: "http://google.com"
|
117
|
+
when: `Time.now`
|
118
|
+
"""
|
119
|
+
And `@samples` includes:
|
120
|
+
"""
|
121
|
+
what: {}
|
122
|
+
"""
|
123
|
+
And `@samples['what']` is:
|
124
|
+
"""
|
125
|
+
- chunky
|
126
|
+
- bacon
|
127
|
+
"""
|
128
|
+
And the data is:
|
129
|
+
"""
|
130
|
+
meal:
|
131
|
+
main_course: `@samples['what'][1]`
|
132
|
+
style: `@samples['what'][0]`
|
133
|
+
ordered: `@samples['when']`
|
134
|
+
"""
|
135
|
+
Then the data should be:
|
136
|
+
"""
|
137
|
+
meal:
|
138
|
+
main_course: bacon
|
139
|
+
style: chunky
|
140
|
+
ordered: `@samples['when']`
|
141
|
+
"""
|
142
|
+
```
|
143
|
+
|
144
|
+
Again, this is done by raw eval, so it's dangerous, and it's definitely enough to shoot your foot off with.
|
145
|
+
|
146
|
+
If you're using this in anything like a complex sense, look up the "evaluation" and "remember" helpers, below
|
147
|
+
|
110
148
|
|
149
|
+
Steps
|
150
|
+
----------
|
151
|
+
|
152
|
+
Matching:
|
111
153
|
* `Then the data should be:`
|
112
154
|
* `Then the data should be "..."`
|
113
155
|
* `Then the data at "..." should be:`
|
114
156
|
* `Then the data at "..." should be "..."`
|
115
157
|
|
158
|
+
Inclusion:
|
116
159
|
* `Then the data includes:`
|
117
160
|
* `Then the data includes "..."`
|
118
161
|
* `Then the data at "..." includes:`
|
119
162
|
* `Then the data at "..." includes "..."`
|
120
163
|
|
164
|
+
Type checking:
|
121
165
|
* `Then the data is of type ...`
|
122
166
|
* `Then the data at "..." if of type ...`
|
123
167
|
|
124
168
|
Pathing is done like so: `data[:chunky]['Bacon'][0]` would be "chunky/bacon/0". Each element (when looking in a hash) is first tried as a symbol, then as a string.
|
125
169
|
|
126
|
-
When checking inclusion against an array, you need to supply an array: `[1,2,3]` includes `[2]`, or `[1, [2,3], 4]` includes `[[2,3]]
|
170
|
+
When checking inclusion against an array, you need to supply an array: `[1,2,3]` includes `[2]`, or `[1, [2,3], 4]` includes `[[2,3]]`.
|
127
171
|
|
128
172
|
When checking inclusion against a hash, you need to supply a hash: `{one: :two, three: four}` includes `{one: :two}`
|
129
173
|
|
130
|
-
|
174
|
+
You don't see this quite the same in the Cucumber steps because YAML parsing from a string does this inherently: `"one: two"` becomes `{'one' => 'two'}` and
|
175
|
+
`"[one, two]"` or `"- one\n- two"` becomes `['one', 'two']`
|
176
|
+
|
177
|
+
# RSpec
|
178
|
+
|
179
|
+
Setup
|
131
180
|
--------
|
181
|
+
```ruby
|
182
|
+
#in spec/spec_helper.rb
|
183
|
+
require 'data_spec'
|
184
|
+
```
|
132
185
|
|
186
|
+
Matchers
|
187
|
+
--------
|
188
|
+
Three matchers:
|
133
189
|
* `match_data(...).at(...)`
|
134
190
|
* `includes_data(...).at(...)`
|
135
191
|
* `match_block(lambda{...}).at(...)`
|
136
192
|
|
137
|
-
Exact matching is
|
138
|
-
|
193
|
+
Exact matching is handled by `==`, while partial matching is handled by
|
194
|
+
[`deep_include?`](http://stackoverflow.com/questions/3826969/ruby-hash-include-another-hash-deep-check)
|
195
|
+
|
196
|
+
Note that pathing is applied to the object being checked:
|
197
|
+
|
198
|
+
hash1.should match_data(hash2).at("path/0")
|
199
|
+
|
200
|
+
results in:
|
201
|
+
|
202
|
+
hash1[:path][0].should match_data(hash2)
|
203
|
+
|
204
|
+
# Library
|
139
205
|
|
140
206
|
Helpers
|
141
207
|
--------
|
142
|
-
* DataSpec::Helpers.at_path(data, path)
|
143
|
-
* DataSpec.parse
|
208
|
+
* `DataSpec::Helpers.at_path(data, path)`
|
209
|
+
* `DataSpec.parse`
|
144
210
|
|
145
|
-
`at_path` is what provides the "pathing" functionality, while `parse` provides interpreting embedded code.
|
211
|
+
`at_path` is what provides the "pathing" functionality, while `parse` provides the interpreting of embedded code.
|
146
212
|
|
147
213
|
As seen in the examples, you can use $ at the beginning and end, or backticks instead of quotes.
|
148
|
-
The backticks will actually be converted to dollar signs
|
214
|
+
The backticks will actually be converted to dollar signs (YAML parsers choke on backticks),
|
215
|
+
but they're prettier and easier to read.
|
149
216
|
|
150
|
-
|
151
|
-
-------
|
152
|
-
`DataSpec::Refinements` adds `tree_walk_with_self` to both `Hash` and `Array`.
|
153
|
-
It allows you to apply a block to every key/value pair in the hash or array, traversing recursively.
|
154
|
-
Supply a block accepting `(key, value), hash`, where `hash` is the current node; `hash[key] == value`; this allows you to alter the values.
|
217
|
+
* `DataSpec::Helpers.evaluate(string)`
|
155
218
|
|
156
|
-
|
157
|
-
|
158
|
-
* The YAML/JSON equivelance check is failing.
|
159
|
-
* The error messages suck. Plan is to provide them as a diff'd YAML, although I'm not sure what to do for blocks
|
160
|
-
* No table syntax as in json_spec
|
161
|
-
* No explicit testing of `tree_walks_with_self`
|
162
|
-
* No support for XML
|
219
|
+
This simply does an `eval` on the string; however, _because it also used when parsing YAML/JSON_, you can add variables
|
220
|
+
in which it is run, and use those variables in your YAML and JSON.
|
163
221
|
|
164
|
-
|
165
|
-
-----------
|
166
|
-
Go for it! Accepted code will have Cucumber and RSpec testing and be minimalist; if you spot a bug, try to provide a failing test in the report.
|
222
|
+
* `DataSpec::Helpers.remember(string, data)
|
167
223
|
|
168
|
-
|
224
|
+
This is another way to add data to the evaulation scope; pass in the complete variable name (such as `@sample_data`) and the data to be stored.
|
225
|
+
|
226
|
+
Refinements
|
227
|
+
-------
|
228
|
+
Defined in `DataSpec::Refinements`; to use, `using DataSpec::Refinements`
|
169
229
|
|
230
|
+
* `Array.tree_walk_with_self{|(key, value), array| ... }`
|
231
|
+
* `Array.deep_include? sub_array`
|
232
|
+
* `Hash.tree_walk_with_self{|(key, value), hash| ... }`
|
233
|
+
* `Hash.deep_include? sub_hash`
|
170
234
|
|
235
|
+
`tree_walk_with_self` allows you to apply a block to every key/value pair in the hash or array, traversing recursively.
|
236
|
+
The third yielded value is the current node: `hash[key] == value` - this allows you to alter the values of the hash during traversal.
|
171
237
|
|
238
|
+
`Array.deep_include? sub_array` simply does `(sub_array - self).empty?`, which is true when all elements of the sub-array
|
239
|
+
are present in `self`
|
172
240
|
|
241
|
+
`Hash.deep_include? sub_hash` is used to detect if every key/value pair in the `sub_hash` is present in `self`
|
173
242
|
|
243
|
+
#Contributing
|
174
244
|
|
245
|
+
Remaining Issues
|
246
|
+
-------
|
247
|
+
* The error messages suck. Plan is to provide them as a diff'd YAML, although I'm not sure what to do for blocks
|
248
|
+
* No table syntax as in `json_spec`
|
249
|
+
* No explicit testing of `tree_walks_with_self`
|
250
|
+
* No support for XML
|
175
251
|
|
252
|
+
Pull Requests
|
253
|
+
-----------
|
254
|
+
Go for it! Accepted code will have Cucumber and RSpec testing and be minimalist; if you spot a bug, try to provide a failing test in the report.
|
176
255
|
|
256
|
+
"Minimalist" doesn't mean fewest lines of code (although that's usually the case); it means "fewest new functions and objects"
|
data/Rakefile
CHANGED
@@ -1 +1,11 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "cucumber/rake/task"
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
Cucumber::Rake::Task.new(:cucumber) do |t|
|
7
|
+
t.cucumber_opts = "--tags ~@fail"
|
8
|
+
end
|
9
|
+
|
10
|
+
task :test => [:spec, :cucumber]
|
11
|
+
task :default => :test
|
data/data_spec.gemspec
CHANGED
@@ -14,11 +14,9 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
17
|
-
spec.
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.test_files = spec.files.grep(%r{^(spec|features)/})
|
19
18
|
spec.require_paths = ["lib"]
|
20
19
|
|
21
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
22
20
|
spec.add_development_dependency "rake"
|
23
21
|
spec.add_dependency "cucumber"
|
24
22
|
spec.add_dependency "rspec"
|
data/features/core.feature
CHANGED
@@ -3,33 +3,33 @@ Feature: Core Steps
|
|
3
3
|
Scenario: JSON / YAML Equality
|
4
4
|
Given the data is:
|
5
5
|
"""
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
chunky: bacon
|
7
|
+
ordered_by:
|
8
|
+
- person: joe
|
9
|
+
wants:
|
10
|
+
pieces: `1+1`
|
11
|
+
- person: josephina
|
12
|
+
wants:
|
13
|
+
pieces: `1e2`
|
14
14
|
"""
|
15
15
|
Then the data should be:
|
16
16
|
"""
|
17
17
|
{
|
18
|
-
"chunky": "bacon",
|
19
18
|
"ordered_by": [
|
20
19
|
{
|
21
|
-
"person": "joe",
|
22
20
|
"wants": {
|
23
21
|
"pieces": "`1+1`"
|
24
|
-
}
|
22
|
+
},
|
23
|
+
"person": "joe"
|
25
24
|
},
|
26
25
|
{
|
27
|
-
"person": "josephina",
|
28
26
|
"wants": {
|
29
27
|
"pieces": "`1e2`"
|
30
|
-
}
|
28
|
+
},
|
29
|
+
"person": "josephina"
|
31
30
|
}
|
32
|
-
]
|
31
|
+
],
|
32
|
+
"chunky": "bacon"
|
33
33
|
}
|
34
34
|
"""
|
35
35
|
|
@@ -110,9 +110,9 @@ Feature: Core Steps
|
|
110
110
|
hash: {}
|
111
111
|
array: []
|
112
112
|
"""
|
113
|
-
Then the data at "date"
|
114
|
-
And the data at "fixnum"
|
115
|
-
And the data at "float"
|
116
|
-
And the data at "string"
|
117
|
-
And the data at "hash"
|
118
|
-
And the data at "array"
|
113
|
+
Then the data at "date" should be of type Time
|
114
|
+
And the data at "fixnum" should be of type Fixnum
|
115
|
+
And the data at "float" should be of type Float
|
116
|
+
And the data at "string" should be of type String
|
117
|
+
And the data at "hash" should be of type Hash
|
118
|
+
And the data at "array" should be of type Array
|
@@ -0,0 +1,126 @@
|
|
1
|
+
Feature: Storage of local information
|
2
|
+
|
3
|
+
Scenario: Variable Assignment
|
4
|
+
Given `@var` is "chunky"
|
5
|
+
And the data is:
|
6
|
+
"""
|
7
|
+
`@var`
|
8
|
+
"""
|
9
|
+
Then the data should be:
|
10
|
+
"""
|
11
|
+
chunky
|
12
|
+
"""
|
13
|
+
|
14
|
+
Scenario: Array Assignment
|
15
|
+
Given `@var` is:
|
16
|
+
"""
|
17
|
+
- chunky
|
18
|
+
- bacon
|
19
|
+
"""
|
20
|
+
And the data is:
|
21
|
+
"""
|
22
|
+
- `@var[0]`
|
23
|
+
- `@var[1]`
|
24
|
+
"""
|
25
|
+
Then the data at "0" should be "`@var[0]`"
|
26
|
+
And the data should be:
|
27
|
+
"""
|
28
|
+
`@var`
|
29
|
+
"""
|
30
|
+
|
31
|
+
Scenario: Array Appending
|
32
|
+
Given `@var` is:
|
33
|
+
"""
|
34
|
+
- chunky
|
35
|
+
- bacon
|
36
|
+
"""
|
37
|
+
And `@var` includes:
|
38
|
+
"""
|
39
|
+
- two
|
40
|
+
- three
|
41
|
+
"""
|
42
|
+
And the data is:
|
43
|
+
"""
|
44
|
+
`@var`
|
45
|
+
"""
|
46
|
+
Then the data should include "`@var[2,3]`"
|
47
|
+
|
48
|
+
Scenario: Hash Assignment
|
49
|
+
Given `@var` is:
|
50
|
+
"""
|
51
|
+
chunky: bacon
|
52
|
+
bacon: chunky
|
53
|
+
"""
|
54
|
+
And the data is:
|
55
|
+
"""
|
56
|
+
`@var`
|
57
|
+
"""
|
58
|
+
Then the data at "chunky" should be "bacon"
|
59
|
+
And the data should be:
|
60
|
+
"""
|
61
|
+
bacon: chunky
|
62
|
+
chunky: bacon
|
63
|
+
"""
|
64
|
+
|
65
|
+
Scenario: Hash Appending
|
66
|
+
Given `@var` is:
|
67
|
+
"""
|
68
|
+
chunky: bacon
|
69
|
+
bacon: chunky
|
70
|
+
"""
|
71
|
+
And `@var` includes:
|
72
|
+
"""
|
73
|
+
bacon: bacon
|
74
|
+
one: two
|
75
|
+
"""
|
76
|
+
And the data is:
|
77
|
+
"""
|
78
|
+
`@var`
|
79
|
+
"""
|
80
|
+
Then the data at "bacon" should be "bacon"
|
81
|
+
And the data at "one" should be "two"
|
82
|
+
|
83
|
+
Scenario: Nesting:
|
84
|
+
Given `@var` is:
|
85
|
+
"""
|
86
|
+
nested:
|
87
|
+
hash:
|
88
|
+
chunky: bacon
|
89
|
+
"""
|
90
|
+
And `@var['nested']` includes:
|
91
|
+
"""
|
92
|
+
array:
|
93
|
+
- 1
|
94
|
+
- 2
|
95
|
+
"""
|
96
|
+
And the data is:
|
97
|
+
"""
|
98
|
+
- `@var['nested']['hash']['chunky']`
|
99
|
+
- `@var['nested']['array']`
|
100
|
+
"""
|
101
|
+
Then the data should be:
|
102
|
+
"""
|
103
|
+
- bacon
|
104
|
+
- - 1
|
105
|
+
- 2
|
106
|
+
"""
|
107
|
+
|
108
|
+
Scenario: Multiple Variables
|
109
|
+
Given `@one` is:
|
110
|
+
"""
|
111
|
+
one: two
|
112
|
+
"""
|
113
|
+
And `@two` is:
|
114
|
+
"""
|
115
|
+
two: three
|
116
|
+
"""
|
117
|
+
And the data is:
|
118
|
+
"""
|
119
|
+
- `@one`
|
120
|
+
- `@two`
|
121
|
+
"""
|
122
|
+
Then the data is:
|
123
|
+
"""
|
124
|
+
- one: two
|
125
|
+
- two: three
|
126
|
+
"""
|
@@ -0,0 +1,95 @@
|
|
1
|
+
Feature: Readme Examples
|
2
|
+
|
3
|
+
Scenario: Matching
|
4
|
+
Given the data is:
|
5
|
+
"""
|
6
|
+
chunky: bacon
|
7
|
+
"""
|
8
|
+
Then the data should be:
|
9
|
+
"""
|
10
|
+
{
|
11
|
+
"chunky": "bacon"
|
12
|
+
}
|
13
|
+
"""
|
14
|
+
Scenario: Path Selection
|
15
|
+
Given the data is:
|
16
|
+
"""
|
17
|
+
interleaved:
|
18
|
+
- hashes:
|
19
|
+
and:
|
20
|
+
- arrays
|
21
|
+
"""
|
22
|
+
Then the data at "interleaved/0/hashes" should be:
|
23
|
+
"""
|
24
|
+
and:
|
25
|
+
- arrays
|
26
|
+
"""
|
27
|
+
|
28
|
+
Scenario: Inclusion
|
29
|
+
Given the data is:
|
30
|
+
"""
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
- 3
|
34
|
+
- even:
|
35
|
+
'in a': hash
|
36
|
+
'with only': some keys
|
37
|
+
"""
|
38
|
+
Then the data should include:
|
39
|
+
"""
|
40
|
+
- 1
|
41
|
+
- 2
|
42
|
+
"""
|
43
|
+
And the data at "3/even" should include "'in a': hash"
|
44
|
+
|
45
|
+
Scenario: Type Checking
|
46
|
+
Given the data is:
|
47
|
+
"""
|
48
|
+
- bacon
|
49
|
+
- 1
|
50
|
+
- 2013-07-06 20:09:32.824102000 -07:00
|
51
|
+
"""
|
52
|
+
Then the data at "0" should be of type String
|
53
|
+
Then the data at "1" should be of type Fixnum
|
54
|
+
Then the data at "2" should be of type Time
|
55
|
+
|
56
|
+
Scenario: Embedded Code
|
57
|
+
Given the data is:
|
58
|
+
"""
|
59
|
+
- `1+1`
|
60
|
+
- '$1e2$'
|
61
|
+
- `"bacon".class`
|
62
|
+
"""
|
63
|
+
Then the data at "0" should be "2"
|
64
|
+
Then the data at "1" should be "100"
|
65
|
+
Then the data at "2" should be "`"chunky".class`"
|
66
|
+
|
67
|
+
Scenario: Memory
|
68
|
+
Given `@samples` is:
|
69
|
+
"""
|
70
|
+
where: "http://google.com"
|
71
|
+
when: `Time.now`
|
72
|
+
"""
|
73
|
+
And `@samples` includes:
|
74
|
+
"""
|
75
|
+
what: {}
|
76
|
+
"""
|
77
|
+
And `@samples['what']` is:
|
78
|
+
"""
|
79
|
+
- chunky
|
80
|
+
- bacon
|
81
|
+
"""
|
82
|
+
And the data is:
|
83
|
+
"""
|
84
|
+
meal:
|
85
|
+
main_course: `@samples['what'][1]`
|
86
|
+
style: `@samples['what'][0]`
|
87
|
+
ordered: `@samples['when']`
|
88
|
+
"""
|
89
|
+
Then the data should be:
|
90
|
+
"""
|
91
|
+
meal:
|
92
|
+
main_course: bacon
|
93
|
+
style: chunky
|
94
|
+
ordered: `@samples['when']`
|
95
|
+
"""
|
data/features/support/env.rb
CHANGED
data/lib/data_spec/cucumber.rb
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
+
require File.expand_path("../../data_spec", __FILE__)
|
1
2
|
require 'data_spec'
|
3
|
+
require 'time'
|
2
4
|
|
3
|
-
World(DataSpec::Helpers, DataSpec::Matchers
|
5
|
+
World(DataSpec::Helpers, DataSpec::Matchers)
|
6
|
+
|
7
|
+
Given(/^`(.*?)` is:?(?: "(.*?)")?$/) do |var, inline, *block|
|
8
|
+
DataSpec::Helpers.evaluate("#{var} = DataSpec.parse(%##{(inline || block.first)}#)")
|
9
|
+
end
|
10
|
+
|
11
|
+
Given(/^`(.*?)` includes:?(?: "(.*?)")?$/) do |var, inline, *block|
|
12
|
+
if DataSpec.parse("`#{var}`").is_a? Hash
|
13
|
+
DataSpec::Helpers.evaluate("#{var}.merge! DataSpec.parse(%##{(inline || block.first)}#)")
|
14
|
+
elsif DataSpec.parse("`#{var}`").is_a? Array
|
15
|
+
DataSpec::Helpers.evaluate("#{var} += DataSpec.parse(%##{(inline || block.first)}#)")
|
16
|
+
end
|
17
|
+
end
|
4
18
|
|
5
19
|
# Then the data at "path" should be "data"
|
6
20
|
# Then the data should be: (...)
|
@@ -12,6 +26,12 @@ Then(/^the data(?: at "(.*?)")? should include:?(?: "(.*?)")?$/) do |path, inlin
|
|
12
26
|
data.should include_data(DataSpec.parse(inline || block.first)).at(path)
|
13
27
|
end
|
14
28
|
|
15
|
-
Then(/^the data at "(.*?)"
|
16
|
-
|
29
|
+
Then(/^the data at "(.*?)" should be of type ([A-Z][a-z]+)$/) do |path, type|
|
30
|
+
if type == "Time"
|
31
|
+
#JSON doesn't actually interpret a time string into a Time,
|
32
|
+
# YAML will, but Time doesn't parse a Time object
|
33
|
+
data.should match_block(lambda{|item| Time.parse(item.to_s).is_a? Time}).at(path)
|
34
|
+
else
|
35
|
+
data.should match_block(lambda{|item| item.is_a? Object.const_get(type)}).at(path)
|
36
|
+
end
|
17
37
|
end
|
data/lib/data_spec/helpers.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
+
require 'yaml'
|
1
2
|
module DataSpec
|
2
3
|
module Refinements
|
3
4
|
refine Array do
|
4
5
|
def tree_walk_with_self &block
|
5
6
|
self.each_with_index do |element, index|
|
6
|
-
if element.is_a?
|
7
|
-
element.tree_walk_with_self &block
|
8
|
-
elsif element.is_a? Array
|
7
|
+
if element.is_a?(Hash) || element.is_a?(Array)
|
9
8
|
element.tree_walk_with_self &block
|
10
9
|
else
|
11
10
|
yield [index, element], self
|
@@ -20,17 +19,16 @@ module DataSpec
|
|
20
19
|
|
21
20
|
refine Hash do
|
22
21
|
def tree_walk_with_self &block
|
23
|
-
self.each do |key,value|
|
24
|
-
if value.is_a?
|
25
|
-
value.tree_walk_with_self &block
|
26
|
-
elsif value.is_a? Array
|
22
|
+
self.each do |key, value|
|
23
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
27
24
|
value.tree_walk_with_self &block
|
28
25
|
else
|
29
|
-
yield [key,value], self
|
26
|
+
yield [key, value], self
|
30
27
|
end
|
31
28
|
end
|
32
29
|
end
|
33
30
|
|
31
|
+
#TODO: Can I replace this with a block passed to Tree Walker?
|
34
32
|
def deep_include?(sub_hash)
|
35
33
|
sub_hash.keys.all? do |key|
|
36
34
|
self.has_key?(key) && if sub_hash[key].is_a?(Hash)
|
@@ -47,17 +45,28 @@ end
|
|
47
45
|
using DataSpec::Refinements
|
48
46
|
module DataSpec
|
49
47
|
module Helpers
|
48
|
+
def self.evaluate string
|
49
|
+
eval(string)
|
50
|
+
end
|
51
|
+
def self.remember varname, data
|
52
|
+
instance_variable_set(varname, data)
|
53
|
+
end
|
50
54
|
def self.parse yaml
|
51
55
|
# `code` is more readable, but not parsable, for our purposes we're converting it to $
|
52
56
|
unrendered = YAML.load(yaml.gsub("`", "$"))
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
if unrendered.is_a?(Array) || unrendered.is_a?(Hash)
|
59
|
+
rendered = unrendered.tree_walk_with_self do |(k, v), h|
|
60
|
+
if v =~ /^\$(.+)\$$/
|
61
|
+
h[k] = self.evaluate($1)
|
62
|
+
end
|
59
63
|
end
|
64
|
+
elsif unrendered.is_a?(String) && unrendered =~ /^\$(.+)\$$/
|
65
|
+
rendered = self.evaluate($1)
|
66
|
+
else
|
67
|
+
rendered = unrendered
|
60
68
|
end
|
69
|
+
rendered
|
61
70
|
end
|
62
71
|
def self.at_path data, path
|
63
72
|
return data if path.nil? || path.empty?
|
data/lib/data_spec/matchers.rb
CHANGED
@@ -15,12 +15,10 @@ module DataSpec
|
|
15
15
|
@path = path
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
failure_message_for_should do |actual|
|
19
|
+
"Got:\n#{actual.to_yaml}\nExpected:\n#{expected.to_yaml}"
|
20
|
+
end
|
19
21
|
end
|
20
|
-
end
|
21
|
-
|
22
|
-
module Inclusion
|
23
|
-
extend RSpec::Matchers::DSL
|
24
22
|
|
25
23
|
matcher :include_data do |expected|
|
26
24
|
match do |actual|
|
@@ -31,12 +29,10 @@ module DataSpec
|
|
31
29
|
@path = path
|
32
30
|
end
|
33
31
|
|
34
|
-
|
32
|
+
failure_message_for_should do |actual|
|
33
|
+
"Got:\n#{actual.to_yaml}\nExpected:\n#{expected.to_yaml}"
|
34
|
+
end
|
35
35
|
end
|
36
|
-
end
|
37
|
-
|
38
|
-
module Block
|
39
|
-
extend RSpec::Matchers::DSL
|
40
36
|
|
41
37
|
matcher :match_block do |block|
|
42
38
|
match do |actual|
|
@@ -48,7 +44,4 @@ module DataSpec
|
|
48
44
|
end
|
49
45
|
end
|
50
46
|
end
|
51
|
-
|
52
|
-
module Interpolation
|
53
|
-
end
|
54
47
|
end
|
data/lib/data_spec/version.rb
CHANGED
data/lib/data_spec.rb
CHANGED
@@ -5,7 +5,10 @@ require 'data_spec/matchers'
|
|
5
5
|
if RSpec && RSpec.respond_to?(:configure)
|
6
6
|
RSpec.configure do |config|
|
7
7
|
config.include DataSpec::Matchers
|
8
|
-
config.include DataSpec::
|
9
|
-
config.include DataSpec::Block
|
8
|
+
config.include DataSpec::Helpers
|
10
9
|
end
|
11
10
|
end
|
11
|
+
|
12
|
+
if defined?(World)
|
13
|
+
require 'data_spec/cucumber'
|
14
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe DataSpec::
|
3
|
+
describe DataSpec::Matchers do
|
4
4
|
|
5
5
|
it "can check array inclusion" do
|
6
6
|
[1,2,3].should include_data([2])
|
@@ -46,9 +46,9 @@ describe DataSpec::Inclusion do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "can check at a path" do
|
49
|
-
[1, {
|
50
|
-
[1, {
|
49
|
+
[1, {breakfast: [2, {chunky: :bacon, bacon: :chunky} ] } ].should include_data({chunky: :bacon}).at("1/breakfast/1")
|
50
|
+
[1, {breakfast: [2, {chunky: :bacon, bacon: :chunky} ] } ].should include_data({chunky: :bacon}).at("1/breakfast/1")
|
51
51
|
|
52
|
-
[1, {
|
52
|
+
[1, {breakfast: [2, {chunky: :bacon, bacon: :chunky} ] } ].should_not include_data({chunky: :nocab}).at("1/breakfast/1")
|
53
53
|
end
|
54
54
|
end
|
@@ -6,30 +6,37 @@ describe DataSpec::Matchers do
|
|
6
6
|
{}.should match_data({})
|
7
7
|
{}.should_not match_data([])
|
8
8
|
end
|
9
|
+
|
9
10
|
it "should match empty arrays" do
|
10
11
|
[].should match_data([])
|
11
12
|
[].should_not match_data({})
|
12
13
|
end
|
14
|
+
|
13
15
|
it "should match strings" do
|
14
16
|
"Bacon".should match_data("Bacon")
|
15
17
|
"Bacon".should_not match_data("Chunky")
|
16
18
|
end
|
19
|
+
|
17
20
|
it "should match integers" do
|
18
21
|
1.should match_data(1)
|
19
22
|
2.should_not match_data(1)
|
20
23
|
end
|
24
|
+
|
21
25
|
it "should match floats" do
|
22
26
|
1.1.should match_data(1.1)
|
23
27
|
2.1.should_not match_data(1.1)
|
24
28
|
end
|
29
|
+
|
25
30
|
it "should match true" do
|
26
31
|
true.should match_data(true)
|
27
32
|
true.should_not match_data(false)
|
28
33
|
end
|
34
|
+
|
29
35
|
it "should match false" do
|
30
36
|
false.should match_data(false)
|
31
37
|
false.should_not match_data(true)
|
32
38
|
end
|
39
|
+
|
33
40
|
it "should match nil" do
|
34
41
|
nil.should match_data(nil)
|
35
42
|
nil.should_not match_data("something")
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: data_spec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- narfanator
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ~>
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.3'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ~>
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.3'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: rake
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,12 +61,15 @@ extra_rdoc_files: []
|
|
75
61
|
files:
|
76
62
|
- .gitignore
|
77
63
|
- .rspec
|
64
|
+
- .travis.yml
|
78
65
|
- Gemfile
|
79
66
|
- LICENSE.txt
|
80
67
|
- README.md
|
81
68
|
- Rakefile
|
82
69
|
- data_spec.gemspec
|
83
70
|
- features/core.feature
|
71
|
+
- features/memory.feature
|
72
|
+
- features/readme.feature
|
84
73
|
- features/step_definitions/steps.rb
|
85
74
|
- features/support/env.rb
|
86
75
|
- lib/data_spec.rb
|
@@ -89,6 +78,7 @@ files:
|
|
89
78
|
- lib/data_spec/matchers.rb
|
90
79
|
- lib/data_spec/version.rb
|
91
80
|
- spec/data_spec/block_spec.rb
|
81
|
+
- spec/data_spec/helpers_spec.rb
|
92
82
|
- spec/data_spec/inclusion_spec.rb
|
93
83
|
- spec/data_spec/interpolation_spec.rb
|
94
84
|
- spec/data_spec/matchers_spec.rb
|
@@ -120,9 +110,12 @@ summary: RSpec matchers and Cucumber steps for describing hash and array structu
|
|
120
110
|
including deep nesting
|
121
111
|
test_files:
|
122
112
|
- features/core.feature
|
113
|
+
- features/memory.feature
|
114
|
+
- features/readme.feature
|
123
115
|
- features/step_definitions/steps.rb
|
124
116
|
- features/support/env.rb
|
125
117
|
- spec/data_spec/block_spec.rb
|
118
|
+
- spec/data_spec/helpers_spec.rb
|
126
119
|
- spec/data_spec/inclusion_spec.rb
|
127
120
|
- spec/data_spec/interpolation_spec.rb
|
128
121
|
- spec/data_spec/matchers_spec.rb
|