easy_json_matcher 0.2.2 → 0.3.0

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/easy_json_matcher/array_content_validator.rb +22 -0
  3. data/lib/easy_json_matcher/array_generator.rb +41 -0
  4. data/lib/easy_json_matcher/array_validator.rb +11 -76
  5. data/lib/easy_json_matcher/attribute_generator.rb +37 -0
  6. data/lib/easy_json_matcher/attribute_type_methods.rb +29 -0
  7. data/lib/easy_json_matcher/coercion_error.rb +10 -0
  8. data/lib/easy_json_matcher/content_wrapper.rb +2 -4
  9. data/lib/easy_json_matcher/{validation_error.rb → easy_json_matcher_error.rb} +2 -1
  10. data/lib/easy_json_matcher/json_coercer.rb +34 -0
  11. data/lib/easy_json_matcher/node.rb +10 -114
  12. data/lib/easy_json_matcher/node_generator.rb +58 -0
  13. data/lib/easy_json_matcher/schema_generator.rb +47 -71
  14. data/lib/easy_json_matcher/schema_library.rb +8 -11
  15. data/lib/easy_json_matcher/unknown_validation_step_error.rb +10 -0
  16. data/lib/easy_json_matcher/validation_chain_factory.rb +48 -0
  17. data/lib/easy_json_matcher/validation_rules.rb +59 -0
  18. data/lib/easy_json_matcher/validation_step.rb +36 -0
  19. data/lib/easy_json_matcher/validator.rb +12 -87
  20. data/lib/easy_json_matcher/validator_set.rb +31 -0
  21. data/lib/easy_json_matcher/version.rb +1 -1
  22. data/lib/easy_json_matcher.rb +6 -2
  23. data/lib/easy_json_matcher.rb~ +5 -0
  24. data/test/array_content_validator_test.rb +17 -0
  25. data/test/custom_validations_test.rb +17 -17
  26. data/test/global_validation_options_test.rb +39 -44
  27. data/test/json_coercer_test.rb +25 -0
  28. data/test/managing_schemas_test.rb +53 -52
  29. data/test/node_test.rb +28 -0
  30. data/test/primitives_boolean_test.rb +27 -0
  31. data/test/primitives_date_test.rb +28 -0
  32. data/test/primitives_number_test.rb +27 -0
  33. data/test/primitives_object_test.rb +27 -0
  34. data/test/primitives_string_test.rb +27 -0
  35. data/test/primtives_value_test.rb +23 -0
  36. data/test/required_validation_test.rb +7 -7
  37. data/test/schema_generator_test.rb +23 -0
  38. data/test/strict_mode_test.rb +25 -54
  39. data/test/test_helper.rb +8 -6
  40. data/test/validating_arrays_test.rb +40 -132
  41. data/test/validation_chain_factory_test.rb +45 -0
  42. data/test/validation_chain_test_helper.rb +13 -0
  43. data/test/validation_step_array_test.rb +27 -0
  44. data/test/validation_step_boolean_test.rb +19 -0
  45. data/test/validation_step_date_test.rb +20 -0
  46. data/test/validation_step_not_required_test.rb +35 -0
  47. data/test/validation_step_number_test.rb +23 -0
  48. data/test/validation_step_object_test.rb +20 -0
  49. data/test/validation_step_required_test.rb +19 -0
  50. data/test/validation_step_string_test.rb +20 -0
  51. data/test/validation_step_test.rb +55 -0
  52. data/test/validation_step_value_test.rb +15 -0
  53. data/test/validator_set_test.rb +49 -0
  54. data/test/validator_test.rb +44 -0
  55. metadata +64 -26
  56. data/lib/easy_json_matcher/boolean_validator.rb +0 -14
  57. data/lib/easy_json_matcher/date_validator.rb +0 -44
  58. data/lib/easy_json_matcher/node.rb~ +0 -121
  59. data/lib/easy_json_matcher/number_validator.rb +0 -22
  60. data/lib/easy_json_matcher/object_validator.rb +0 -12
  61. data/lib/easy_json_matcher/schema_generator.rb~ +0 -104
  62. data/lib/easy_json_matcher/string_validator.rb +0 -16
  63. data/lib/easy_json_matcher/validator.rb~ +0 -99
  64. data/lib/easy_json_matcher/validator_factory.rb +0 -76
  65. data/lib/easy_json_matcher/value_validator.rb +0 -10
  66. data/lib/easy_json_matcher/version.rb~ +0 -3
  67. data/test/custom_validations_test.rb~ +0 -25
  68. data/test/easy_json_matcher_test.rb +0 -262
  69. data/test/easy_json_matcher_test.rb~ +0 -262
  70. data/test/error_messages_test.rb +0 -148
  71. data/test/reset_test.rb +0 -32
  72. data/test/reset_test.rb~ +0 -32
