duck-hunt 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +526 -0
  3. data/Rakefile +15 -0
  4. data/lib/duck-hunt.rb +17 -0
  5. data/lib/duck-hunt/hash_helpers.rb +28 -0
  6. data/lib/duck-hunt/properties.rb +13 -0
  7. data/lib/duck-hunt/properties/array.rb +81 -0
  8. data/lib/duck-hunt/properties/boolean.rb +10 -0
  9. data/lib/duck-hunt/properties/float.rb +10 -0
  10. data/lib/duck-hunt/properties/integer.rb +9 -0
  11. data/lib/duck-hunt/properties/nested_hash.rb +61 -0
  12. data/lib/duck-hunt/properties/nil.rb +15 -0
  13. data/lib/duck-hunt/properties/property.rb +85 -0
  14. data/lib/duck-hunt/properties/string.rb +10 -0
  15. data/lib/duck-hunt/properties/validator_lookup.rb +27 -0
  16. data/lib/duck-hunt/schemas.rb +8 -0
  17. data/lib/duck-hunt/schemas/array_schema.rb +254 -0
  18. data/lib/duck-hunt/schemas/hash_schema.rb +135 -0
  19. data/lib/duck-hunt/schemas/property_lookup.rb +32 -0
  20. data/lib/duck-hunt/schemas/schema_definition.rb +25 -0
  21. data/lib/duck-hunt/string_helpers.rb +25 -0
  22. data/lib/duck-hunt/validators.rb +16 -0
  23. data/lib/duck-hunt/validators/accepted_values.rb +19 -0
  24. data/lib/duck-hunt/validators/divisible_by.rb +19 -0
  25. data/lib/duck-hunt/validators/equal_to.rb +19 -0
  26. data/lib/duck-hunt/validators/greater_than.rb +19 -0
  27. data/lib/duck-hunt/validators/greater_than_or_equal_to.rb +19 -0
  28. data/lib/duck-hunt/validators/less_than.rb +19 -0
  29. data/lib/duck-hunt/validators/less_than_or_equal_to.rb +19 -0
  30. data/lib/duck-hunt/validators/matches.rb +18 -0
  31. data/lib/duck-hunt/validators/not_divisible_by.rb +19 -0
  32. data/lib/duck-hunt/validators/not_equal_to.rb +19 -0
  33. data/lib/duck-hunt/validators/rejected_values.rb +19 -0
  34. data/lib/duck-hunt/validators/validator.rb +16 -0
  35. data/lib/duck-hunt/version.rb +3 -0
  36. data/test/properties/array_test.rb +837 -0
  37. data/test/properties/boolean_test.rb +37 -0
  38. data/test/properties/float_test.rb +49 -0
  39. data/test/properties/integer_test.rb +48 -0
  40. data/test/properties/nested_hash_test.rb +465 -0
  41. data/test/properties/nil_test.rb +30 -0
  42. data/test/properties/property_test.rb +193 -0
  43. data/test/properties/string_test.rb +24 -0
  44. data/test/properties/validator_lookup_test.rb +25 -0
  45. data/test/schemas/array_schema_test.rb +797 -0
  46. data/test/schemas/hash_schema_test.rb +264 -0
  47. data/test/schemas/property_lookup_test.rb +41 -0
  48. data/test/schemas/schema_definition_test.rb +51 -0
  49. data/test/test_helper.rb +29 -0
  50. data/test/test_helper/test_classes.rb +74 -0
  51. data/test/validators/accepted_values_test.rb +46 -0
  52. data/test/validators/divisible_by_test.rb +38 -0
  53. data/test/validators/equal_to_test.rb +38 -0
  54. data/test/validators/greater_than_or_equal_to_test.rb +39 -0
  55. data/test/validators/greater_than_test.rb +39 -0
  56. data/test/validators/less_than_or_equal_to_test.rb +40 -0
  57. data/test/validators/less_than_test.rb +39 -0
  58. data/test/validators/matches_test.rb +43 -0
  59. data/test/validators/not_divisible_by_test.rb +38 -0
  60. data/test/validators/not_equal_to_test.rb +38 -0
  61. data/test/validators/rejected_values_test.rb +46 -0
  62. data/test/validators/validator_test.rb +23 -0
  63. metadata +196 -0
