easy_json_matcher 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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