@@ -1,104 +0,0 @@
1
- require 'easy_json_matcher/validator_factory'
2
- require 'easy_json_matcher/node'
3
- require 'easy_json_matcher/schema_library'
4
- require 'easy_json_matcher/exceptions'
5
- module EasyJSONMatcher
6
- class SchemaGenerator
7
-
8
- attr_reader :node, :name, :options, :glob_opts
9
-
10
- def initialize(opts: {}, global_opts: {})
11
- @name = opts.delete(:key)
12
- @options = opts
13
- @glob_opts = global_opts
14
- yield self if block_given?
15
- end
16
-
17
- def has_attribute(key:, opts: {})
18
- node.add_validator(_create_validator(key, opts))
19
- end
20
-
21
- ################ Methods for adding specific attribute types ##############
22
-
23
- def contains_node(key:, opts: {})
24
- generator = _node_generator _validator_opts(key, opts)
25
- yield generator if block_given?
26
- node.add_validator generator.generate_schema
27
- end
28
-
29
- def has_boolean(key:, opts: {})
30
- has_attribute(key: key, opts: opts.merge({type: :boolean}))
31
- end
32
-
33
- def has_number(key: , opts: {})
34
- has_attribute(key: key, opts: opts.merge({type: :number}))
35
- end
36
-
37
- def has_date(key:, opts: {})
38
- has_attribute(key: key, opts: opts.merge({type: :date}))
39
- end
40
-
41
- def has_object(key:, opts: {})
42
- has_attribute(key: key, opts: opts.merge({type: :object}))
43
- end
44
-
45
- def has_value(key:, opts: {})
46
- has_attribute(key: key, opts: opts.merge({type: :value}))
47
- end
48
-
49
- def has_string(key:, opts: {})
50
- has_attribute(key: key, opts: opts.merge({type: :string}))
51
- end
52
-
53
- def contains_array(key:, opts: {})
54
- opts = opts.merge!({type: :array})
55
- array_validator = _create_validator(key, opts)
56
- yield array_validator if block_given?
57
- node.add_validator array_validator
58
- end
59
-
60
- def has_schema(key:, opts: {})
61
- has_attribute(key: key, opts: opts.merge({type: :schema}))
62
- end
63
-
64
- ################ Methods for generating the schema #########################
65
-
66
- def generate_schema
67
- node
68
- end
69
-
70
- def register(as:)
71
- SchemaLibrary.add_schema(name: as, schema: generate_schema)
72
- generate_schema
73
- end
74
-
75
- ################## Private methods #########################################
76
-
77
- def _prep_schema_opts(schema_name, opts)
78
- opts[:type] = :schema
79
- opts[:name] = schema_name
80
- opts
81
- end
82
-
83
- def _set_validator_key(validator, key)
84
- validator.key = key
85
- end
86
-
87
- def _validator_opts(key, opts)
88
- opts[:key] = key
89
- glob_opts.merge(opts)
90
- end
91
-
92
- def _create_validator(key, opts)
93
- ValidatorFactory.get_instance type: opts[:type], opts: _validator_opts(key, opts)
94
- end
95
-
96
- def _node_generator(opts = {})
97
- self.class.new opts: opts, global_opts: glob_opts
98
- end
99
-
100
- def node
101
- @node ||= Node.new(opts: _validator_opts(name, options))
102
- end
103
- end
104
- end
@@ -1,16 +0,0 @@
1
- require 'easy_json_matcher/validator'
2
- module EasyJSONMatcher
3
-
4
- class StringValidator < Validator
5
-
6
- def _validate
7
- # Could possible have a meta-method here that takes a list of symbols representing validator names
8
- # and executes them in the validator of self.
9
- _content_is_a_string?
10
- end
11
-
12
- def _content_is_a_string?
13
- errors << "#{content} is not a String" unless content.is_a? String
14
- end
15
- end
16
- end
@@ -1,99 +0,0 @@
1
- module EasyJSONMatcher
2
- class Validator
3
-
4
- attr_reader :content, :required, :errors, :custom_validator
5
- attr_accessor :key
6
-
7
- def initialize(options: {})
8
- @key = options[:key]
9
- @required = options[:required]
10
- @custom_validator = options[:custom_validator]
11
- @errors = []
12
- _post_initialise(options)
13
- end
14
-
15
- # Hook. Allows further setup to be carried out by subclasses
16
- def _post_initialise(options); end
17
-
18
- def valid?(candidate)
19
- if key
20
- return false unless _check_content_type(candidate)
21
- end
22
- _set_content(candidate) #Hook
23
- if content.nil?
24
- _check_required?
25
- else
26
- _validate #Hook
27
- end
28
- _run_custom_validator if custom_validator
29
- _no_errors?
30
- end
31
-
32
- # Hook. Overriden in Node
33
- def reset!
34
- errors.clear
35
- end
36
-
37
- # Hook
38
- # Protected method that Validators use to implement their validation logic.
39
- # Called by #valid?
40
- def _validate
41
- raise NotImplementedError.new "Validators must override _validate"
42
- end
43
-
44
- # Hook
45
- # Protected method that Validators use to set their content from the candidate.
46
- def _set_content(candidate)
47
- @content = key ? candidate[key] : candidate
48
- end
49
-
50
- # Hook.
51
- # This method returns the errors that this validator has found in the candidate.
52
- def get_errors
53
- error_message = {}
54
- error_message[key.to_sym] = errors
55
- error_message
56
- end
57
-
58
- # This method makees sure that the candidate behaves like a Hash, and not a
59
- # value or an array.
60
- def _check_content_type(candidate)
61
- # TODO perhaps this should raise an error instead of returning false?
62
- # if the value that has arrived at this point doesn't behave like a Hash then it
63
- # is in the wrong place.
64
- begin
65
- candidate[key]
66
- rescue TypeError
67
- return false
68
- end
69
- true
70
- end
71
-
72
- def _check_required?
73
- if required
74
- errors << "Value was not present"
75
- return true
76
- else
77
- return false
78
- end
79
- end
80
-
81
- def _create_validator(type:, opts: {})
82
- ValidatorFactory.get_instance(type: type, opts: opts)
83
- end
84
-
85
- def _custom_validator?
86
- custom_validator
87
- end
88
-
89
- def _run_custom_validator
90
- if error_message = custom_validator.call(content)
91
- errors << error_message
92
- end
93
- end
94
-
95
- def _no_errors?
96
- errors.empty?
97
- end
98
- end
99
- end
@@ -1,76 +0,0 @@
1
- require 'easy_json_matcher/object_validator'
2
- require 'easy_json_matcher/string_validator'
3
- require 'easy_json_matcher/number_validator'
4
- require 'easy_json_matcher/date_validator'
5
- require 'easy_json_matcher/boolean_validator'
6
- require 'easy_json_matcher/array_validator'
7
- require 'easy_json_matcher/value_validator'
8
- module EasyJSONMatcher
9
- class ValidatorFactory
10
-
11
- class << self
12
- def get_instance(type:, opts: {})
13
- raise "Type must be specified" unless type
14
- if type == :schema
15
- SchemaLibrary.get_schema(name: opts[:name], opts: opts)
16
- else
17
- validator_class = get_type(type)
18
- validator_class.new options: opts
19
- end
20
- end
21
-
22
- def get_type(name)
23
- case name
24
- when nil
25
- default_validator
26
- when :object
27
- object_validator
28
- when :string
29
- string_validator
30
- when :number
31
- number_validator
32
- when :date
33
- date_validator
34
- when :boolean
35
- boolean_validator
36
- when :array
37
- array_validator
38
- when :value
39
- value_validator
40
- end
41
- end
42
-
43
- def default_validator
44
- value_validator
45
- end
46
-
47
- def object_validator
48
- ObjectValidator
49
- end
50
-
51
- def string_validator
52
- StringValidator
53
- end
54
-
55
- def number_validator
56
- NumberValidator
57
- end
58
-
59
- def date_validator
60
- DateValidator
61
- end
62
-
63
- def boolean_validator
64
- BooleanValidator
65
- end
66
-
67
- def array_validator
68
- ArrayValidator
69
- end
70
-
71
- def value_validator
72
- ValueValidator
73
- end
74
- end
75
- end
76
- end
@@ -1,10 +0,0 @@
1
- require 'easy_json_matcher/validator'
2
- module EasyJSONMatcher
3
-
4
- class ValueValidator < Validator
5
-
6
- def _validate
7
- true
8
- end
9
- end
10
- end
@@ -1,3 +0,0 @@
1
- module EasyJSONMatcher
2
- VERSION = "0.2.1".freeze
3
- end
@@ -1,25 +0,0 @@
1
- require 'test_helper'
2
-
3
- class CustomValidationsTest < ActiveSupport::TestCase
4
-
5
- test 'As a user, I want to be able to specify custom validations' do
6
- test_schema = EasyJSONMatcher::SchemaGenerator.new do |s|
7
- string_validator = ->(candidate) { "String did not say 'hi'" unless candidate == 'hi' }
8
- s.has_string key: :a_string, opts: { custom_validator: string_validator }
9
- end.generate_schema
10
-
11
- should_not_validate = {
12
- a_string: 'go away'
13
- }.to_json
14
-
15
- assert_not(test_schema.valid?(should_not_validate))
16
-
17
- should_validate = {
18
- a_string: 'hi'
19
- }.to_json
20
-
21
- test_schema.reset!
22
-
23
- assert(test_schema.valid?(should_validate), test_schema.get_errors)
24
- end
25
- end
@@ -1,262 +0,0 @@
1
- require 'test_helper'
2
- require 'json'
3
-
4
- # This test suite covers the basic concept of validating that a value is a
5
- # certain type
6
- class EasyJSONMatcherTest < ActiveSupport::TestCase
7
-
8
- test "As a user I want to create new Schemas to match JSON objects" do
9
- # This test represents the minimum level of implementation required to create a
10
- # working node.
11
- test_schema = EasyJSONMatcher::SchemaGenerator.new { |schema|
12
- schema.contains_node(key: :data) do |node|
13
- node.has_attribute(key: :title, opts: {type: :string})
14
- end
15
- }.register(as: :test)
16
-
17
- valid_json = {
18
- data: {
19
- 'title'=> "here's a title"
20
- }
21
- }.to_json
22
- assert(test_schema.valid? valid_json)
23
- end
24
-
25
- # The first thing the gem ought to do is to check that the JSON candidate is actually JSON
26
- test "As a user, if the validation candidate cannot be parsed as JSON, the schema should not be valid" do
27
- test_schema = EasyJSONMatcher::SchemaGenerator.new {|s|
28
- s.has_number(key: :population_of_china_1970)
29
- }.generate_schema
30
-
31
- invalid_json = "'population_of_china_1970' 810000000"
32
-
33
- assert_not(test_schema.valid? invalid_json)
34
- end
35
-
36
-
37
- test "As a user I want to be able to validate strings" do
38
- test_schema = EasyJSONMatcher::SchemaGenerator.new {|schema|
39
- schema.has_string(key: :string, opts: { required: :true})
40
- }.generate_schema
41
-
42
- valid_json = {
43
- string: "Mrs Mogs Hamilton"
44
- }.to_json
45
-
46
- assert(test_schema.valid?(valid_json), 'String was not validated')
47
-
48
- # There isn't really a clear case for the string validator picking up if a
49
- # value is not intended to be a string since all json values are effectively
50
- # strings, and how is the library to know if the client meant 16 to be passed
51
- # as a number or as a string?
52
- # invalid_json = {
53
- # string: 16
54
- # }.to_json
55
- #
56
- # assert_not(test_schema.valid?(invalid_json), 'Number was validated as a string')
57
- end
58
-
59
-
60
- test "As a user I want to be able to validate numbers" do
61
-
62
- test_schema = EasyJSONMatcher::SchemaGenerator.new {|schema|
63
- schema.has_number(key: :number, opts: {required: :true})
64
- }.generate_schema
65
-
66
- valid_json = {
67
- number: 5.55,
68
- }.to_json
69
-
70
- assert(test_schema.valid?(valid_json), "Number was not validated")
71
-
72
- invalid_json = {
73
- number: "hi"
74
- }.to_json
75
- assert_not(test_schema.valid?(invalid_json), "\"hi\" should not have been valid")
76
-
77
- invalid_nil = {
78
- number: nil
79
- }.to_json
80
- assert_not(test_schema.valid?(invalid_nil), "#{invalid_nil} should not have validated, or thrown an error")
81
- end
82
-
83
- test "As a user I want to be able to validate booleans" do
84
-
85
- test_schema = EasyJSONMatcher::SchemaGenerator.new {|schema|
86
- schema.has_boolean(key: :true)
87
- schema.has_boolean(key: :false)
88
- }.generate_schema
89
-
90
- valid_json = {
91
- true: true,
92
- false: false
93
- }.to_json
94
-
95
- assert(test_schema.valid?(valid_json), "Boolean was not validated")
96
-
97
- invalid_json = {
98
- true: 1,
99
- false: "wibble"
100
- }.to_json
101
-
102
- # byebug
103
- assert_not(test_schema.valid?(invalid_json), "\"1\" and \"wibble\" are not valid boolean values")
104
- end
105
-
106
- test "As a user I want to be able to validate Array values" do
107
- test_schema = EasyJSONMatcher::SchemaGenerator.new {|schema|
108
- schema.has_attribute(key: :array, opts: {type: :array})
109
- }.generate_schema
110
-
111
- valid_json = {
112
- array: []
113
- }.to_json
114
-
115
- assert(test_schema.valid?(valid_json), "Array was not validated")
116
-
117
- invalid_json = {
118
- array: 1
119
- }.to_json
120
-
121
- assert(!test_schema.valid?(invalid_json), "\"1\" is not a valid array value")
122
- end
123
-
124
- test "As a user I want to be able to validate date values" do
125
- test_schema = EasyJSONMatcher::SchemaGenerator.new { |schema|
126
- schema.has_date(key: :date)
127
- }.generate_schema
128
-
129
- valid_json = {
130
- date: "2015-01-15"
131
- }.to_json
132
-
133
- assert(test_schema.valid?(valid_json), "Date was not validated")
134
-
135
- not_a_date = 'Good Night Mr. Tom'
136
- invalid_json = {
137
- date: not_a_date
138
- }.to_json
139
-
140
- assert_not(test_schema.valid?(invalid_json), "\"#{not_a_date}\" should not have been validated as a date")
141
- end
142
-
143
- test "As a user I want to be able to use different types of date format" do
144
- flunk "Implement me"
145
- end
146
-
147
- test "As a user I want to validate object values" do
148
- test_schema = EasyJSONMatcher::SchemaGenerator.new { |schema|
149
- schema.has_object(key: :object)
150
- }.generate_schema
151
-
152
- is_an_object = {}
153
-
154
- valid_json = {
155
- object: is_an_object
156
- }.to_json
157
-
158
- assert(test_schema.valid?(valid_json),"#{is_an_object} was not validated as an object" )
159
-
160
- not_an_object = "Popular Music"
161
-
162
- invalid_json = {
163
- object: not_an_object
164
- }.to_json
165
-
166
- assert_not(test_schema.valid?(invalid_json), "#{not_an_object} should not have validated as an object")
167
- end
168
-
169
- # Refers to validation of a JSON value attribute. This one is slightly tricky
170
- # though since attempting to access a Ruby Hash with a missing key will return
171
- # nil. The ValueValidator (or indeed any Validator) will accept nil as a value
172
- # when the value is not marked as required.
173
- # ValueValidator we will be stuck because although the other Validator
174
- # classes nil indicates a missing value, in the case of the ValueValidator null is
175
- # a valid value and we just want to check that there is a key available.
176
- test "As a user I want to validate json value attributes" do
177
- test_schema = EasyJSONMatcher::SchemaGenerator.new {|schema|
178
- schema.has_value(key: :array)
179
- schema.has_value(key: :boolean)
180
- schema.has_value(key: :date)
181
- schema.has_value(key: :number)
182
- schema.has_value(key: :object)
183
- schema.has_value(key: :string)
184
- schema.has_value(key: :null)
185
- }.generate_schema
186
-
187
-
188
- valid_json = {
189
- array: [],
190
- boolean: true,
191
- date: Date.today,
192
- number: 1.11,
193
- object: {},
194
- string: 'The Tenderness of Wolves',
195
- null: nil
196
- }.to_json
197
-
198
- assert(test_schema.valid?(valid_json), 'Value did not validate')
199
-
200
- # There is no 'negative' test for this validator at this stage, since
201
- # the lack of a value does not mean the key is required. See the tests
202
- # on required validation later on.
203
- end
204
-
205
- test "As a user I want to validate nested json objects" do
206
- test_schema = EasyJSONMatcher::SchemaGenerator.new {|schema|
207
- schema.has_attribute(key: :level_1_attribute, opts: {type: :number})
208
- schema.contains_node(key: :level_2) do |n|
209
- n.has_attribute(key: :level_2_attribute, opts: {type: :number})
210
- n.contains_node(key: :level_3) do |n3|
211
- n3.has_attribute(key: :level_3_attribute, opts: {type: :number})
212
- end
213
- end
214
- }.generate_schema
215
-
216
- valid_json = {
217
- level_1_attribute: 1,
218
- level_2:{
219
- level_2_attribute: 2,
220
- level_3:{
221
- level_3_attribute: 3
222
- }
223
- }
224
- }.to_json
225
-
226
- assert(test_schema.valid?(valid_json), "Nested JSON was not correctly validated")
227
- end
228
-
229
- test "As a user, if I specify a node and the content is not a node, it should be invalid without raising an error" do
230
- test_schema = EasyJSONMatcher::SchemaGenerator.new {|schema|
231
- schema.has_attribute(key: :fish_name, opts: {type: :string, required: :true})
232
- schema.contains_node(key: :scientific_name) do |n|
233
- n.has_attribute(key: :genus, opts: {type: :string, required: :true})
234
- n.has_attribute(key: :species, opts: {type: :string, required: :true})
235
- end
236
- }.generate_schema
237
-
238
- valid_json = {
239
- fish_name: 'Clownfish',
240
- scientific_name: {
241
- genus: 'Amphiprion',
242
- species: 'ocellaris'
243
- }
244
- }.to_json
245
-
246
- assert(test_schema.valid?(valid_json), "#{valid_json} should have been valid")
247
-
248
- invalid_with_array = {
249
- fish_name: 'Green Mandarin',
250
- scientific_name: ['Synchiropus', 'splendidus']
251
- }.to_json
252
-
253
- assert_not(test_schema.valid?(invalid_with_array), "#{invalid_with_array} should not have been valid as it has an array instead of a node")
254
-
255
- invalid_with_primitive = {
256
- fish_name: 'Hawaiian Tang',
257
- scientific_name: 'Zebrasoma flavescens'
258
- }.to_json
259
-
260
- assert_not(test_schema.valid?(invalid_with_primitive), "#{invalid_with_primitive} shoudl not have been valid as it has a primite instead of a node")
261
- end
262
- end