rspec-json_matchers 0.1.0.alpha.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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +20 -0
  4. data/Appraisals +16 -0
  5. data/CHANGELOG.md +7 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +497 -0
  9. data/Rakefile +14 -0
  10. data/gemfiles/rspec_3_0.gemfile +7 -0
  11. data/gemfiles/rspec_3_1.gemfile +7 -0
  12. data/gemfiles/rspec_3_2.gemfile +7 -0
  13. data/gemfiles/rspec_3_3.gemfile +7 -0
  14. data/lib/rspec/json_matchers/comparers/abstract_comparer.rb +289 -0
  15. data/lib/rspec/json_matchers/comparers/comparison_result.rb +22 -0
  16. data/lib/rspec/json_matchers/comparers/exact_keys_comparer.rb +27 -0
  17. data/lib/rspec/json_matchers/comparers/include_keys_comparer.rb +27 -0
  18. data/lib/rspec/json_matchers/comparers.rb +13 -0
  19. data/lib/rspec/json_matchers/expectation.rb +78 -0
  20. data/lib/rspec/json_matchers/expectations/abstract.rb +36 -0
  21. data/lib/rspec/json_matchers/expectations/core.rb +103 -0
  22. data/lib/rspec/json_matchers/expectations/mixins/built_in.rb +177 -0
  23. data/lib/rspec/json_matchers/expectations/private.rb +181 -0
  24. data/lib/rspec/json_matchers/expectations.rb +14 -0
  25. data/lib/rspec/json_matchers/matchers/be_json_matcher.rb +92 -0
  26. data/lib/rspec/json_matchers/matchers/be_json_with_content_matcher.rb +21 -0
  27. data/lib/rspec/json_matchers/matchers/be_json_with_sizes_matcher.rb +21 -0
  28. data/lib/rspec/json_matchers/matchers/be_json_with_something_matcher.rb +174 -0
  29. data/lib/rspec/json_matchers/matchers.rb +12 -0
  30. data/lib/rspec/json_matchers/utils/collection_keys_extractor.rb +35 -0
  31. data/lib/rspec/json_matchers/utils/key_path/extraction_result.rb +22 -0
  32. data/lib/rspec/json_matchers/utils/key_path/extractor.rb +70 -0
  33. data/lib/rspec/json_matchers/utils/key_path/path.rb +104 -0
  34. data/lib/rspec/json_matchers/utils.rb +10 -0
  35. data/lib/rspec/json_matchers/version.rb +8 -0
  36. data/lib/rspec/json_matchers.rb +15 -0
  37. data/lib/rspec-json_matchers.rb +1 -0
  38. data/rspec-json_matchers.gemspec +47 -0
  39. metadata +245 -0
