data_spec 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +176 -0
- data/Rakefile +1 -0
- data/data_spec.gemspec +25 -0
- data/features/core.feature +118 -0
- data/features/step_definitions/steps.rb +4 -0
- data/features/support/env.rb +6 -0
- data/lib/data_spec/cucumber.rb +17 -0
- data/lib/data_spec/helpers.rb +74 -0
- data/lib/data_spec/matchers.rb +54 -0
- data/lib/data_spec/version.rb +3 -0
- data/lib/data_spec.rb +11 -0
- data/spec/data_spec/block_spec.rb +15 -0
- data/spec/data_spec/inclusion_spec.rb +54 -0
- data/spec/data_spec/interpolation_spec.rb +72 -0
- data/spec/data_spec/matchers_spec.rb +106 -0
- data/spec/spec_helper.rb +9 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 41b97a4b8d4e7d9ba659c756dd00132cb8fc8865
|
4
|
+
data.tar.gz: 6991ac05e24b5c297ebabfb3d8795669b6681f6a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4428020420b3c23d340b4893a6bc6882014bf78c860cac3b5540099ec333bf195518c9cfa230cb624ffcc419258ba809129687d190b9cd8b7cc9547f379f38d6
|
7
|
+
data.tar.gz: 7d963c06e3a45144c6b5e05d540ea80a277b90de236cc05170f932b210d4180f0cf7fd6ebe9f09476d5c3077a8c8c9b9819cc4752a6c333e80e199d13e6f9abb
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 nick.barone
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
data_spec
|
2
|
+
========
|
3
|
+
|
4
|
+
Easily compare hashes and arrays in RSpec and Cucumber
|
5
|
+
|
6
|
+
Originally inspired by collectiveidea's json_spec gem
|
7
|
+
|
8
|
+
Installation
|
9
|
+
------------
|
10
|
+
|
11
|
+
gem 'data_spec'
|
12
|
+
{cucumber}
|
13
|
+
{rspec}
|
14
|
+
|
15
|
+
Cucumber
|
16
|
+
------------
|
17
|
+
|
18
|
+
# Setup:
|
19
|
+
|
20
|
+
Include `data_spec/cucumber` and define `data` in your Cucumber environment:
|
21
|
+
```ruby
|
22
|
+
# features/support/env.rb
|
23
|
+
require "data_spec/cucumber"
|
24
|
+
|
25
|
+
def data
|
26
|
+
#...
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
# Usage:
|
31
|
+
|
32
|
+
Use either YAML or JSON:
|
33
|
+
````ruby
|
34
|
+
Given the data is: # You define this one
|
35
|
+
"""
|
36
|
+
chunky: bacon
|
37
|
+
"""
|
38
|
+
Then the data should be:
|
39
|
+
"""
|
40
|
+
{
|
41
|
+
"chunky": "bacon"
|
42
|
+
}
|
43
|
+
"""
|
44
|
+
```
|
45
|
+
|
46
|
+
Use path selection:
|
47
|
+
```ruby
|
48
|
+
Given the data is:
|
49
|
+
"""
|
50
|
+
interleaved:
|
51
|
+
- hashes:
|
52
|
+
and:
|
53
|
+
- arrays
|
54
|
+
"""
|
55
|
+
Then the data at "interleaved/0/hashes" should be:
|
56
|
+
"""
|
57
|
+
and:
|
58
|
+
- arrays
|
59
|
+
"""
|
60
|
+
```
|
61
|
+
|
62
|
+
Check inclusion:
|
63
|
+
```ruby
|
64
|
+
Given the data is:
|
65
|
+
"""
|
66
|
+
- 1
|
67
|
+
- 2
|
68
|
+
- 3
|
69
|
+
- even:
|
70
|
+
'in a': hash
|
71
|
+
'with only': some keys
|
72
|
+
"""
|
73
|
+
Then the data includes:
|
74
|
+
"""
|
75
|
+
- 1
|
76
|
+
- 2
|
77
|
+
"""
|
78
|
+
And the data at "even" includes "'in a': hash"
|
79
|
+
```
|
80
|
+
|
81
|
+
Check types:
|
82
|
+
```ruby
|
83
|
+
Given the data is:
|
84
|
+
"""
|
85
|
+
- bacon
|
86
|
+
- 1
|
87
|
+
- 2013-07-06 20:09:32.824102000 -07:00
|
88
|
+
"""
|
89
|
+
Then the data at "0" is of type String
|
90
|
+
Then the data at "1" is of type Fixnum
|
91
|
+
Then the data at "2" is of type Time
|
92
|
+
```
|
93
|
+
|
94
|
+
Use embedded code:
|
95
|
+
```ruby
|
96
|
+
Given the data is:
|
97
|
+
"""
|
98
|
+
- `1+1`
|
99
|
+
- '$1e2$'
|
100
|
+
- `"bacon".class`
|
101
|
+
"""
|
102
|
+
Then the data at "0" should be 2
|
103
|
+
Then the data at "1" should be 100
|
104
|
+
Then the data at "2" should be `String.class`
|
105
|
+
```
|
106
|
+
(Among other things, this lets you work around Ruby YAML's lack of support for scientific notation)
|
107
|
+
**Note: This is done via a raw `eval`, so it's dangerous**
|
108
|
+
|
109
|
+
#Steps
|
110
|
+
|
111
|
+
* `Then the data should be:`
|
112
|
+
* `Then the data should be "..."`
|
113
|
+
* `Then the data at "..." should be:`
|
114
|
+
* `Then the data at "..." should be "..."`
|
115
|
+
|
116
|
+
* `Then the data includes:`
|
117
|
+
* `Then the data includes "..."`
|
118
|
+
* `Then the data at "..." includes:`
|
119
|
+
* `Then the data at "..." includes "..."`
|
120
|
+
|
121
|
+
* `Then the data is of type ...`
|
122
|
+
* `Then the data at "..." if of type ...`
|
123
|
+
|
124
|
+
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
|
+
|
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]]`
|
127
|
+
|
128
|
+
When checking inclusion against a hash, you need to supply a hash: `{one: :two, three: four}` includes `{one: :two}`
|
129
|
+
|
130
|
+
RSpec
|
131
|
+
--------
|
132
|
+
|
133
|
+
* `match_data(...).at(...)`
|
134
|
+
* `includes_data(...).at(...)`
|
135
|
+
* `match_block(lambda{...}).at(...)`
|
136
|
+
|
137
|
+
Exact matching is (as it turns out!) handled by `==`, while partial matching is handled by http://stackoverflow.com/questions/3826969/ruby-hash-include-another-hash-deep-check
|
138
|
+
Note that pathing is applied to the object being checked: in `hash1.should match_data(hash2).at("path/0")`, `hash1[:path][0]` would be compared to `hash2`.
|
139
|
+
|
140
|
+
Helpers
|
141
|
+
--------
|
142
|
+
* DataSpec::Helpers.at_path(data, path)
|
143
|
+
* DataSpec.parse
|
144
|
+
|
145
|
+
`at_path` is what provides the "pathing" functionality, while `parse` provides interpreting embedded code.
|
146
|
+
|
147
|
+
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, but they're prettier and easier to read.
|
149
|
+
|
150
|
+
Refinements
|
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.
|
155
|
+
|
156
|
+
Issues
|
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
|
163
|
+
|
164
|
+
Contributing
|
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.
|
167
|
+
|
168
|
+
"Minimalist" doesn't mean fewest lines of code (although that's usually the case); it generally means "fewest new functions and objects"
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/data_spec.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'data_spec/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "data_spec"
|
8
|
+
spec.version = DataSpec::VERSION
|
9
|
+
spec.authors = ["narfanator"]
|
10
|
+
spec.email = ["narafanator@gmail.com"]
|
11
|
+
spec.description = %q{RSpec & Cucumber for Data Examination}
|
12
|
+
spec.summary = %q{RSpec matchers and Cucumber steps for describing hash and array structures, including deep nesting}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_dependency "cucumber"
|
24
|
+
spec.add_dependency "rspec"
|
25
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
Feature: Core Steps
|
2
|
+
|
3
|
+
Scenario: JSON / YAML Equality
|
4
|
+
Given the data is:
|
5
|
+
"""
|
6
|
+
- chunky: bacon
|
7
|
+
ordered_by:
|
8
|
+
- person: joe
|
9
|
+
wants:
|
10
|
+
pieces: `1+1`
|
11
|
+
- person: josephina
|
12
|
+
wants:
|
13
|
+
pieces: `1e2`
|
14
|
+
"""
|
15
|
+
Then the data should be:
|
16
|
+
"""
|
17
|
+
{
|
18
|
+
"chunky": "bacon",
|
19
|
+
"ordered_by": [
|
20
|
+
{
|
21
|
+
"person": "joe",
|
22
|
+
"wants": {
|
23
|
+
"pieces": "`1+1`"
|
24
|
+
}
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"person": "josephina",
|
28
|
+
"wants": {
|
29
|
+
"pieces": "`1e2`"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
]
|
33
|
+
}
|
34
|
+
"""
|
35
|
+
|
36
|
+
Scenario: Array Equality
|
37
|
+
Given the data is:
|
38
|
+
"""
|
39
|
+
- 1
|
40
|
+
- array:
|
41
|
+
- 2
|
42
|
+
- chunky: bacon
|
43
|
+
"""
|
44
|
+
Then the data at "1/array/1" should be "chunky: bacon"
|
45
|
+
Then the data should be:
|
46
|
+
"""
|
47
|
+
- 1
|
48
|
+
- array:
|
49
|
+
- 2
|
50
|
+
- chunky: bacon
|
51
|
+
"""
|
52
|
+
|
53
|
+
Scenario: Hash Equality
|
54
|
+
Given the data is:
|
55
|
+
"""
|
56
|
+
one: two
|
57
|
+
three: four
|
58
|
+
five:
|
59
|
+
chunky: bacon
|
60
|
+
bacon: chunky
|
61
|
+
"""
|
62
|
+
Then the data at "five/chunky" should be "bacon"
|
63
|
+
Then the data should be:
|
64
|
+
"""
|
65
|
+
five:
|
66
|
+
bacon: chunky
|
67
|
+
chunky: bacon
|
68
|
+
three: four
|
69
|
+
one: two
|
70
|
+
"""
|
71
|
+
|
72
|
+
Scenario: Inclusion
|
73
|
+
Given the data is:
|
74
|
+
"""
|
75
|
+
array:
|
76
|
+
- chunky: bacon
|
77
|
+
- 2
|
78
|
+
bacon: chunky
|
79
|
+
"""
|
80
|
+
Then the data should include "bacon: chunky"
|
81
|
+
And the data at "array" should include "[2]"
|
82
|
+
And the data should include:
|
83
|
+
"""
|
84
|
+
array:
|
85
|
+
- chunky: bacon
|
86
|
+
- 2
|
87
|
+
"""
|
88
|
+
|
89
|
+
Scenario: Interpolation
|
90
|
+
Given the data is:
|
91
|
+
"""
|
92
|
+
- 1
|
93
|
+
- `1+1`
|
94
|
+
- `1+1+1`
|
95
|
+
"""
|
96
|
+
Then the data should be:
|
97
|
+
"""
|
98
|
+
- 1
|
99
|
+
- 2
|
100
|
+
- 3
|
101
|
+
"""
|
102
|
+
|
103
|
+
Scenario: Types
|
104
|
+
Given the data is:
|
105
|
+
"""
|
106
|
+
date: 2013-07-06 20:09:32.824102000 -07:00
|
107
|
+
fixnum: 1
|
108
|
+
float: 1.0
|
109
|
+
string: bacon
|
110
|
+
hash: {}
|
111
|
+
array: []
|
112
|
+
"""
|
113
|
+
Then the data at "date" is of type Time
|
114
|
+
And the data at "fixnum" is of type Fixnum
|
115
|
+
And the data at "float" is of type Float
|
116
|
+
And the data at "string" is of type String
|
117
|
+
And the data at "hash" is of type Hash
|
118
|
+
And the data at "array" is of type Array
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'data_spec'
|
2
|
+
|
3
|
+
World(DataSpec::Helpers, DataSpec::Matchers, DataSpec::Inclusion, DataSpec::Block)
|
4
|
+
|
5
|
+
# Then the data at "path" should be "data"
|
6
|
+
# Then the data should be: (...)
|
7
|
+
Then(/^the data(?: at "(.*?)")? should be:?(?: "(.*?)")?$/) do |path, inline, *block|
|
8
|
+
data.should match_data(DataSpec.parse(inline || block.first)).at(path)
|
9
|
+
end
|
10
|
+
|
11
|
+
Then(/^the data(?: at "(.*?)")? should include:?(?: "(.*?)")?$/) do |path, inline, *block|
|
12
|
+
data.should include_data(DataSpec.parse(inline || block.first)).at(path)
|
13
|
+
end
|
14
|
+
|
15
|
+
Then(/^the data at "(.*?)" is of type ([A-Z][a-z]+)$/) do |path, type|
|
16
|
+
data.should match_block(lambda{|item| item.is_a? Object.const_get(type)}).at(path)
|
17
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module DataSpec
|
2
|
+
module Refinements
|
3
|
+
refine Array do
|
4
|
+
def tree_walk_with_self &block
|
5
|
+
self.each_with_index do |element, index|
|
6
|
+
if element.is_a? Hash
|
7
|
+
element.tree_walk_with_self &block
|
8
|
+
elsif element.is_a? Array
|
9
|
+
element.tree_walk_with_self &block
|
10
|
+
else
|
11
|
+
yield [index, element], self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def deep_include? sub_array
|
17
|
+
(sub_array - self).empty?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
refine Hash do
|
22
|
+
def tree_walk_with_self &block
|
23
|
+
self.each do |key,value|
|
24
|
+
if value.is_a? Hash
|
25
|
+
value.tree_walk_with_self &block
|
26
|
+
elsif value.is_a? Array
|
27
|
+
value.tree_walk_with_self &block
|
28
|
+
else
|
29
|
+
yield [key,value], self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def deep_include?(sub_hash)
|
35
|
+
sub_hash.keys.all? do |key|
|
36
|
+
self.has_key?(key) && if sub_hash[key].is_a?(Hash)
|
37
|
+
self[key].is_a?(Hash) && self[key].deep_include?(sub_hash[key])
|
38
|
+
else
|
39
|
+
self[key] == sub_hash[key]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
using DataSpec::Refinements
|
48
|
+
module DataSpec
|
49
|
+
module Helpers
|
50
|
+
def self.parse yaml
|
51
|
+
# `code` is more readable, but not parsable, for our purposes we're converting it to $
|
52
|
+
unrendered = YAML.load(yaml.gsub("`", "$"))
|
53
|
+
|
54
|
+
return unrendered unless unrendered.is_a?(Array) || unrendered.is_a?(Hash)
|
55
|
+
|
56
|
+
unrendered.tree_walk_with_self do |(k, v), h|
|
57
|
+
if v =~ /^\$(.+)\$$/
|
58
|
+
h[k] = eval($1)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
def self.at_path data, path
|
63
|
+
return data if path.nil? || path.empty?
|
64
|
+
path.split('/').each do |key|
|
65
|
+
key = key.to_i if data.is_a? Array
|
66
|
+
data = data[key] || data[key.to_sym]
|
67
|
+
end
|
68
|
+
data
|
69
|
+
end
|
70
|
+
end
|
71
|
+
def self.parse string
|
72
|
+
DataSpec::Helpers.parse(string)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'data_spec/helpers'
|
2
|
+
|
3
|
+
using DataSpec::Refinements
|
4
|
+
|
5
|
+
module DataSpec
|
6
|
+
module Matchers
|
7
|
+
extend RSpec::Matchers::DSL
|
8
|
+
|
9
|
+
matcher :match_data do |expected|
|
10
|
+
match do |actual|
|
11
|
+
DataSpec::Helpers.at_path(actual, @path) == expected
|
12
|
+
end
|
13
|
+
|
14
|
+
chain :at do |path|
|
15
|
+
@path = path
|
16
|
+
end
|
17
|
+
|
18
|
+
diffable
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Inclusion
|
23
|
+
extend RSpec::Matchers::DSL
|
24
|
+
|
25
|
+
matcher :include_data do |expected|
|
26
|
+
match do |actual|
|
27
|
+
DataSpec::Helpers.at_path(actual, @path).deep_include? expected
|
28
|
+
end
|
29
|
+
|
30
|
+
chain :at do |path|
|
31
|
+
@path = path
|
32
|
+
end
|
33
|
+
|
34
|
+
diffable
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Block
|
39
|
+
extend RSpec::Matchers::DSL
|
40
|
+
|
41
|
+
matcher :match_block do |block|
|
42
|
+
match do |actual|
|
43
|
+
block.call DataSpec::Helpers.at_path(actual, @path)
|
44
|
+
end
|
45
|
+
|
46
|
+
chain :at do |path|
|
47
|
+
@path = path
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module Interpolation
|
53
|
+
end
|
54
|
+
end
|
data/lib/data_spec.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "data_spec/version"
|
2
|
+
require 'data_spec/helpers'
|
3
|
+
require 'data_spec/matchers'
|
4
|
+
|
5
|
+
if RSpec && RSpec.respond_to?(:configure)
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.include DataSpec::Matchers
|
8
|
+
config.include DataSpec::Inclusion
|
9
|
+
config.include DataSpec::Block
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataSpec::Block do
|
4
|
+
it "can check versus a block" do
|
5
|
+
"chunky".should match_block(lambda{|got| got.is_a? String})
|
6
|
+
"chunky".should_not match_block(lambda{|got| got.is_a? Integer})
|
7
|
+
end
|
8
|
+
|
9
|
+
it "can check versus a block at a path" do
|
10
|
+
[1, 'bacon'].should match_block(lambda{|got| got.is_a? String}).at("1")
|
11
|
+
|
12
|
+
[1, 'bacon'].should_not match_block(lambda{|got| got.is_a? Integer}).at("1")
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataSpec::Inclusion do
|
4
|
+
|
5
|
+
it "can check array inclusion" do
|
6
|
+
[1,2,3].should include_data([2])
|
7
|
+
[1,2,3].should include_data([2,3])
|
8
|
+
|
9
|
+
[1,2,3].should_not include_data([3,4])
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can check nested array inclusion" do
|
13
|
+
[1,[2,3],[4,5],6].should include_data([[2,3]])
|
14
|
+
[1,[2,3],[4,5],6].should include_data([[2,3],[4,5]])
|
15
|
+
|
16
|
+
|
17
|
+
[1,[2,3],[4,5],6].should_not include_data([2,3])
|
18
|
+
[1,[2,3],[4,5],6].should_not include_data([[3,3],[4,5]])
|
19
|
+
[1,[2,3],[4,5],6].should_not include_data([[2,3],[5,5]])
|
20
|
+
[1,[2,3],[4,5],6].should_not include_data([3,4])
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can check hash inclusion" do
|
24
|
+
{one: :two, three: :four}.should include_data({three: :four})
|
25
|
+
|
26
|
+
{one: :two, three: :four}.should_not include_data({four: :four})
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can check nested hash inclusion" do
|
30
|
+
{one: :two, three: {four: :five, seven: :eight}}.should include_data({three: {four: :five}})
|
31
|
+
|
32
|
+
{one: :two, three: {four: :five, seven: :eight}}.should_not include_data({four: :five})
|
33
|
+
{one: :two, three: {four: :five, seven: :eight}}.should_not include_data({three: {nine: :five}})
|
34
|
+
{one: :two, three: {four: :five, seven: :eight}}.should_not include_data({three: {four: :ten}})
|
35
|
+
{one: :two, three: {four: :five, seven: :eight}}.should_not include_data({nine: :ten})
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can check mixed nested inclusion" do
|
39
|
+
[1, {one: :two}].should include_data([{one: :two}])
|
40
|
+
|
41
|
+
[1, {one: :two}].should_not include_data([{two: :two}])
|
42
|
+
|
43
|
+
{one: :two, three: [1,2]}.should include_data({three: [1,2]})
|
44
|
+
|
45
|
+
{one: :two, three: [1,2]}.should_not include_data({three: [2,2]})
|
46
|
+
end
|
47
|
+
|
48
|
+
it "can check at a path" do
|
49
|
+
[1, {array: [2, {chunky: :bacon, bacon: :chunky} ] } ].should include_data({chunky: :bacon}).at("1/array/1")
|
50
|
+
[1, {array: [2, {chunky: :bacon, bacon: :chunky} ] } ].should include_data({chunky: :bacon}).at("1/array/1")
|
51
|
+
|
52
|
+
[1, {array: [2, {chunky: :bacon, bacon: :chunky} ] } ].should_not include_data({chunky: :nocab}).at("1/array/1")
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataSpec::Helpers do
|
4
|
+
|
5
|
+
it "parses YAML" do
|
6
|
+
DataSpec.parse("[1, {array: [2, {chunky: bacon} ] } ]").should match_data([1, {'array' => [2, {'chunky' => 'bacon'} ] } ])
|
7
|
+
yaml =
|
8
|
+
"""
|
9
|
+
- 1
|
10
|
+
- array:
|
11
|
+
- 2
|
12
|
+
- chunky: bacon
|
13
|
+
"""
|
14
|
+
DataSpec.parse(yaml).should match_data([1, {'array' => [2, {'chunky' => 'bacon'} ] } ])
|
15
|
+
end
|
16
|
+
|
17
|
+
it "parses JSON" do
|
18
|
+
DataSpec.parse('[1, {"array": [2, {"chunky": "bacon"} ] } ]').should match_data([1, {'array' => [2, {'chunky' => 'bacon'} ] } ])
|
19
|
+
|
20
|
+
json = <<-eot
|
21
|
+
[
|
22
|
+
1,
|
23
|
+
{
|
24
|
+
"array": [
|
25
|
+
2,
|
26
|
+
{
|
27
|
+
"chunky": "bacon"
|
28
|
+
}
|
29
|
+
]
|
30
|
+
}
|
31
|
+
]
|
32
|
+
eot
|
33
|
+
|
34
|
+
DataSpec.parse(json).should match_data([1, {'array' => [2, {'chunky' => 'bacon'} ] } ])
|
35
|
+
end
|
36
|
+
|
37
|
+
it "interpolates json" do
|
38
|
+
json = <<-eot
|
39
|
+
[
|
40
|
+
1,
|
41
|
+
{
|
42
|
+
"array": [
|
43
|
+
`1+1`,
|
44
|
+
{
|
45
|
+
"chunky": "bacon"
|
46
|
+
}
|
47
|
+
]
|
48
|
+
}
|
49
|
+
]
|
50
|
+
eot
|
51
|
+
DataSpec.parse(json).should match_data([1, {'array' => [2, {'chunky' => 'bacon'} ] } ])
|
52
|
+
end
|
53
|
+
|
54
|
+
it "interpolates array values" do
|
55
|
+
DataSpec.parse("[1, 2, `1+2`]").should match_data([1,2,3])
|
56
|
+
|
57
|
+
DataSpec.parse("[1, 2, `1+2`]").should_not match_data([1,2,4])
|
58
|
+
end
|
59
|
+
|
60
|
+
it "interpolates hash values" do
|
61
|
+
DataSpec.parse("{one: two, three: `2+2`}").should match_data({'one' => 'two', 'three' => 4})
|
62
|
+
|
63
|
+
DataSpec.parse("{one: two, three: `2+2`}").should_not match_data({'one' => 'two', 'three' => 5})
|
64
|
+
end
|
65
|
+
|
66
|
+
it "interpolates nested values" do
|
67
|
+
DataSpec.parse("[1, {array: [`1+1`, {chunky: `'bacon'.to_sym`} ] } ]").should match_data([1, {'array' => [2, {'chunky' => :bacon} ] } ])
|
68
|
+
|
69
|
+
DataSpec.parse("[1, {array: [`1+1`, {chunky: `'bacon'.to_sym`} ] } ]").should_not match_data([1, {'array' => [3, {'chunky' => :bacon} ] } ])
|
70
|
+
DataSpec.parse("[1, {array: [`1+1`, {chunky: `'bacon'.to_sym`} ] } ]").should_not match_data([1, {'array' => [2, {'chunky' => :nocab} ] } ])
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataSpec::Matchers do
|
4
|
+
|
5
|
+
it "should match empty hashes" do
|
6
|
+
{}.should match_data({})
|
7
|
+
{}.should_not match_data([])
|
8
|
+
end
|
9
|
+
it "should match empty arrays" do
|
10
|
+
[].should match_data([])
|
11
|
+
[].should_not match_data({})
|
12
|
+
end
|
13
|
+
it "should match strings" do
|
14
|
+
"Bacon".should match_data("Bacon")
|
15
|
+
"Bacon".should_not match_data("Chunky")
|
16
|
+
end
|
17
|
+
it "should match integers" do
|
18
|
+
1.should match_data(1)
|
19
|
+
2.should_not match_data(1)
|
20
|
+
end
|
21
|
+
it "should match floats" do
|
22
|
+
1.1.should match_data(1.1)
|
23
|
+
2.1.should_not match_data(1.1)
|
24
|
+
end
|
25
|
+
it "should match true" do
|
26
|
+
true.should match_data(true)
|
27
|
+
true.should_not match_data(false)
|
28
|
+
end
|
29
|
+
it "should match false" do
|
30
|
+
false.should match_data(false)
|
31
|
+
false.should_not match_data(true)
|
32
|
+
end
|
33
|
+
it "should match nil" do
|
34
|
+
nil.should match_data(nil)
|
35
|
+
nil.should_not match_data("something")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should match hashes" do
|
39
|
+
{1 => 2}.should match_data({1 => 2})
|
40
|
+
{1 => 2, 3 => 4, 5 => 6}.should match_data({1 => 2, 3 => 4, 5 => 6})
|
41
|
+
{1 => 2, 5 => 6, 3 => 4}.should match_data({1 => 2, 3 => 4, 5 => 6})
|
42
|
+
|
43
|
+
{1 => 2}.should_not match_data({1 => 3})
|
44
|
+
{1 => 2}.should_not match_data({2 => 2})
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should match arrays" do
|
48
|
+
[1,2,3].should match_data([1,2,3])
|
49
|
+
|
50
|
+
[1,2,3].should_not match_data([2,1,3])
|
51
|
+
[1,2,3].should_not match_data([2,2,3])
|
52
|
+
[1,2,3].should_not match_data([1,2])
|
53
|
+
[1,2,3].should_not match_data([1,2,3,4])
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should match hash nesting" do
|
57
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should match_data( { three: :four, nested: { one: :two, hash: { bacon: :chunky, chunky: :bacon } } })
|
58
|
+
|
59
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { four: :four, nested: { one: :two, hash: { bacon: :chunky, chunky: :bacon } } } )
|
60
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { three: :five, nested: { one: :two, hash: { bacon: :chunky, chunky: :bacon } } } )
|
61
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { three: :five, nested: { two: :two, hash: { bacon: :chunky, chunky: :bacon } } } )
|
62
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { three: :five, nested: { one: :one, hash: { bacon: :chunky, chunky: :bacon } } } )
|
63
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { three: :five, nested: { one: :two, hash: { nocab: :chunky, chunky: :bacon } } } )
|
64
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { three: :five, nested: { one: :two, hash: { bacon: :yknuhc, chunky: :bacon } } } )
|
65
|
+
|
66
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { nested: { one: :two, hash: { bacon: :chunky, chunky: :bacon } } })
|
67
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { three: :four, nested: { hash: { bacon: :chunky, chunky: :bacon } } })
|
68
|
+
{ nested: { hash: { chunky: :bacon, bacon: :chunky }, one: :two }, three: :four }.should_not match_data( { three: :four, nested: { one: :two, hash: { chunky: :bacon } } })
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should match array nesting" do
|
72
|
+
[1, [2, [3, 4], 5], 6].should match_data([1, [2, [3, 4], 5], 6])
|
73
|
+
|
74
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([2, [2, [3, 4], 5], 6])
|
75
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [3, [3, 4], 5], 6])
|
76
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [2, [4, 4], 5], 6])
|
77
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [2, [3, 5], 6], 6])
|
78
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [2, [3, 4], 5], 7])
|
79
|
+
|
80
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([ [2, [3, 4], 5], 6])
|
81
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [ [3, 4], 5], 6])
|
82
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [2, [ 4], 5], 6])
|
83
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [2, [3 ], 5], 6])
|
84
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [2, [3, 4] ], 6])
|
85
|
+
[1, [2, [3, 4], 5], 6].should_not match_data([1, [2, [3, 4], 5] ])
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should match mixed nesting" do
|
89
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should match_data([1, {array: [2, {chunky: :bacon} ] } ])
|
90
|
+
|
91
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should_not match_data([2, {array: [2, {chunky: :bacon} ] } ])
|
92
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should_not match_data([1, {yarra: [2, {chunky: :bacon} ] } ])
|
93
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should_not match_data([1, {array: [3, {chunky: :bacon} ] } ])
|
94
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should_not match_data([1, {array: [2, {yknuhc: :bacon} ] } ])
|
95
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should_not match_data([1, {array: [2, {chunky: :nocab} ] } ])
|
96
|
+
|
97
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should_not match_data([ {array: [2, {chunky: :bacon} ] } ])
|
98
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should_not match_data([1, {array: [ {chunky: :bacon} ] } ])
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should match at a path" do
|
102
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should match_data({chunky: :bacon}).at('1/array/1')
|
103
|
+
|
104
|
+
[1, {array: [2, {chunky: :bacon} ] } ].should_not match_data({bacon: :chunky}).at('1/array/1')
|
105
|
+
end
|
106
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: data_spec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- narfanator
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-07 00:00:00.000000000 Z
|
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
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: cucumber
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: RSpec & Cucumber for Data Examination
|
70
|
+
email:
|
71
|
+
- narafanator@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- .rspec
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- data_spec.gemspec
|
83
|
+
- features/core.feature
|
84
|
+
- features/step_definitions/steps.rb
|
85
|
+
- features/support/env.rb
|
86
|
+
- lib/data_spec.rb
|
87
|
+
- lib/data_spec/cucumber.rb
|
88
|
+
- lib/data_spec/helpers.rb
|
89
|
+
- lib/data_spec/matchers.rb
|
90
|
+
- lib/data_spec/version.rb
|
91
|
+
- spec/data_spec/block_spec.rb
|
92
|
+
- spec/data_spec/inclusion_spec.rb
|
93
|
+
- spec/data_spec/interpolation_spec.rb
|
94
|
+
- spec/data_spec/matchers_spec.rb
|
95
|
+
- spec/spec_helper.rb
|
96
|
+
homepage: ''
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project:
|
116
|
+
rubygems_version: 2.0.3
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: RSpec matchers and Cucumber steps for describing hash and array structures,
|
120
|
+
including deep nesting
|
121
|
+
test_files:
|
122
|
+
- features/core.feature
|
123
|
+
- features/step_definitions/steps.rb
|
124
|
+
- features/support/env.rb
|
125
|
+
- spec/data_spec/block_spec.rb
|
126
|
+
- spec/data_spec/inclusion_spec.rb
|
127
|
+
- spec/data_spec/interpolation_spec.rb
|
128
|
+
- spec/data_spec/matchers_spec.rb
|
129
|
+
- spec/spec_helper.rb
|