duck-hunt 0.0.3

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 (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