data_spec 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/narfanator/data_spec.png)](http://travis-ci.org/narfanator/data_spec) [![Dependency Status](https://gemnasium.com/narfanator/data_spec.png)](https://gemnasium.com/narfanator/data_spec) [![Code Climate](https://codeclimate.com/badge.png)](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
|