jsonschema 1.0.0 → 2.0.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.
- data/lib/jsonschema.rb +206 -335
- data/test/jsonschema_test.rb +204 -7
- metadata +17 -5
data/lib/jsonschema.rb
CHANGED
@@ -2,376 +2,260 @@
|
|
2
2
|
|
3
3
|
module JSON
|
4
4
|
class Schema
|
5
|
-
VERSION = '
|
5
|
+
VERSION = '2.0.0'
|
6
6
|
class ValueError < Exception;end
|
7
|
+
class Undefined;end
|
7
8
|
TypesMap = {
|
8
9
|
"string" => String,
|
9
|
-
"integer" => Integer,
|
10
|
-
"number" => [Integer, Float],
|
10
|
+
"integer" => [Integer, Fixnum],
|
11
|
+
"number" => [Integer, Float, Fixnum, Numeric],
|
11
12
|
"boolean" => [TrueClass, FalseClass],
|
12
13
|
"object" => Hash,
|
13
14
|
"array" => Array,
|
14
15
|
"null" => NilClass,
|
15
16
|
"any" => nil
|
16
17
|
}
|
17
|
-
TypesList = [String, Integer, Float, TrueClass, FalseClass, Hash, Array, NilClass]
|
18
|
-
|
19
|
-
"id" => nil,
|
20
|
-
"type" => nil,
|
21
|
-
"properties" => nil,
|
22
|
-
"items" => nil,
|
23
|
-
"optional" => false,
|
24
|
-
"additionalProperties" => nil,
|
25
|
-
"requires" => nil,
|
26
|
-
"identity" => nil,
|
27
|
-
"minimum" => nil,
|
28
|
-
"maximum" => nil,
|
29
|
-
"minItems" => nil,
|
30
|
-
"maxItems" => nil,
|
31
|
-
"pattern" => nil,
|
32
|
-
"maxLength" => nil,
|
33
|
-
"minLength" => nil,
|
34
|
-
"enum" => nil,
|
35
|
-
"options" => nil,
|
36
|
-
"readonly" => nil,
|
37
|
-
"title" => nil,
|
38
|
-
"description" => nil,
|
39
|
-
"format" => nil,
|
40
|
-
"default" => nil,
|
41
|
-
"transient" => nil,
|
42
|
-
"maxDecimal" => nil,
|
43
|
-
"hidden" => nil,
|
44
|
-
"disallow" => nil,
|
45
|
-
"extends" => nil
|
46
|
-
}
|
47
|
-
def initialize interactive=true
|
18
|
+
TypesList = [String, Integer, Float, Fixnum, Numeric, TrueClass, FalseClass, Hash, Array, NilClass]
|
19
|
+
def initialize interactive
|
48
20
|
@interactive = interactive
|
49
21
|
@refmap = {}
|
50
22
|
end
|
51
23
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
24
|
+
def check_property value, schema, key, parent
|
25
|
+
if schema
|
26
|
+
# if @interactive && schema['readonly']
|
27
|
+
# raise ValueError, "#{key} is a readonly field , it can not be changed"
|
28
|
+
# end
|
58
29
|
|
59
|
-
|
60
|
-
|
61
|
-
unless id.nil?
|
62
|
-
if id == '$'
|
63
|
-
raise ValueError, "Reference id for field '#{fieldname}' cannot equal '$'"
|
30
|
+
if schema['id']
|
31
|
+
@refmap[schema['id']] = schema
|
64
32
|
end
|
65
|
-
@refmap[id] = schema
|
66
|
-
end
|
67
|
-
return x
|
68
|
-
end
|
69
33
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
ensure
|
78
|
-
val = x[fieldname]
|
79
|
-
end
|
80
|
-
if converted_fieldtype && fieldexists
|
81
|
-
if converted_fieldtype.kind_of? Array
|
82
|
-
datavalid = false
|
83
|
-
converted_fieldtype.each do |type|
|
84
|
-
begin
|
85
|
-
validate_type(x, fieldname, type, type)
|
86
|
-
datavalid = true
|
87
|
-
break
|
88
|
-
rescue ValueError
|
89
|
-
next
|
90
|
-
end
|
91
|
-
end
|
92
|
-
unless datavalid
|
93
|
-
raise ValueError, "Value #{val} for field '#{fieldname}' is not of type #{fieldtype}"
|
34
|
+
if schema['extends']
|
35
|
+
check_property(value, schema['extends'], key, parent)
|
36
|
+
end
|
37
|
+
|
38
|
+
if value == Undefined
|
39
|
+
unless schema['optional']
|
40
|
+
raise ValueError, "#{key} is missing and it is not optional"
|
94
41
|
end
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
42
|
+
|
43
|
+
# default
|
44
|
+
if @interactive && !parent.include?(key) && !schema['default'].nil?
|
45
|
+
unless schema["readonly"]
|
46
|
+
parent[key] = schema['default']
|
47
|
+
end
|
100
48
|
end
|
101
49
|
else
|
102
|
-
|
103
|
-
|
50
|
+
|
51
|
+
# type
|
52
|
+
if schema['type']
|
53
|
+
check_type(value, schema['type'], key, parent)
|
104
54
|
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
return x
|
108
|
-
end
|
109
55
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
__validate(key, value, val)
|
118
|
-
end
|
119
|
-
else
|
120
|
-
raise ValueError, "Properties definition of field '#{fieldname}' is not an object"
|
56
|
+
# disallow
|
57
|
+
if schema['disallow']
|
58
|
+
flag = true
|
59
|
+
begin
|
60
|
+
check_type(value, schema['disallow'], key, parent)
|
61
|
+
rescue ValueError
|
62
|
+
flag = false
|
121
63
|
end
|
64
|
+
raise ValueError, "disallowed value was matched" if flag
|
122
65
|
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
return x
|
126
|
-
end
|
127
66
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
67
|
+
unless value.nil?
|
68
|
+
if value.instance_of? Array
|
69
|
+
if schema['items']
|
70
|
+
if schema['items'].instance_of?(Array)
|
71
|
+
schema['items'].each_with_index {|val, index|
|
72
|
+
check_property(undefined_check(value, index), schema['items'][index], index, value)
|
73
|
+
}
|
74
|
+
if schema.include?('additionalProperties')
|
75
|
+
additional = schema['additionalProperties']
|
76
|
+
if additional.instance_of?(FalseClass)
|
77
|
+
if schema['items'].size < value.size
|
78
|
+
raise ValueError, "There are more values in the array than are allowed by the items and additionalProperties restrictions."
|
79
|
+
end
|
80
|
+
else
|
81
|
+
value.each_with_index {|val, index|
|
82
|
+
check_property(undefined_check(value, index), schema['additionalProperties'], index, value)
|
83
|
+
}
|
84
|
+
end
|
140
85
|
end
|
86
|
+
else
|
87
|
+
value.each_with_index {|val, index|
|
88
|
+
check_property(undefined_check(value, index), schema['items'], index, value)
|
89
|
+
}
|
141
90
|
end
|
142
|
-
else
|
143
|
-
raise ValueError, "Length of list #{value} for field '#{fieldname}' is not equal to length of schema list"
|
144
91
|
end
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
92
|
+
if schema['minItems'] && value.size < schema['minItems']
|
93
|
+
raise ValueError, "There must be a minimum of #{schema['minItems']} in the array"
|
94
|
+
end
|
95
|
+
if schema['maxItems'] && value.size > schema['maxItems']
|
96
|
+
raise ValueError, "There must be a maximum of #{schema['maxItems']} in the array"
|
97
|
+
end
|
98
|
+
elsif schema['properties']
|
99
|
+
check_object(value, schema['properties'], schema['additionalProperties'])
|
100
|
+
elsif schema.include?('additionalProperties')
|
101
|
+
additional = schema['additionalProperties']
|
102
|
+
unless additional.instance_of?(TrueClass)
|
103
|
+
if additional.instance_of?(Hash) || additional.instance_of?(FalseClass)
|
104
|
+
properties = {}
|
105
|
+
value.each {|k, val|
|
106
|
+
if additional.instance_of?(FalseClass)
|
107
|
+
raise ValueError, "Additional properties not defined by 'properties' are not allowed in field '#{k}'"
|
108
|
+
else
|
109
|
+
check_property(val, schema['additionalProperties'], k, value)
|
110
|
+
end
|
111
|
+
}
|
112
|
+
else
|
113
|
+
raise ValueError, "additionalProperties schema definition for field '#{}' is not an object"
|
151
114
|
end
|
152
115
|
end
|
153
|
-
else
|
154
|
-
raise ValueError, "Properties definition of field '#{fieldname}' is not a list or an object"
|
155
116
|
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
return x
|
160
|
-
end
|
161
117
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
end
|
118
|
+
if value.instance_of?(String)
|
119
|
+
# pattern
|
120
|
+
if schema['pattern'] && !(value =~ Regexp.new(schema['pattern']))
|
121
|
+
raise ValueError, "does not match the regex pattern #{schema['pattern']}"
|
122
|
+
end
|
168
123
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
properties = {}
|
179
|
-
end
|
180
|
-
value.keys.each do |key|
|
181
|
-
unless properties.include? key
|
182
|
-
if additional_properties.kind_of? FalseClass
|
183
|
-
raise ValueError, "Additional properties not defined by 'properties' are not allowed in field '#{fieldname}'"
|
184
|
-
else
|
185
|
-
__validate(key, value, additional_properties)
|
124
|
+
strlen = value.split(//).size
|
125
|
+
# maxLength
|
126
|
+
if schema['maxLength'] && strlen > schema['maxLength']
|
127
|
+
raise ValueError, "may only be #{schema['maxLength']} characters long"
|
128
|
+
end
|
129
|
+
|
130
|
+
# minLength
|
131
|
+
if schema['minLength'] && strlen < schema['minLength']
|
132
|
+
raise ValueError, "must be at least #{schema['minLength']} characters long"
|
186
133
|
end
|
187
134
|
end
|
188
|
-
end
|
189
|
-
else
|
190
|
-
raise ValueError, "additionalProperties schema definition for field '#{fieldname}' is not an object"
|
191
|
-
end
|
192
|
-
end
|
193
|
-
return x
|
194
|
-
end
|
195
135
|
|
196
|
-
|
197
|
-
if x[fieldname] && !requires.nil?
|
198
|
-
unless x[requires]
|
199
|
-
raise ValueError, "Field '#{requires}' is required by field '#{fieldname}'"
|
200
|
-
end
|
201
|
-
end
|
202
|
-
return x
|
203
|
-
end
|
136
|
+
if value.kind_of?(Numeric)
|
204
137
|
|
205
|
-
|
206
|
-
|
207
|
-
|
138
|
+
# minimum + minimumCanEqual
|
139
|
+
if schema['minimum']
|
140
|
+
minimumCanEqual = schema.fetch('minimumCanEqual', Undefined)
|
141
|
+
if minimumCanEqual == Undefined || minimumCanEqual
|
142
|
+
if value < schema['minimum']
|
143
|
+
raise ValueError, "must have a minimum value of #{schema['minimum']}"
|
144
|
+
end
|
145
|
+
else
|
146
|
+
if value <= schema['minimum']
|
147
|
+
raise ValueError, "must have a minimum value of #{schema['minimum']}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
208
151
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
152
|
+
# maximum + maximumCanEqual
|
153
|
+
if schema['maximum']
|
154
|
+
maximumCanEqual = schema.fetch('maximumCanEqual', Undefined)
|
155
|
+
if maximumCanEqual == Undefined || maximumCanEqual
|
156
|
+
if value > schema['maximum']
|
157
|
+
raise ValueError, "must have a maximum value of #{schema['maximum']}"
|
158
|
+
end
|
159
|
+
else
|
160
|
+
if value >= schema['maximum']
|
161
|
+
raise ValueError, "must have a maximum value of #{schema['maximum']}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
222
165
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
elsif value.kind_of?(Array) && value.size > maximum
|
230
|
-
raise ValueError, "Value #{value} for field '#{fieldname}' has more values than the maximum: #{maximum}"
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
return x
|
235
|
-
end
|
166
|
+
# maxDecimal
|
167
|
+
if schema['maxDecimal'] && schema['maxDecimal'].kind_of?(Numeric)
|
168
|
+
if value.to_s =~ /\.\d{#{schema['maxDecimal']+1},}/
|
169
|
+
raise ValueError, "may only have #{schema['maxDecimal']} digits of decimal places"
|
170
|
+
end
|
171
|
+
end
|
236
172
|
|
237
|
-
|
238
|
-
if !minitems.nil? && x[fieldname]
|
239
|
-
value = x[fieldname]
|
240
|
-
if value
|
241
|
-
if value.kind_of?(Array) && value.size < minitems
|
242
|
-
raise ValueError, "Value #{value} for field '#{fieldname}' must have a minimum of #{minitems} items"
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
return x
|
247
|
-
end
|
173
|
+
end
|
248
174
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
return x
|
259
|
-
end
|
175
|
+
# enum
|
176
|
+
if schema['enum']
|
177
|
+
unless(schema['enum'].detect{|enum| enum == value })
|
178
|
+
raise ValueError, "does not have a value in the enumeration #{schema['enum'].join(", ")}"
|
179
|
+
end
|
180
|
+
end
|
260
181
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
if !p.match(value)
|
266
|
-
raise ValueError, "Value #{value} for field '#{fieldname}' does not match regular expression '#{pattern}'"
|
267
|
-
end
|
268
|
-
end
|
269
|
-
return x
|
270
|
-
end
|
182
|
+
# description
|
183
|
+
if schema['description'] && !schema['description'].instance_of?(String)
|
184
|
+
raise ValueError, "The description for field '#{value}' must be a string"
|
185
|
+
end
|
271
186
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
if value.split(//).size > length
|
277
|
-
raise ValueError, "Length of value #{value} for field '#{fieldname}' must be less than or equal to #{length}"
|
278
|
-
end
|
279
|
-
end
|
280
|
-
return x
|
281
|
-
end
|
187
|
+
# title
|
188
|
+
if schema['title'] && !schema['title'].instance_of?(String)
|
189
|
+
raise ValueError, "The title for field '#{value}' must be a string"
|
190
|
+
end
|
282
191
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
if value.split(//).size < length
|
287
|
-
raise ValueError, "Length of value #{value} for field '#{fieldname}' must be more than or equal to #{length}"
|
288
|
-
end
|
289
|
-
end
|
290
|
-
return x
|
291
|
-
end
|
192
|
+
# format
|
193
|
+
if schema['format']
|
194
|
+
end
|
292
195
|
|
293
|
-
|
294
|
-
value = x[fieldname]
|
295
|
-
if !options.nil? && value
|
296
|
-
unless options.kind_of? Array
|
297
|
-
raise ValueError, "Enumeration #{options} for field '#{fieldname}' is not a list type"
|
298
|
-
end
|
299
|
-
unless options.include? value
|
300
|
-
raise ValueError, "Value #{value} for field '#{fieldname}' is not in the enumeration: #{options}"
|
196
|
+
end
|
301
197
|
end
|
302
198
|
end
|
303
|
-
return x
|
304
199
|
end
|
305
200
|
|
306
|
-
def
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
return x
|
312
|
-
end
|
313
|
-
|
314
|
-
def validate_title x, fieldname, schema, title=nil
|
315
|
-
if !title.nil? && !title.kind_of?(String)
|
316
|
-
raise ValueError, "The title for field '#{fieldname}' must be a string"
|
317
|
-
end
|
318
|
-
return x
|
319
|
-
end
|
201
|
+
def check_object value, object_type_def, additional
|
202
|
+
if object_type_def.instance_of? Hash
|
203
|
+
if !value.instance_of?(Hash) || value.instance_of?(Array)
|
204
|
+
raise ValueError, "an object is required"
|
205
|
+
end
|
320
206
|
|
321
|
-
|
322
|
-
|
323
|
-
|
207
|
+
object_type_def.each {|key, odef|
|
208
|
+
if key.index('__') != 0
|
209
|
+
check_property(undefined_check(value, key), odef, key, value)
|
210
|
+
end
|
211
|
+
}
|
324
212
|
end
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
def validate_format x, fieldname, schema, format=nil
|
329
|
-
return x
|
330
|
-
end
|
331
|
-
|
332
|
-
def validate_default x, fieldname, schema, default=nil
|
333
|
-
if @interactive && !x.include?(fieldname) && !default.nil?
|
334
|
-
unless schema["readonly"]
|
335
|
-
x[fieldname] = default
|
213
|
+
value.each {|key, val|
|
214
|
+
if key.index('__') != 0 && object_type_def && !object_type_def[key] && additional == false
|
215
|
+
raise ValueError, "#{value.class} The property #{key} is not defined in the schema and the schema does not allow additional properties"
|
336
216
|
end
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
def validate_transient x, fieldname, schema, transient=false
|
342
|
-
return x
|
343
|
-
end
|
344
|
-
|
345
|
-
def validate_maxDecimal x, fieldname, schema, maxdecimal=nil
|
346
|
-
value = x[fieldname]
|
347
|
-
if !maxdecimal.nil? && value
|
348
|
-
maxdecstring = value.to_s
|
349
|
-
index = maxdecstring.index('.')
|
350
|
-
if index && maxdecstring[(index+1)...maxdecstring.size].split(//u).size > maxdecimal
|
351
|
-
raise ValueError, "Value #{value} for field '#{fieldname}' must not have more than #{maxdecimal} decimal places"
|
217
|
+
requires = object_type_def && object_type_def[key] && object_type_def[key]['requires']
|
218
|
+
if requires && !value.include?(requires)
|
219
|
+
raise ValueError, "the presence of the property #{key} requires that #{requires} also be present"
|
352
220
|
end
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
221
|
+
if object_type_def && object_type_def.instance_of?(Hash) && !object_type_def.include?(key)
|
222
|
+
check_property(val, additional, key, value)
|
223
|
+
end
|
224
|
+
if !@interactive && val && val['$schema']
|
225
|
+
check_property(val, val['$schema'], key, value)
|
226
|
+
end
|
227
|
+
}
|
359
228
|
end
|
360
229
|
|
361
|
-
def
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
230
|
+
def check_type value, type, key, parent
|
231
|
+
converted_fieldtype = convert_type(type)
|
232
|
+
if converted_fieldtype
|
233
|
+
if converted_fieldtype.instance_of? Array
|
234
|
+
datavalid = false
|
235
|
+
converted_fieldtype.each do |t|
|
236
|
+
begin
|
237
|
+
check_type(value, t, key, parent)
|
238
|
+
datavalid = true
|
239
|
+
break
|
240
|
+
rescue ValueError
|
241
|
+
next
|
242
|
+
end
|
243
|
+
end
|
244
|
+
unless datavalid
|
245
|
+
raise ValueError, "#{value.class} value found, but a #{type} is required"
|
246
|
+
end
|
247
|
+
elsif converted_fieldtype.instance_of? Hash
|
248
|
+
check_property(value, type, key, parent)
|
249
|
+
else
|
250
|
+
unless value.instance_of? converted_fieldtype
|
251
|
+
raise ValueError, "#{value.class} value found, but a #{type} is required"
|
252
|
+
end
|
367
253
|
end
|
368
|
-
raise ValueError, "Value #{x[fieldname]} of type #{disallow} is disallowed for field '#{fieldname}'"
|
369
254
|
end
|
370
|
-
return x
|
371
255
|
end
|
372
256
|
|
373
|
-
def
|
374
|
-
|
257
|
+
def undefined_check value, key
|
258
|
+
value.fetch(key, Undefined)
|
375
259
|
end
|
376
260
|
|
377
261
|
def convert_type fieldtype
|
@@ -395,34 +279,21 @@ module JSON
|
|
395
279
|
end
|
396
280
|
end
|
397
281
|
|
398
|
-
def
|
282
|
+
def validate instance, schema
|
283
|
+
@tree = {
|
284
|
+
'self' => instance
|
285
|
+
}
|
399
286
|
if schema
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
new_schema = Marshal.load(Marshal.dump(schema))
|
405
|
-
DefaultSchema.each do |key, val|
|
406
|
-
new_schema[key] = val unless new_schema.include?(key)
|
407
|
-
end
|
408
|
-
new_schema.each do |key ,val|
|
409
|
-
validatorname = "validate_"+key
|
410
|
-
begin
|
411
|
-
__send__(validatorname, data, fieldname, schema, new_schema[key])
|
412
|
-
rescue NoMethodError => e
|
413
|
-
raise ValueError, "Schema property '#{e.message}' is not supported"
|
414
|
-
end
|
415
|
-
end
|
287
|
+
check_property(instance, schema, 'self', @tree)
|
288
|
+
elsif instance && instance['$schema']
|
289
|
+
# self definition schema
|
290
|
+
check_property(instance, instance['$schema'], 'self', @tree)
|
416
291
|
end
|
417
|
-
return
|
418
|
-
end
|
419
|
-
|
420
|
-
def _validate data, schema
|
421
|
-
__validate("_data", {"_data" => data}, schema)
|
292
|
+
return @tree['self']
|
422
293
|
end
|
423
294
|
|
424
295
|
class << self
|
425
|
-
def validate data, schema, interactive=true
|
296
|
+
def validate data, schema=nil, interactive=true
|
426
297
|
validator = JSON::Schema.new(interactive)
|
427
298
|
validator.validate(data, schema)
|
428
299
|
end
|
data/test/jsonschema_test.rb
CHANGED
@@ -1,9 +1,72 @@
|
|
1
1
|
require 'test/unit'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'pp'
|
2
4
|
require File.dirname(__FILE__) + '/../lib/jsonschema'
|
3
5
|
|
4
6
|
class JSONSchemaTest < Test::Unit::TestCase
|
7
|
+
def test_self_schema
|
8
|
+
data1 = {
|
9
|
+
"$schema"=> {
|
10
|
+
"properties"=> {
|
11
|
+
"name"=> {
|
12
|
+
"type"=> "string"
|
13
|
+
},
|
14
|
+
"age" => {
|
15
|
+
"type"=> "integer",
|
16
|
+
"maximum"=> 125,
|
17
|
+
"optional"=> true
|
18
|
+
}
|
19
|
+
}
|
20
|
+
},
|
21
|
+
"name" => "John Doe",
|
22
|
+
"age" => 30,
|
23
|
+
"type" => "object"
|
24
|
+
}
|
25
|
+
assert_nothing_raised{
|
26
|
+
JSON::Schema.validate(data1)
|
27
|
+
}
|
28
|
+
data2 = {
|
29
|
+
"$schema"=> {
|
30
|
+
"properties"=> {
|
31
|
+
"name"=> {
|
32
|
+
"type"=> "integer"
|
33
|
+
},
|
34
|
+
"age" => {
|
35
|
+
"type"=> "integer",
|
36
|
+
"maximum"=> 125,
|
37
|
+
"optional"=> true
|
38
|
+
}
|
39
|
+
}
|
40
|
+
},
|
41
|
+
"name" => "John Doe",
|
42
|
+
"age" => 30,
|
43
|
+
"type" => "object"
|
44
|
+
}
|
45
|
+
assert_raise(JSON::Schema::ValueError){
|
46
|
+
JSON::Schema.validate(data2)
|
47
|
+
}
|
48
|
+
data3 = {
|
49
|
+
"$schema"=> {
|
50
|
+
"properties"=> {
|
51
|
+
"name"=> {
|
52
|
+
"type"=> "integer"
|
53
|
+
},
|
54
|
+
"age" => {
|
55
|
+
"type"=> "integer",
|
56
|
+
"maximum"=> 125,
|
57
|
+
"optional"=> true
|
58
|
+
}
|
59
|
+
}
|
60
|
+
},
|
61
|
+
"name" => "John Doe",
|
62
|
+
}
|
63
|
+
assert_raise(JSON::Schema::ValueError){
|
64
|
+
JSON::Schema.validate(data3)
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
5
68
|
def test_maximum
|
6
|
-
|
69
|
+
schema1 = {
|
7
70
|
"type" => "object",
|
8
71
|
"properties" => {
|
9
72
|
"prop01" => {
|
@@ -32,6 +95,91 @@ class JSONSchemaTest < Test::Unit::TestCase
|
|
32
95
|
"prop01"=> 9,
|
33
96
|
"prop02"=> 21
|
34
97
|
}
|
98
|
+
assert_nothing_raised{
|
99
|
+
JSON::Schema.validate(data1, schema1)
|
100
|
+
}
|
101
|
+
assert_nothing_raised{
|
102
|
+
JSON::Schema.validate(data2, schema1)
|
103
|
+
}
|
104
|
+
assert_raise(JSON::Schema::ValueError){
|
105
|
+
JSON::Schema.validate(data3, schema1)
|
106
|
+
}
|
107
|
+
assert_raise(JSON::Schema::ValueError){
|
108
|
+
JSON::Schema.validate(data4, schema1)
|
109
|
+
}
|
110
|
+
schema2 = {
|
111
|
+
"type" => "object",
|
112
|
+
"properties" => {
|
113
|
+
"prop01" => {
|
114
|
+
"type" => "number",
|
115
|
+
"maximum" => 10,
|
116
|
+
"maximumCanEqual" => true
|
117
|
+
},
|
118
|
+
"prop02" => {
|
119
|
+
"type" => "integer",
|
120
|
+
"maximum" => 20,
|
121
|
+
"maximumCanEqual" => false
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
data5 = {
|
126
|
+
"prop01"=> 10,
|
127
|
+
"prop02"=> 10
|
128
|
+
}
|
129
|
+
data6 = {
|
130
|
+
"prop01"=> 10,
|
131
|
+
"prop02"=> 19
|
132
|
+
}
|
133
|
+
data7 = {
|
134
|
+
"prop01"=> 11,
|
135
|
+
"prop02"=> 19
|
136
|
+
}
|
137
|
+
data8 = {
|
138
|
+
"prop01"=> 9,
|
139
|
+
"prop02"=> 20
|
140
|
+
}
|
141
|
+
assert_nothing_raised{
|
142
|
+
JSON::Schema.validate(data5, schema2)
|
143
|
+
}
|
144
|
+
assert_nothing_raised{
|
145
|
+
JSON::Schema.validate(data6, schema2)
|
146
|
+
}
|
147
|
+
assert_raise(JSON::Schema::ValueError){
|
148
|
+
JSON::Schema.validate(data7, schema2)
|
149
|
+
}
|
150
|
+
assert_raise(JSON::Schema::ValueError){
|
151
|
+
JSON::Schema.validate(data8, schema2)
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_extends
|
156
|
+
schema = {
|
157
|
+
"type" => "object",
|
158
|
+
"properties" => {
|
159
|
+
"prop01" => {
|
160
|
+
"type" => "number",
|
161
|
+
"minimum" => 10
|
162
|
+
},
|
163
|
+
"prop02" => {}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
schema["properties"]["prop02"]["extends"] = schema["properties"]["prop01"]
|
167
|
+
data1 = {
|
168
|
+
"prop01"=> 21,
|
169
|
+
"prop02"=> 21
|
170
|
+
}
|
171
|
+
data2 = {
|
172
|
+
"prop01"=> 10,
|
173
|
+
"prop02"=> 20
|
174
|
+
}
|
175
|
+
data3 = {
|
176
|
+
"prop01"=> 9,
|
177
|
+
"prop02"=> 21
|
178
|
+
}
|
179
|
+
data4 = {
|
180
|
+
"prop01"=> 10,
|
181
|
+
"prop02"=> 9
|
182
|
+
}
|
35
183
|
assert_nothing_raised{
|
36
184
|
JSON::Schema.validate(data1, schema)
|
37
185
|
}
|
@@ -47,9 +195,9 @@ class JSONSchemaTest < Test::Unit::TestCase
|
|
47
195
|
end
|
48
196
|
|
49
197
|
def test_minimum
|
50
|
-
|
198
|
+
schema1 = {
|
51
199
|
"type" => "object",
|
52
|
-
|
200
|
+
"properties" => {
|
53
201
|
"prop01" => {
|
54
202
|
"type" => "number",
|
55
203
|
"minimum" => 10
|
@@ -77,16 +225,52 @@ class JSONSchemaTest < Test::Unit::TestCase
|
|
77
225
|
"prop02"=> 19
|
78
226
|
}
|
79
227
|
assert_nothing_raised{
|
80
|
-
JSON::Schema.validate(data1,
|
228
|
+
JSON::Schema.validate(data1, schema1)
|
81
229
|
}
|
82
230
|
assert_nothing_raised{
|
83
|
-
JSON::Schema.validate(data2,
|
231
|
+
JSON::Schema.validate(data2, schema1)
|
84
232
|
}
|
85
233
|
assert_raise(JSON::Schema::ValueError){
|
86
|
-
JSON::Schema.validate(data3,
|
234
|
+
JSON::Schema.validate(data3, schema1)
|
87
235
|
}
|
88
236
|
assert_raise(JSON::Schema::ValueError){
|
89
|
-
JSON::Schema.validate(data4,
|
237
|
+
JSON::Schema.validate(data4, schema1)
|
238
|
+
}
|
239
|
+
schema2 = {
|
240
|
+
"type" => "object",
|
241
|
+
"properties" => {
|
242
|
+
"prop01" => {
|
243
|
+
"type" => "number",
|
244
|
+
"minimum" => 10,
|
245
|
+
"minimumCanEqual" => false
|
246
|
+
},
|
247
|
+
"prop02" => {
|
248
|
+
"type" => "integer",
|
249
|
+
"minimum" => 19,
|
250
|
+
"minimumCanEqual" => true
|
251
|
+
}
|
252
|
+
}
|
253
|
+
}
|
254
|
+
data5 = {
|
255
|
+
"prop01"=> 11,
|
256
|
+
"prop02"=> 19
|
257
|
+
}
|
258
|
+
data6 = {
|
259
|
+
"prop01"=> 10,
|
260
|
+
"prop02"=> 19
|
261
|
+
}
|
262
|
+
data7 = {
|
263
|
+
"prop01"=> 11,
|
264
|
+
"prop02"=> 18
|
265
|
+
}
|
266
|
+
assert_nothing_raised{
|
267
|
+
JSON::Schema.validate(data5, schema2)
|
268
|
+
}
|
269
|
+
assert_raise(JSON::Schema::ValueError){
|
270
|
+
JSON::Schema.validate(data6, schema2)
|
271
|
+
}
|
272
|
+
assert_raise(JSON::Schema::ValueError){
|
273
|
+
JSON::Schema.validate(data7, schema2)
|
90
274
|
}
|
91
275
|
end
|
92
276
|
|
@@ -392,9 +576,22 @@ class JSONSchemaTest < Test::Unit::TestCase
|
|
392
576
|
data2 = {
|
393
577
|
"prop02"=>"blah"
|
394
578
|
}
|
579
|
+
data3 = {
|
580
|
+
"prop01"=>"blah"
|
581
|
+
}
|
582
|
+
data4 = {
|
583
|
+
"prop01"=>"test",
|
584
|
+
"prop03"=>1,
|
585
|
+
}
|
395
586
|
assert_raise(JSON::Schema::ValueError){
|
396
587
|
JSON::Schema.validate(data2, schema)
|
397
588
|
}
|
589
|
+
assert_raise(JSON::Schema::ValueError){
|
590
|
+
JSON::Schema.validate(data3, schema)
|
591
|
+
}
|
592
|
+
assert_raise(JSON::Schema::ValueError){
|
593
|
+
JSON::Schema.validate(data4, schema)
|
594
|
+
}
|
398
595
|
end
|
399
596
|
|
400
597
|
def test_default
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonschema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 15
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Constellation
|
@@ -9,7 +15,7 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2010-08-23 00:00:00 +09:00
|
13
19
|
default_executable:
|
14
20
|
dependencies: []
|
15
21
|
|
@@ -41,21 +47,27 @@ rdoc_options:
|
|
41
47
|
require_paths:
|
42
48
|
- lib
|
43
49
|
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
44
51
|
requirements:
|
45
52
|
- - ">="
|
46
53
|
- !ruby/object:Gem::Version
|
54
|
+
hash: 3
|
55
|
+
segments:
|
56
|
+
- 0
|
47
57
|
version: "0"
|
48
|
-
version:
|
49
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
50
60
|
requirements:
|
51
61
|
- - ">="
|
52
62
|
- !ruby/object:Gem::Version
|
63
|
+
hash: 3
|
64
|
+
segments:
|
65
|
+
- 0
|
53
66
|
version: "0"
|
54
|
-
version:
|
55
67
|
requirements: []
|
56
68
|
|
57
69
|
rubyforge_project: jsonschema
|
58
|
-
rubygems_version: 1.3.
|
70
|
+
rubygems_version: 1.3.7
|
59
71
|
signing_key:
|
60
72
|
specification_version: 3
|
61
73
|
summary: json schema library ruby porting from http://code.google.com/p/jsonschema/
|