@@ -0,0 +1,35 @@
1
+ module RSpec
2
+ module JsonMatchers
3
+ module Utils
4
+ # @api private
5
+ class CollectionKeysExtractor
6
+ #
7
+ # @param collection [Array, Hash]
8
+ #
9
+ # @return [Set] set of keys/indexes of the collection
10
+ # @raise [TypeError] When `collection` is not one of expected types
11
+ def self.extract(collection)
12
+ new(collection).extract
13
+ end
14
+
15
+ COLLECTION_TYPE_TO_VALUE_EXTRACTION_PROC_MAP = {
16
+ Array => -> (collection) { collection.each_index.to_a.to_set },
17
+ Hash => -> (collection) { collection.each_key.map(&:to_s).to_set },
18
+ }.freeze
19
+ private_constant :COLLECTION_TYPE_TO_VALUE_EXTRACTION_PROC_MAP
20
+
21
+ attr_reader :collection
22
+
23
+ def initialize(collection)
24
+ @collection = collection
25
+ end
26
+
27
+ def extract
28
+ COLLECTION_TYPE_TO_VALUE_EXTRACTION_PROC_MAP.fetch(collection.class) do
29
+ raise TypeError
30
+ end.call(collection)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ module RSpec
2
+ module JsonMatchers
3
+ module Utils
4
+ # @api private
5
+ module KeyPath
6
+ # Only as a value object
7
+ class ExtractionResult
8
+ attr_reader :object, :successful
9
+
10
+ def initialize(object, successful)
11
+ @object = object
12
+ @successful = successful
13
+ end
14
+
15
+ def failed?
16
+ !successful
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ require_relative "path"
2
+
3
+ module RSpec
4
+ module JsonMatchers
5
+ module Utils
6
+ # @api private
7
+ module KeyPath
8
+ class Extractor
9
+
10
+ private
11
+ attr_accessor *[
12
+ :object,
13
+ ]
14
+ attr_reader *[
15
+ :path,
16
+ ]
17
+ public
18
+
19
+ # Create a new extractor with the "source object"
20
+ # and the path to be used for extracting our target object
21
+ #
22
+ # @param object [Object]
23
+ # The source object to extract our target object from
24
+ # @param path [String, Path]
25
+ # the path of target object
26
+ # Will convert into {Path}
27
+ #
28
+ # @see JsonMatchers::Matchers::BeJsonWithSomethingMatcher#at_path
29
+ def initialize(object, path)
30
+ @object = object
31
+ @path = KeyPath::Path.new(path)
32
+ end
33
+
34
+ # Actually perform the extraction and return the result
35
+ # Since the object could be falsy,
36
+ # an object of custom class is returned instead of the object only
37
+ #
38
+ # Assume the path to be valid
39
+ #
40
+ # @return (see Path#extract)
41
+ def extract
42
+ path.each_path_part do |path_part|
43
+ self.object = case object
44
+ when Hash
45
+ # Allow nil as object, but disallow key to be absent
46
+ unless object.key?(path_part)
47
+ return ExtractionResult.new(object, false)
48
+ end
49
+ object.fetch(path_part)
50
+ when Array
51
+ index = path_part.to_i
52
+ # Disallow index to be out of range
53
+ # Disallow negative number as index
54
+ unless (path_part =~ /\A\d+\z/) && index < object.size
55
+ return ExtractionResult.new(object, false)
56
+ end
57
+ object.slice(index)
58
+ else
59
+ # Disallow non JSON collection type
60
+ return ExtractionResult.new(object, false)
61
+ end
62
+ end
63
+
64
+ ExtractionResult.new(object, true)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,104 @@
1
+ require_relative "extraction_result"
2
+ require_relative "extractor"
3
+
4
+ module RSpec
5
+ module JsonMatchers
6
+ module Utils
7
+ # @api private
8
+ module KeyPath
9
+ class Path
10
+ # The "path part" separator
11
+ # Period is used since it's the least used char as part of a key name
12
+ # (it can never by used for index anyway)
13
+ # As a side effect this char CANNOT be used, escaping is not planned to be added
14
+ PATH_PART_SPLITTER = ".".freeze
15
+ # The regular expression for checking "invalid" path
16
+ # The separator should NOT at the start/end of the string,
17
+ # or repeating itself without other chars in between
18
+ INVALID_PATH_REGEX = %r_(
19
+ ^#{Regexp.escape(PATH_PART_SPLITTER)}
20
+ |
21
+ #{Regexp.escape(PATH_PART_SPLITTER)}{2,}
22
+ |
23
+ #{Regexp.escape(PATH_PART_SPLITTER)}$
24
+ )_x.freeze
25
+
26
+ # Creates a {Path}
27
+ # with a {String} (mainly from external) (will store it internally)
28
+ # or a {Path} (mainly from internal) (will get and assign the string path it internally)
29
+ #
30
+ # @note
31
+ # It does not copy the string object since there is not need
32
+ # This might lead to some strange bug
33
+ #
34
+ # @param path [String, Path]
35
+ # the path to be used
36
+ # {String} is mainly for external use, {Path} for internal use
37
+ #
38
+ # @raise [TypeError] when `path` is not a {String} or {Path}
39
+ def initialize(path)
40
+ case path
41
+ when Path
42
+ @string_path = path.string_path
43
+ when String
44
+ @string_path = path
45
+ else
46
+ raise TypeError, "Only String and Path is expected"
47
+ end
48
+ end
49
+
50
+ def valid?
51
+ !invalid?
52
+ end
53
+
54
+ # Run a loop on all "path parts" without exposing the parts
55
+ # a block is required
56
+ #
57
+ # @yieldparam part [String] a "path part" if the {#string_path}
58
+ #
59
+ # @return [Path] The path object itself
60
+ def each_path_part(&block)
61
+ path_parts.each(&block)
62
+ self
63
+ end
64
+
65
+ # Return successful extraction result when path is empty
66
+ # Return failed extraction result when path is invalid
67
+ # Delegate to {Extractor} otherwise
68
+ #
69
+ # @param object [Object]
70
+ # The "source object" to extract our "target object" from
71
+ #
72
+ # @return [ExtractionResult] The result of object extraction
73
+ def extract(object)
74
+ return ExtractionResult.new(object, true) if empty?
75
+ return ExtractionResult.new(object, false) if invalid?
76
+ Extractor.new(object, self).extract
77
+ end
78
+
79
+ protected
80
+
81
+ attr_reader :string_path
82
+
83
+ private
84
+
85
+ def path_parts
86
+ string_path.split(PATH_PART_SPLITTER)
87
+ end
88
+
89
+ def invalid?
90
+ INVALID_PATH_REGEX =~ string_path
91
+ end
92
+
93
+ def empty?
94
+ path_parts.empty?
95
+ end
96
+
97
+ def to_s
98
+ string_path
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,10 @@
1
+ require_relative "utils/collection_keys_extractor"
2
+ require_relative "utils/key_path/path"
3
+
4
+ module RSpec
5
+ module JsonMatchers
6
+ # @api private
7
+ module Utils
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module RSpec
2
+ module JsonMatchers
3
+ # The version of the gem
4
+ # Used for generating the value in gemspec file
5
+ # Also can be referenced by code for debugging or other purposes
6
+ VERSION = "0.1.0.alpha.1"
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ require "rspec"
2
+
3
+ require_relative "json_matchers/version"
4
+ require_relative "json_matchers/matchers"
5
+ require_relative "json_matchers/expectation"
6
+ require_relative "json_matchers/expectations"
7
+
8
+ # The namespace for {RSpec}
9
+ # We only add {JsonMatchers} to it
10
+ module RSpec
11
+ # The actual namespace for this gem
12
+ # All other classes/modules are defined within this module
13
+ module JsonMatchers
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ require_relative "rspec/json_matchers"
@@ -0,0 +1,47 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rspec/json_matchers/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rspec-json_matchers"
8
+ spec.version = RSpec::JsonMatchers::VERSION
9
+ spec.authors = ["PikachuEXE"]
10
+ spec.email = ["pikachuexe@gmail.com"]
11
+
12
+ spec.summary = %q{A collection of RSpec matchers for testing JSON data.}
13
+ spec.description = <<-DESC
14
+ This gem provides a collection of RSpec matchers for testing JSON data.
15
+ It aims to make JSON testing flexible & easier, especially for testing multiple properties.
16
+ It does not and will not have anything related to JSON Schema.
17
+ DESC
18
+ spec.homepage = "https://github.com/PikachuEXE/rspec-json_matchers"
19
+ spec.license = "MIT"
20
+
21
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "rspec", "~> 3.0"
27
+ spec.add_dependency "awesome_print", "~> 1.6"
28
+ spec.add_dependency "abstract_class", "~> 1.0", ">= 1.0.1"
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.5"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+
33
+ spec.add_development_dependency "appraisal", "~> 2.0"
34
+
35
+ spec.add_development_dependency "rspec-its", "~> 1.0"
36
+
37
+ spec.add_development_dependency "coveralls", "~> 0.8"
38
+
39
+ spec.add_development_dependency "gem-release", "~> 0.7"
40
+
41
+ spec.add_development_dependency "rubocop", "~> 0.32"
42
+ spec.add_development_dependency "inch", "~> 0.6"
43
+
44
+ spec.required_ruby_version = ">= 2.0.0"
45
+
46
+ spec.required_rubygems_version = ">= 1.4.0"
47
+ end
metadata ADDED
@@ -0,0 +1,245 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-json_matchers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.alpha.1
5
+ platform: ruby
6
+ authors:
7
+ - PikachuEXE
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-07-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: awesome_print
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: abstract_class
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 1.0.1
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.0'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.0.1
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.5'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.5'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: appraisal
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '2.0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rspec-its
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '1.0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: coveralls
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.8'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '0.8'
131
+ - !ruby/object:Gem::Dependency
132
+ name: gem-release
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '0.7'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '0.7'
145
+ - !ruby/object:Gem::Dependency
146
+ name: rubocop
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '0.32'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '0.32'
159
+ - !ruby/object:Gem::Dependency
160
+ name: inch
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '0.6'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '0.6'
173
+ description: |2
174
+ This gem provides a collection of RSpec matchers for testing JSON data.
175
+ It aims to make JSON testing flexible & easier, especially for testing multiple properties.
176
+ It does not and will not have anything related to JSON Schema.
177
+ email:
178
+ - pikachuexe@gmail.com
179
+ executables: []
180
+ extensions: []
181
+ extra_rdoc_files: []
182
+ files:
183
+ - ".gitignore"
184
+ - ".travis.yml"
185
+ - Appraisals
186
+ - CHANGELOG.md
187
+ - Gemfile
188
+ - LICENSE.txt
189
+ - README.md
190
+ - Rakefile
191
+ - gemfiles/rspec_3_0.gemfile
192
+ - gemfiles/rspec_3_1.gemfile
193
+ - gemfiles/rspec_3_2.gemfile
194
+ - gemfiles/rspec_3_3.gemfile
195
+ - lib/rspec-json_matchers.rb
196
+ - lib/rspec/json_matchers.rb
197
+ - lib/rspec/json_matchers/comparers.rb
198
+ - lib/rspec/json_matchers/comparers/abstract_comparer.rb
199
+ - lib/rspec/json_matchers/comparers/comparison_result.rb
200
+ - lib/rspec/json_matchers/comparers/exact_keys_comparer.rb
201
+ - lib/rspec/json_matchers/comparers/include_keys_comparer.rb
202
+ - lib/rspec/json_matchers/expectation.rb
203
+ - lib/rspec/json_matchers/expectations.rb
204
+ - lib/rspec/json_matchers/expectations/abstract.rb
205
+ - lib/rspec/json_matchers/expectations/core.rb
206
+ - lib/rspec/json_matchers/expectations/mixins/built_in.rb
207
+ - lib/rspec/json_matchers/expectations/private.rb
208
+ - lib/rspec/json_matchers/matchers.rb
209
+ - lib/rspec/json_matchers/matchers/be_json_matcher.rb
210
+ - lib/rspec/json_matchers/matchers/be_json_with_content_matcher.rb
211
+ - lib/rspec/json_matchers/matchers/be_json_with_sizes_matcher.rb
212
+ - lib/rspec/json_matchers/matchers/be_json_with_something_matcher.rb
213
+ - lib/rspec/json_matchers/utils.rb
214
+ - lib/rspec/json_matchers/utils/collection_keys_extractor.rb
215
+ - lib/rspec/json_matchers/utils/key_path/extraction_result.rb
216
+ - lib/rspec/json_matchers/utils/key_path/extractor.rb
217
+ - lib/rspec/json_matchers/utils/key_path/path.rb
218
+ - lib/rspec/json_matchers/version.rb
219
+ - rspec-json_matchers.gemspec
220
+ homepage: https://github.com/PikachuEXE/rspec-json_matchers
221
+ licenses:
222
+ - MIT
223
+ metadata: {}
224
+ post_install_message:
225
+ rdoc_options: []
226
+ require_paths:
227
+ - lib
228
+ required_ruby_version: !ruby/object:Gem::Requirement
229
+ requirements:
230
+ - - ">="
231
+ - !ruby/object:Gem::Version
232
+ version: 2.0.0
233
+ required_rubygems_version: !ruby/object:Gem::Requirement
234
+ requirements:
235
+ - - ">="
236
+ - !ruby/object:Gem::Version
237
+ version: 1.4.0
238
+ requirements: []
239
+ rubyforge_project:
240
+ rubygems_version: 2.4.6
241
+ signing_key:
242
+ specification_version: 4
243
+ summary: A collection of RSpec matchers for testing JSON data.
244
+ test_files: []
245
+ has_rdoc: