data_spec 0.0.1
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 +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
|