@@ -0,0 +1,37 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe DuckHunt::Properties::Boolean, "validation" do
4
+ before do
5
+ @property = DuckHunt::Properties::Boolean.new
6
+ end
7
+
8
+ it "should be able to validate a boolean" do
9
+ @property.valid?(true).must_equal true
10
+ @property.errors.size.must_equal 0
11
+
12
+ @property.valid?(false).must_equal true
13
+ @property.errors.size.must_equal 0
14
+ end
15
+
16
+ it "should be invalid if there's a type mismatch" do
17
+ @property.valid?([1,2,3]).must_equal false
18
+ @property.errors.size.must_equal 1
19
+ @property.errors.first.must_equal "wrong type"
20
+ end
21
+
22
+ it "should not be able to validate a string of a boolean" do
23
+ @property.valid?("true").must_equal false
24
+ @property.errors.size.must_equal 1
25
+ @property.errors.first.must_equal "wrong type"
26
+ end
27
+
28
+ it "should not be able to validate the integer 'representations' of a boolean" do
29
+ @property.valid?(0).must_equal false
30
+ @property.errors.size.must_equal 1
31
+ @property.errors.first.must_equal "wrong type"
32
+
33
+ @property.valid?(1).must_equal false
34
+ @property.errors.size.must_equal 1
35
+ @property.errors.first.must_equal "wrong type"
36
+ end
37
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe DuckHunt::Properties::Float, "validation" do
4
+ before do
5
+ @property = DuckHunt::Properties::Float.new
6
+ end
7
+
8
+ it "should be able to validate a float" do
9
+ float = 1.17
10
+ float.must_be_instance_of Float
11
+ @property.valid?(float).must_equal true
12
+ @property.errors.size.must_equal 0
13
+ end
14
+
15
+ it "should be able to validate a BigDecimal floating point" do
16
+ bigdecimal = BigDecimal.new("3.4")
17
+ bigdecimal.must_be_instance_of BigDecimal
18
+ @property.valid?(bigdecimal).must_equal true
19
+ @property.errors.size.must_equal 0
20
+ end
21
+
22
+ it "should be invalid if there's a type mismatch" do
23
+ @property.valid?([1,2,3]).must_equal false
24
+ @property.errors.size.must_equal 1
25
+ @property.errors.first.must_equal "wrong type"
26
+ end
27
+
28
+ it "should not be validate to parse a Fixnum" do
29
+ integer = 3
30
+ integer.must_be_instance_of Fixnum
31
+ @property.valid?(integer).must_equal false
32
+ @property.errors.size.must_equal 1
33
+ @property.errors.first.must_equal "wrong type"
34
+ end
35
+
36
+ it "should not be able to validate a Bignum" do
37
+ integer = 18446744073709551616
38
+ integer.must_be_instance_of Bignum
39
+ @property.valid?(integer).must_equal false
40
+ @property.errors.size.must_equal 1
41
+ @property.errors.first.must_equal "wrong type"
42
+ end
43
+
44
+ it "should not be able to validate a string of an float" do
45
+ @property.valid?("3.17").must_equal false
46
+ @property.errors.size.must_equal 1
47
+ @property.errors.first.must_equal "wrong type"
48
+ end
49
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe DuckHunt::Properties::Integer, "validation" do
4
+ before do
5
+ @property = DuckHunt::Properties::Integer.new
6
+ end
7
+ it "should be invalid if there's a type mismatch" do
8
+ @property.valid?([1,2,3]).must_equal false
9
+ @property.errors.size.must_equal 1
10
+ @property.errors.first.must_equal "wrong type"
11
+ end
12
+
13
+ it "should be able to parse a Fixnum" do
14
+ integer = 3
15
+ integer.must_be_instance_of Fixnum
16
+ @property.valid?(integer).must_equal true
17
+ @property.errors.size.must_equal 0
18
+ end
19
+
20
+ it "should be able to parse a Bignum" do
21
+ integer = 18446744073709551616
22
+ integer.must_be_instance_of Bignum
23
+ @property.valid?(integer).must_equal true
24
+ @property.errors.size.must_equal 0
25
+ end
26
+
27
+ it "should not be able to parse a string of an integer" do
28
+ @property.valid?("3").must_equal false
29
+ @property.errors.size.must_equal 1
30
+ @property.errors.first.must_equal "wrong type"
31
+ end
32
+
33
+ it "should not be able to parse a float" do
34
+ float = 1.17
35
+ float.must_be_instance_of Float
36
+ @property.valid?(float).must_equal false
37
+ @property.errors.size.must_equal 1
38
+ @property.errors.first.must_equal "wrong type"
39
+ end
40
+
41
+ it "should not be able to parse a BigDecimal floating point" do
42
+ bigdecimal = BigDecimal.new("3.4")
43
+ bigdecimal.must_be_instance_of BigDecimal
44
+ @property.valid?(bigdecimal).must_equal false
45
+ @property.errors.size.must_equal 1
46
+ @property.errors.first.must_equal "wrong type"
47
+ end
48
+ end
@@ -0,0 +1,465 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe DuckHunt::Properties::NestedHash, "initialize using a block" do
4
+ it "should be able to set the property to required" do
5
+ property = DuckHunt::Properties::NestedHash.new :required => true do |s|
6
+ s.test "name"
7
+ end
8
+ property.required.must_equal true
9
+ property.required?.must_equal true
10
+ end
11
+
12
+ it "should be able to define the property" do
13
+ property = DuckHunt::Properties::NestedHash.new :required => true do |s|
14
+ s.test "name"
15
+ end
16
+
17
+ property.properties["name"].must_be_instance_of DuckHunt::Properties::Test
18
+ end
19
+
20
+ it "should be able to set options for the property" do
21
+ property = DuckHunt::Properties::NestedHash.new :strict_mode => false do |s|
22
+ s.test "name"
23
+ end
24
+
25
+ property.strict_mode?.must_equal false
26
+ end
27
+
28
+ it "should be able to set property-level and property-level options at the same time" do
29
+ property = DuckHunt::Properties::NestedHash.new :required => true, :strict_mode => false do |s|
30
+ s.test "name"
31
+ end
32
+ property.required.must_equal true
33
+ property.required?.must_equal true
34
+ property.strict_mode?.must_equal false
35
+ end
36
+
37
+ it "should default the `strict mode` to `true`" do
38
+ property = DuckHunt::Properties::NestedHash.new do |s|
39
+ end
40
+
41
+ property.strict_mode.must_equal true
42
+ property.strict_mode?.must_equal true
43
+ end
44
+
45
+ end
46
+
47
+ describe DuckHunt::Properties::NestedHash, "initialize without a block" do
48
+ it "should raise an exception if a block is not provided" do
49
+ lambda{
50
+ DuckHunt::Properties::NestedHash.new :required => false
51
+ }.must_raise(ArgumentError)
52
+ end
53
+ end
54
+
55
+ describe DuckHunt::Properties::NestedHash, "defining properties" do
56
+ it "should be able to add a new property to the property, which is required by default" do
57
+ property = DuckHunt::Properties::NestedHash.new do |s|
58
+ s.test "name"
59
+ end
60
+
61
+ property.properties.size.must_equal 1
62
+ property.properties["name"].wont_be_nil
63
+ property.properties["name"].required.must_equal true
64
+ property.properties["name"].required?.must_equal true
65
+ end
66
+
67
+ it "should allow a property to be explictly set as required" do
68
+ property = DuckHunt::Properties::NestedHash.new do |s|
69
+ s.test "name", :required => true
70
+ s.test "item", "required" => true
71
+ end
72
+
73
+ property.properties.size.must_equal 2
74
+
75
+ property.properties["name"].wont_be_nil
76
+ property.properties["name"].required.must_equal true
77
+ property.properties["name"].required?.must_equal true
78
+ property.properties["item"].wont_be_nil
79
+ property.properties["item"].required.must_equal true
80
+ property.properties["item"].required?.must_equal true
81
+ end
82
+
83
+ it "should allow a property to be set as not required" do
84
+ property = DuckHunt::Properties::NestedHash.new do |s|
85
+ s.test "name", :required => false
86
+ s.test "item", "required" => false
87
+ end
88
+
89
+ property.properties.size.must_equal 2
90
+ property.properties["name"].wont_be_nil
91
+ property.properties["name"].required.must_equal false
92
+ property.properties["name"].required?.must_equal false
93
+ property.properties["item"].wont_be_nil
94
+ property.properties["item"].required.must_equal false
95
+ property.properties["item"].required?.must_equal false
96
+ end
97
+
98
+ it "should require that properties are named" do
99
+ lambda{
100
+ DuckHunt::Properties::NestedHash.new do |s|
101
+ s.test
102
+ end
103
+ }.must_raise(ArgumentError)
104
+
105
+ lambda{
106
+ DuckHunt::Properties::NestedHash.new do |s|
107
+ s.test ""
108
+ end
109
+ }.must_raise(ArgumentError)
110
+ end
111
+
112
+
113
+ it "should prevent a property from being defined multiple times in a property" do
114
+ lambda {
115
+ property = DuckHunt::Properties::NestedHash.new do |s|
116
+ s.test "name"
117
+ s.test "name"
118
+ end
119
+ }.must_raise(DuckHunt::PropertyAlreadyDefined)
120
+ end
121
+
122
+ it "should ensure the list of properties cannot be modified" do
123
+ property = DuckHunt::Properties::NestedHash.new do |s|
124
+ s.test "name"
125
+ end
126
+
127
+ property.properties.size.must_equal 1
128
+
129
+ property.properties["malicious"] = "muwah ha ha"
130
+ property.properties.size.must_equal 1
131
+
132
+ lambda{
133
+ property.properties = {:malicious => "mwuah ha ha"}
134
+ }.must_raise(NoMethodError)
135
+ end
136
+
137
+ it "should ensure the list of required properties cannot be modified" do
138
+ property = DuckHunt::Properties::NestedHash.new do |s|
139
+ s.test "name"
140
+ end
141
+
142
+ lambda{
143
+ property.required_properties = {:malicious => "mwuah ha ha"}
144
+ }.must_raise(NoMethodError)
145
+ end
146
+ end
147
+
148
+ describe DuckHunt::Properties::NestedHash, "validation (strict mode)" do
149
+ it "should return false if the object provided is not a hash" do
150
+ property = DuckHunt::Properties::NestedHash.new do |s|
151
+ s.test "name"
152
+ end
153
+
154
+ property.valid?("hello").must_equal false
155
+ property.errors.size.must_equal 1
156
+ property.errors["base"].must_equal ["wrong type"]
157
+ end
158
+
159
+ it "should return false if one of the properties is not valid" do
160
+ property = DuckHunt::Properties::NestedHash.new do |s|
161
+ s.always_wrong_type "name"
162
+ end
163
+
164
+ property.valid?({:name => "hello"}).must_equal false
165
+ property.errors.size.must_equal 1
166
+ property.errors["name"].must_equal ["wrong type"]
167
+ end
168
+
169
+ it "should return false if the object is missing a required property" do
170
+ property = DuckHunt::Properties::NestedHash.new do |s|
171
+ s.test "name", :required => true
172
+ s.always_right_type "hello", :required => false
173
+ end
174
+
175
+ property.valid?({:hello => "hello"}).must_equal false
176
+ property.errors.size.must_equal 1
177
+ property.errors["name"].must_equal ["required"]
178
+ end
179
+
180
+ it "should return false if the property has been set to strict mode and the hash provided has extra properties" do
181
+ property = DuckHunt::Properties::NestedHash.new do |s|
182
+ s.test "name", :required => true
183
+ end
184
+
185
+ property.valid?({:name => "hello", :hello => "hello"}).must_equal false
186
+ property.errors.size.must_equal 1
187
+ property.errors["base"].must_equal ["has properties not defined in schema"]
188
+ end
189
+ end
190
+
191
+ describe DuckHunt::Properties::NestedHash, "validation (relaxed mode)" do
192
+ it "should return false if the object provided is not a hash" do
193
+ property = DuckHunt::Properties::NestedHash.new :strict_mode => false do |s|
194
+ s.test "name"
195
+ end
196
+
197
+ property.valid?("hello").must_equal false
198
+ property.errors.size.must_equal 1
199
+ property.errors["base"].must_equal ["wrong type"]
200
+ end
201
+
202
+ it "should return false if one of the properties is not valid" do
203
+ property = DuckHunt::Properties::NestedHash.new :strict_mode => false do |s|
204
+ s.always_wrong_type "name"
205
+ end
206
+
207
+ property.valid?({:name => "hello"}).must_equal false
208
+ property.errors.size.must_equal 1
209
+ property.errors["name"].must_equal ["wrong type"]
210
+ end
211
+
212
+ it "should return false if the object is missing a required property" do
213
+ property = DuckHunt::Properties::NestedHash.new :strict_mode => false do |s|
214
+ s.test "name", :required => true
215
+ s.always_right_type "hello", :required => false
216
+ end
217
+
218
+ property.valid?({:hello => "hello"}).must_equal false
219
+ property.errors.size.must_equal 1
220
+ property.errors["name"].must_equal ["required"]
221
+ end
222
+
223
+ it "should return true if the property has been set to relaxed mode and the hash provided has extra properties" do
224
+ property = DuckHunt::Properties::NestedHash.new :strict_mode => false do |s|
225
+ s.always_right_type "name", :required => true
226
+ end
227
+
228
+ property.valid?({:name => "hello", :hello => "hello"}).must_equal true
229
+ property.errors.size.must_equal 0
230
+ end
231
+ end
232
+
233
+ describe DuckHunt::Properties::NestedHash, "validating `allow nil`" do
234
+ it "should return false if nil is not allowed and a nil object is given" do
235
+ property = DuckHunt::Properties::NestedHash.new :allow_nil => false do |s|
236
+ s.test "name"
237
+ end
238
+ property.valid?(nil).must_equal false
239
+ property.errors.size.must_equal 1
240
+ property.errors["base"].must_equal ["nil object not allowed"]
241
+ end
242
+
243
+ it "should return true if nil is allowed and a nil object is given" do
244
+ property = DuckHunt::Properties::NestedHash.new :allow_nil => true do |s|
245
+ s.test "name"
246
+ end
247
+ property.valid?(nil).must_equal true
248
+ property.errors.size.must_equal 0
249
+ end
250
+ end
251
+
252
+ describe DuckHunt::Properties::NestedHash, "Nesting in single-type array schemas" do
253
+ before do
254
+ @schema = DuckHunt::Schemas::ArraySchema.define do |s|
255
+ s.nested_hash do |s|
256
+ s.always_right_type "name", :required => true
257
+ end
258
+ end
259
+ end
260
+
261
+ it "should be able to be nested in an array schema" do
262
+ @schema.single_type_property.must_be_instance_of DuckHunt::Properties::NestedHash
263
+ end
264
+
265
+ it "should return true if the nested hashes are valid" do
266
+ @schema.validate?([{:name => "Hello"}, {:name => "World"}]).must_equal true
267
+ @schema.errors.size.must_equal 0
268
+ end
269
+
270
+ it "should return false if one of the nested hashes is invalid" do
271
+ @schema.validate?([{:name => "Hello"}, {:world => "World"}]).must_equal false
272
+ @schema.errors.size.must_equal 1
273
+ @schema.errors["1"].must_equal({"base" => ["has properties not defined in schema"]})
274
+
275
+ @schema.validate?([{:name => "Hello"}, {}]).must_equal false
276
+ @schema.errors.size.must_equal 1
277
+ @schema.errors["1"].must_equal({"name" => ["required"]})
278
+ end
279
+
280
+ it "should return false if both of the nested hashes are invalid" do
281
+ @schema.validate?([{}, {}]).must_equal false
282
+ @schema.errors.size.must_equal 2
283
+ @schema.errors["0"].must_equal({"name" => ["required"]})
284
+ @schema.errors["1"].must_equal({"name" => ["required"]})
285
+ end
286
+ end
287
+
288
+ describe DuckHunt::Properties::NestedHash, "Nesting in tuple array schemas (no optional properties)" do
289
+ before do
290
+ @schema = DuckHunt::Schemas::ArraySchema.define do |s|
291
+ s.items do |x|
292
+ x.nested_hash do |z|
293
+ z.always_right_type "name", :required => true
294
+ end
295
+
296
+ x.nested_hash do |y|
297
+ y.always_right_type "age", :required => true
298
+ end
299
+ end
300
+ end
301
+ end
302
+
303
+ it "should be able to be nested in an array schema" do
304
+ @schema.tuple_properties.each{|x| x.must_be_instance_of DuckHunt::Properties::NestedHash}
305
+ end
306
+
307
+ it "should return true if the nested hashes are valid" do
308
+ @schema.validate?([{:name => "Hello"}, {:age => "World"}]).must_equal true
309
+ @schema.errors.size.must_equal 0
310
+ end
311
+
312
+ it "should return false if one of the nested hashes is invalid" do
313
+ @schema.validate?([{:name => "Hello"}, {:world => "World"}]).must_equal false
314
+ @schema.errors.size.must_equal 1
315
+ @schema.errors["1"].must_equal({"base" => ["has properties not defined in schema"]})
316
+
317
+ @schema.validate?([{:name => "Hello"}, {}]).must_equal false
318
+ @schema.errors.size.must_equal 1
319
+ @schema.errors["1"].must_equal({"age" => ["required"]})
320
+ end
321
+
322
+ it "should return false if both of the nested hashes are invalid" do
323
+ @schema.validate?([{}, {}]).must_equal false
324
+ @schema.errors.size.must_equal 2
325
+ @schema.errors["0"].must_equal({"name" => ["required"]})
326
+ @schema.errors["1"].must_equal({"age" => ["required"]})
327
+ end
328
+ end
329
+
330
+ describe DuckHunt::Properties::NestedHash, "Nesting in tuple array schemas (with optional properties)" do
331
+ before do
332
+ @schema = DuckHunt::Schemas::ArraySchema.define do |s|
333
+ s.items do |x|
334
+ x.nested_hash do |z|
335
+ z.always_right_type "name", :required => true
336
+ end
337
+ end
338
+
339
+ s.optional_items do |w|
340
+ w.nested_hash do |y|
341
+ y.always_right_type "age", :required => true
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ it "should be able to be nested in an array schema" do
348
+ @schema.tuple_properties.each{|x| x.must_be_instance_of DuckHunt::Properties::NestedHash}
349
+ @schema.optional_tuple_properties.each{|x| x.must_be_instance_of DuckHunt::Properties::NestedHash}
350
+ end
351
+
352
+ it "should return true if the nested hashes are valid" do
353
+ @schema.validate?([{:name => "Hello"}, {:age => "World"}]).must_equal true
354
+ @schema.errors.size.must_equal 0
355
+ end
356
+
357
+ it "should return true if only the required hashes are provided" do
358
+ @schema.validate?([{:name => "Hello"}]).must_equal true
359
+ @schema.errors.size.must_equal 0
360
+ end
361
+
362
+ it "should return false if one of the nested hashes is invalid" do
363
+ @schema.validate?([{:name => "Hello"}, {:world => "World"}]).must_equal false
364
+ @schema.errors.size.must_equal 1
365
+ @schema.errors["1"].must_equal({"base" => ["has properties not defined in schema"]})
366
+
367
+ @schema.validate?([{:name => "Hello"}, {}]).must_equal false
368
+ @schema.errors.size.must_equal 1
369
+ @schema.errors["1"].must_equal({"age" => ["required"]})
370
+ end
371
+
372
+ it "should return false if both of the nested hashes are invalid" do
373
+ @schema.validate?([{}, {}]).must_equal false
374
+ @schema.errors.size.must_equal 2
375
+ @schema.errors["0"].must_equal({"name" => ["required"]})
376
+ @schema.errors["1"].must_equal({"age" => ["required"]})
377
+ end
378
+ end
379
+
380
+ describe DuckHunt::Properties::NestedHash, "Nesting in tuple array schemas (all optional properties)" do
381
+ before do
382
+ @schema = DuckHunt::Schemas::ArraySchema.define do |s|
383
+ s.optional_items do |x|
384
+ x.nested_hash do |z|
385
+ z.always_right_type "name", :required => true
386
+ end
387
+
388
+ x.nested_hash do |w|
389
+ w.always_right_type "age", :required => true
390
+ end
391
+ end
392
+ end
393
+ end
394
+
395
+ it "should be able to be nested in an array schema" do
396
+ @schema.optional_tuple_properties.each{|x| x.must_be_instance_of DuckHunt::Properties::NestedHash}
397
+ end
398
+
399
+ it "should return true if the nested hashes are valid" do
400
+ @schema.validate?([{:name => "Hello"}, {:age => "World"}]).must_equal true
401
+ @schema.errors.size.must_equal 0
402
+ end
403
+
404
+ it "should return true if no hashes are provided" do
405
+ @schema.validate?([]).must_equal true
406
+ @schema.errors.size.must_equal 0
407
+ end
408
+
409
+ it "should return false if one of the nested hashes is invalid" do
410
+ @schema.validate?([{:name => "Hello"}, {:world => "World"}]).must_equal false
411
+ @schema.errors.size.must_equal 1
412
+ @schema.errors["1"].must_equal({"base" => ["has properties not defined in schema"]})
413
+
414
+ @schema.validate?([{}, {:age => "World"}]).must_equal false
415
+ @schema.errors.size.must_equal 1
416
+ @schema.errors["0"].must_equal({"name" => ["required"]})
417
+ end
418
+
419
+ it "should return false if both of the nested hashes are invalid" do
420
+ @schema.validate?([{}, {}]).must_equal false
421
+ @schema.errors.size.must_equal 2
422
+ @schema.errors["0"].must_equal({"name" => ["required"]})
423
+ @schema.errors["1"].must_equal({"age" => ["required"]})
424
+ end
425
+ end
426
+
427
+ describe DuckHunt::Properties::NestedHash, "Nesting in hashes" do
428
+ before do
429
+ @schema = DuckHunt::Schemas::HashSchema.define do |s|
430
+ s.nested_hash "profile" do |x|
431
+ x.always_right_type "name", :required => true
432
+ end
433
+
434
+ s.nested_hash "info" do |x|
435
+ x.always_right_type "age", :required => true
436
+ end
437
+ end
438
+ end
439
+
440
+ it "should be able to be nested in an array schema" do
441
+ @schema.properties["profile"].must_be_instance_of DuckHunt::Properties::NestedHash
442
+ end
443
+
444
+ it "should return true if the nested hashes are valid" do
445
+ @schema.validate?({:profile => {:name => "John"}, :info => {:age => 35}}).must_equal true
446
+ @schema.errors.size.must_equal 0
447
+ end
448
+
449
+ it "should return false if one of the nested hashes is invalid" do
450
+ @schema.validate?({:profile => {:name => "John"}, :info => {:birthdate => 35}}).must_equal false
451
+ @schema.errors.size.must_equal 1
452
+ @schema.errors["info"].must_equal({"base" => ["has properties not defined in schema"]})
453
+
454
+ @schema.validate?({:profile => {:name => "John"}, :info => {}}).must_equal false
455
+ @schema.errors.size.must_equal 1
456
+ @schema.errors["info"].must_equal({"age" => ["required"]})
457
+ end
458
+
459
+ it "should return false if both of the nested hashes are invalid" do
460
+ @schema.validate?({:profile => {}, :info => {}}).must_equal false
461
+ @schema.errors.size.must_equal 2
462
+ @schema.errors["profile"].must_equal({"name" => ["required"]})
463
+ @schema.errors["info"].must_equal({"age" => ["required"]})
464
+ end
465
+ end