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,30 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe DuckHunt::Properties::Nil, "validation" do
4
+ before do
5
+ @property = DuckHunt::Properties::Nil.new
6
+ end
7
+
8
+ it "should be able to validate a nil value" do
9
+ @property.valid?(nil).must_equal true
10
+ @property.errors.size.must_equal 0
11
+ end
12
+
13
+ it "should be invalid if the value is not nil" do
14
+ @property.valid?([1,2,3]).must_equal false
15
+ @property.errors.size.must_equal 1
16
+ @property.errors.first.must_equal "wrong type"
17
+ end
18
+
19
+ it "should not be able to validate a string representing nil" do
20
+ @property.valid?("nil").must_equal false
21
+ @property.errors.size.must_equal 1
22
+ @property.errors.first.must_equal "wrong type"
23
+ end
24
+
25
+ it "should not be able to validate the integer 'representation' of a nil" do
26
+ @property.valid?(0).must_equal false
27
+ @property.errors.size.must_equal 1
28
+ @property.errors.first.must_equal "wrong type"
29
+ end
30
+ end
@@ -0,0 +1,193 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe DuckHunt::Properties::Property, "initialization" do
4
+ it "should make the property required by default" do
5
+ property = DuckHunt::Properties::Property.new
6
+ property.required.must_equal true
7
+ property.required?.must_equal true
8
+ end
9
+
10
+ it "should not allow nil objects by default" do
11
+ property = DuckHunt::Properties::Property.new
12
+ property.allow_nil.must_equal false
13
+ property.allow_nil?.must_equal false
14
+ end
15
+
16
+ it "allow the requiredness to be changed via the options hash" do
17
+ property = DuckHunt::Properties::Property.new(:required => false)
18
+ property.required.must_equal false
19
+ property.required?.must_equal false
20
+
21
+ property = DuckHunt::Properties::Property.new(:required => true)
22
+ property.required.must_equal true
23
+ property.required?.must_equal true
24
+ end
25
+ end
26
+
27
+ describe DuckHunt::Properties::Property, "validation" do
28
+ it "should be invalid if there's a type mismatch" do
29
+ property = DuckHunt::Properties::Property.new
30
+ property.stubs(:matches_type?).returns(false)
31
+
32
+ property.valid?("herp").must_equal false
33
+ property.errors.size.must_equal 1
34
+ property.errors.first.must_equal "wrong type"
35
+ end
36
+
37
+ it "should not call the validators when there is a type mismatch" do
38
+ property = DuckHunt::Properties::Property.new(:always_wrong => true)
39
+ property.stubs(:matches_type?).returns(false)
40
+
41
+ property.valid?("herp").must_equal false
42
+ property.errors.size.must_equal 1
43
+ property.errors.first.must_equal "wrong type"
44
+ end
45
+
46
+ it "should raise an exception if a validator raises an exception, since this is the clearest way to indicate the schema was not defined correctly" do
47
+ property = DuckHunt::Properties::Property.new(:always_raise_exception => true)
48
+ property.stubs(:matches_type?).returns(true)
49
+
50
+ lambda{
51
+ property.valid?("herp")
52
+ }.must_raise Exception
53
+ end
54
+
55
+ it "should use a validator defined during initialization when validating" do
56
+ property = DuckHunt::Properties::Property.new(:always_wrong => true)
57
+ property.stubs(:matches_type?).returns(true)
58
+ property.valid?("herp").must_equal false
59
+ property.errors.size.must_equal 1
60
+ property.errors.first.must_equal "Always Wrong"
61
+ end
62
+
63
+ it "should support adding multiple validators during initialization" do
64
+ property = DuckHunt::Properties::Property.new(:always_wrong => true, :wrong_again => true)
65
+ property.stubs(:matches_type?).returns(true)
66
+ property.valid?("herp").must_equal false
67
+ property.errors.size.must_equal 2
68
+ property.errors.to_set.must_equal ["Always Wrong", "Wrong Again"].to_set
69
+ end
70
+
71
+ it "should be valid if the type matches and no validators are added" do
72
+ property = DuckHunt::Properties::Property.new
73
+ property.stubs(:matches_type?).returns(true)
74
+
75
+ property.valid?("herp").must_equal true
76
+ property.errors.size.must_equal 0
77
+ end
78
+
79
+ it "should be valid if the type matches and all validators pass" do
80
+ property = DuckHunt::Properties::Property.new(:always_right => true, :right_again => true)
81
+ property.stubs(:matches_type?).returns(true)
82
+
83
+ property.valid?("herp").must_equal true
84
+ property.errors.size.must_equal 0
85
+ end
86
+
87
+ it "should be valid if a nil object is allowed and a nil object is provided" do
88
+ property = DuckHunt::Properties::Property.new(:allow_nil => true)
89
+ property.valid?(nil).must_equal true
90
+ property.errors.size.must_equal 0
91
+ end
92
+
93
+ it "should be valid if a nil object is allowed and a nil object is provided, even if there are other validators that would be invalidated" do
94
+ property = DuckHunt::Properties::Property.new(:allow_nil => true, :always_wrong => true)
95
+ property.valid?(nil).must_equal true
96
+ property.errors.size.must_equal 0
97
+ end
98
+
99
+ it "should be invalid if a nil object is provided and nil objects are not allowed" do
100
+ property = DuckHunt::Properties::Property.new(:allow_nil => false)
101
+ property.valid?(nil).must_equal false
102
+ property.errors.size.must_equal 1
103
+ property.errors.first.must_equal "nil object not allowed"
104
+ end
105
+
106
+ it "should be valid if the type matches and all validators pass (even if a nil object is allowed)" do
107
+ property = DuckHunt::Properties::Property.new(:allow_nil => true, :always_right => true)
108
+ property.stubs(:matches_type?).returns(true)
109
+ property.valid?("hello").must_equal true
110
+ property.errors.size.must_equal 0
111
+ end
112
+
113
+ it "should add the 'required' error message if requested" do
114
+ property = DuckHunt::Properties::Property.new
115
+ property.add_required_error
116
+ property.errors.size.must_equal 1
117
+ property.errors.first.must_equal "required"
118
+ end
119
+
120
+ it "should raise NotImplementedError if `matches_type?` has not been defined (subclasses define it)" do
121
+ property = DuckHunt::Properties::Property.new
122
+ lambda{
123
+ property.valid?("hello")
124
+ }.must_raise(NotImplementedError)
125
+ end
126
+ end
127
+
128
+ describe DuckHunt::Properties::Property, "validating multiple times" do
129
+ before do
130
+ @property = DuckHunt::Properties::Property.new
131
+ @property.stubs(:matches_type?).returns(true)
132
+ end
133
+
134
+ it "should ensure that the errors are cleared out each time `valid?` is called" do
135
+ @property.stubs(:matches_type?).returns(false)
136
+ @property.valid?("herp")
137
+ @property.errors.size.must_equal 1
138
+
139
+ @property.stubs(:matches_type?).returns(true)
140
+ @property.valid?("herp")
141
+ @property.errors.size.must_equal 0
142
+ end
143
+
144
+ it "should ensure that a property can go from valid to invalid" do
145
+ @property.valid?("herp").must_equal true
146
+ @property.errors.size.must_equal 0
147
+
148
+ @property.stubs(:matches_type?).returns(false)
149
+ @property.valid?("herp").must_equal false
150
+ @property.errors.size.must_equal 1
151
+ end
152
+
153
+ it "should ensure that a property can go from invalid to valid" do
154
+ @property.stubs(:matches_type?).returns(false)
155
+ @property.valid?("herp").must_equal false
156
+ @property.errors.size.must_equal 1
157
+
158
+ @property.stubs(:matches_type?).returns(true)
159
+ @property.valid?("herp").must_equal true
160
+ @property.errors.size.must_equal 0
161
+ end
162
+
163
+ it "should not add the required message twice" do
164
+ @property.stubs(:matches_type?).returns(false)
165
+ @property.add_required_error
166
+ @property.add_required_error
167
+ @property.errors.size.must_equal 1
168
+ @property.errors.must_equal ["required"]
169
+ end
170
+ end
171
+
172
+ describe DuckHunt::Properties::Property, "security" do
173
+ it "should ensure the required status cannot be modified" do
174
+ property = DuckHunt::Properties::Property.new(:required => true)
175
+ lambda{
176
+ property.required = false
177
+ }.must_raise(NoMethodError)
178
+
179
+ property.required.must_equal true
180
+ end
181
+
182
+ it "should ensure the list of validators cannot be accessed or modified" do
183
+ property = DuckHunt::Properties::Property.new
184
+
185
+ lambda{
186
+ property.validators["malicious"] = "muwah ha ha"
187
+ }.must_raise(NoMethodError)
188
+
189
+ lambda{
190
+ property.validators = {:malicious => "mwuah ha ha"}
191
+ }.must_raise(NoMethodError)
192
+ end
193
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe DuckHunt::Properties::String, "validation" do
4
+ before do
5
+ @property = DuckHunt::Properties::String.new
6
+ end
7
+
8
+ it "should be able to validate a string" do
9
+ @property.valid?("herpderp").must_equal true
10
+ @property.errors.size.must_equal 0
11
+ end
12
+
13
+ it "should be invalid if there's a type mismatch" do
14
+ @property.valid?([1,2,3]).must_equal false
15
+ @property.errors.size.must_equal 1
16
+ @property.errors.first.must_equal "wrong type"
17
+ end
18
+
19
+ it "should not be able to validate a symbol" do
20
+ @property.valid?(:test).must_equal false
21
+ @property.errors.size.must_equal 1
22
+ @property.errors.first.must_equal "wrong type"
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ class ValidatorLookupTestClass
4
+ include DuckHunt::Properties::ValidatorLookup
5
+
6
+ def add(name)
7
+ find_and_create_validator(name, true)
8
+ end
9
+ end
10
+
11
+ describe DuckHunt::Properties::ValidatorLookup, "Adding a validator to the property" do
12
+ it "should raise a `NotImplementedError` if the validator definition exists (classes using this module must implement `add_validator`" do
13
+ property = ValidatorLookupTestClass.new
14
+ lambda {
15
+ property.add("test")
16
+ }.must_raise(NotImplementedError)
17
+ end
18
+
19
+ it "should raise Name if the validator definition does not exist (it was not found)" do
20
+ property = ValidatorLookupTestClass.new
21
+ lambda {
22
+ property.add("herp")
23
+ }.must_raise(NameError)
24
+ end
25
+ end
@@ -0,0 +1,797 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe DuckHunt::Schemas::ArraySchema, "defining an object through a block" do
4
+ it "should be able to define a single-type array" do
5
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
6
+ s.integer
7
+ end
8
+
9
+ schema.single_type_property.must_be_instance_of DuckHunt::Properties::Integer
10
+ schema.tuple_properties.must_be_nil
11
+ schema.optional_tuple_properties.must_be_nil
12
+ end
13
+
14
+ it "should be able to define a tuple array with no optional items" do
15
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
16
+ s.items do |x|
17
+ x.integer
18
+ end
19
+ end
20
+
21
+ schema.tuple_properties.size.must_equal 1
22
+ schema.tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
23
+
24
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
25
+ s.items do |x|
26
+ x.integer
27
+ x.test
28
+ end
29
+ end
30
+
31
+ schema.tuple_properties.size.must_equal 2
32
+ schema.tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
33
+ schema.tuple_properties.last.must_be_instance_of DuckHunt::Properties::Test
34
+ end
35
+
36
+ it "should be able to define a tuple array with optional items" do
37
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
38
+ s.items do |x|
39
+ x.integer
40
+ end
41
+
42
+ s.optional_items do |y|
43
+ y.integer
44
+ y.test
45
+ end
46
+ end
47
+
48
+ schema.tuple_properties.size.must_equal 1
49
+ schema.tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
50
+
51
+ schema.optional_tuple_properties.size.must_equal 2
52
+ schema.optional_tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
53
+ schema.optional_tuple_properties.last.must_be_instance_of DuckHunt::Properties::Test
54
+
55
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
56
+ s.items do |x|
57
+ x.integer
58
+ x.test
59
+ end
60
+
61
+ s.optional_items do |x|
62
+ x.integer
63
+ end
64
+ end
65
+
66
+ schema.tuple_properties.size.must_equal 2
67
+ schema.tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
68
+ schema.tuple_properties.last.must_be_instance_of DuckHunt::Properties::Test
69
+
70
+ schema.optional_tuple_properties.size.must_equal 1
71
+ schema.optional_tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
72
+ end
73
+
74
+ it "should not allow single-type and tuple definitions in the same schema" do
75
+ lambda{
76
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
77
+ s.integer
78
+ s.items do |x|
79
+ x.integer
80
+ end
81
+ end
82
+ }.must_raise DuckHunt::InvalidSchema
83
+
84
+ lambda{
85
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
86
+ s.items do |x|
87
+ x.integer
88
+ end
89
+ s.integer
90
+ end
91
+ }.must_raise DuckHunt::InvalidSchema
92
+
93
+ lambda{
94
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
95
+ s.integer
96
+ s.optional_items do |x|
97
+ x.integer
98
+ end
99
+ end
100
+ }.must_raise DuckHunt::InvalidSchema
101
+
102
+ lambda{
103
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
104
+ s.optional_items do |x|
105
+ x.integer
106
+ end
107
+ s.integer
108
+ end
109
+ }.must_raise DuckHunt::InvalidSchema
110
+ end
111
+
112
+ it "should pass a block down to the property that defines a single-type array" do
113
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
114
+ s.test_block_passed {1+1}
115
+ end
116
+
117
+ schema.single_type_property.block_passed.must_equal true
118
+ end
119
+
120
+ it "should pass a block down to the properties in a tuple array" do
121
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
122
+ s.items do |x|
123
+ x.test_block_passed {1+1}
124
+ end
125
+
126
+ s.optional_items do |y|
127
+ y.test_block_passed {1+1}
128
+ end
129
+ end
130
+
131
+ schema.tuple_properties.first.block_passed.must_equal true
132
+ schema.optional_tuple_properties.first.block_passed.must_equal true
133
+ end
134
+
135
+ it "should require that a block be passed when setting tuple properties" do
136
+ lambda{
137
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
138
+ s.items
139
+ end
140
+ }.must_raise ArgumentError
141
+
142
+ lambda{
143
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
144
+ s.optional_items
145
+ end
146
+ }.must_raise ArgumentError
147
+ end
148
+
149
+ it "should allow the uniqueness flag to be set during initialization" do
150
+ schema = DuckHunt::Schemas::ArraySchema.define :validates_uniqueness => true do |s|
151
+ s.integer
152
+ end
153
+
154
+ schema.validates_uniqueness?.must_equal true
155
+ schema.validates_uniqueness.must_equal true
156
+ end
157
+
158
+ it "should allow the min and max size to be set during initialization" do
159
+ schema = DuckHunt::Schemas::ArraySchema.define :min_size => 10 do |s|
160
+ s.integer
161
+ end
162
+
163
+ schema.min_size.must_equal 10
164
+ schema.max_size.must_be_nil
165
+
166
+ schema = DuckHunt::Schemas::ArraySchema.define :max_size => 10 do |s|
167
+ s.integer
168
+ end
169
+
170
+ schema.min_size.must_be_nil
171
+ schema.max_size.must_equal 10
172
+
173
+ schema = DuckHunt::Schemas::ArraySchema.define :min_size => 5, :max_size => 10 do |s|
174
+ s.integer
175
+ end
176
+
177
+ schema.min_size.must_equal 5
178
+ schema.max_size.must_equal 10
179
+ end
180
+
181
+ it "should allow the 'allow nil' flag to be set during initialization" do
182
+ schema = DuckHunt::Schemas::ArraySchema.define :allow_nil => true do |s|
183
+ s.integer
184
+ end
185
+
186
+ schema.allow_nil.must_equal true
187
+ schema.allow_nil?.must_equal true
188
+ end
189
+
190
+ it "should default the uniqueness flag to false" do
191
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
192
+ s.integer
193
+ end
194
+
195
+ schema.validates_uniqueness.must_equal false
196
+ schema.validates_uniqueness?.must_equal false
197
+ end
198
+
199
+ it "should default the min and max size to nil" do
200
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
201
+ s.integer
202
+ end
203
+
204
+ schema.min_size.must_be_nil
205
+ schema.max_size.must_be_nil
206
+ end
207
+
208
+ it "should default the 'allow nil' flag to false" do
209
+ schema = DuckHunt::Schemas::ArraySchema.define do |s|
210
+ s.integer
211
+ end
212
+
213
+ schema.allow_nil.must_equal false
214
+ schema.allow_nil?.must_equal false
215
+ end
216
+ end
217
+
218
+ describe DuckHunt::Schemas::ArraySchema, "defining an object without a block" do
219
+ it "should be able to define a single-type array" do
220
+ schema = DuckHunt::Schemas::ArraySchema.new
221
+ schema.integer
222
+
223
+ schema.single_type_property.must_be_instance_of DuckHunt::Properties::Integer
224
+ schema.tuple_properties.must_be_nil
225
+ schema.optional_tuple_properties.must_be_nil
226
+ end
227
+
228
+ it "should be able to define a tuple array with no optional items" do
229
+ schema = DuckHunt::Schemas::ArraySchema.new
230
+ schema.items do |x|
231
+ x.integer
232
+ end
233
+
234
+ schema.tuple_properties.size.must_equal 1
235
+ schema.tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
236
+
237
+ schema = DuckHunt::Schemas::ArraySchema.new
238
+ schema.items do |x|
239
+ x.integer
240
+ x.test
241
+ end
242
+
243
+ schema.tuple_properties.size.must_equal 2
244
+ schema.tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
245
+ schema.tuple_properties.last.must_be_instance_of DuckHunt::Properties::Test
246
+ end
247
+
248
+ it "should be able to define a tuple array with optional items" do
249
+ schema = DuckHunt::Schemas::ArraySchema.new
250
+ schema.items do |x|
251
+ x.integer
252
+ end
253
+
254
+ schema.optional_items do |y|
255
+ y.integer
256
+ y.test
257
+ end
258
+
259
+ schema.tuple_properties.size.must_equal 1
260
+ schema.tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
261
+
262
+ schema.optional_tuple_properties.size.must_equal 2
263
+ schema.optional_tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
264
+ schema.optional_tuple_properties.last.must_be_instance_of DuckHunt::Properties::Test
265
+
266
+ schema = DuckHunt::Schemas::ArraySchema.new
267
+ schema.items do |x|
268
+ x.integer
269
+ x.test
270
+ end
271
+
272
+ schema.optional_items do |x|
273
+ x.integer
274
+ end
275
+
276
+ schema.tuple_properties.size.must_equal 2
277
+ schema.tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
278
+ schema.tuple_properties.last.must_be_instance_of DuckHunt::Properties::Test
279
+
280
+ schema.optional_tuple_properties.size.must_equal 1
281
+ schema.optional_tuple_properties.first.must_be_instance_of DuckHunt::Properties::Integer
282
+ end
283
+
284
+ it "should not allow single-type and tuple definitions in the same schema" do
285
+ lambda{
286
+ schema = DuckHunt::Schemas::ArraySchema.new
287
+ schema.integer
288
+ schema.items do |x|
289
+ x.integer
290
+ end
291
+ }.must_raise DuckHunt::InvalidSchema
292
+
293
+ lambda{
294
+ schema = DuckHunt::Schemas::ArraySchema.new
295
+ schema.items do |x|
296
+ x.integer
297
+ end
298
+ schema.integer
299
+ }.must_raise DuckHunt::InvalidSchema
300
+
301
+ lambda{
302
+ schema = DuckHunt::Schemas::ArraySchema.new
303
+ schema.integer
304
+ schema.optional_items do |x|
305
+ x.integer
306
+ end
307
+ }.must_raise DuckHunt::InvalidSchema
308
+
309
+ lambda{
310
+ schema = DuckHunt::Schemas::ArraySchema.new
311
+ schema.optional_items do |x|
312
+ x.integer
313
+ end
314
+ schema.integer
315
+ }.must_raise DuckHunt::InvalidSchema
316
+ end
317
+
318
+ it "should require that a block be passed when setting tuple properties" do
319
+ lambda{
320
+ schema = DuckHunt::Schemas::ArraySchema.new
321
+ schema.items
322
+ }.must_raise ArgumentError
323
+
324
+ lambda{
325
+ schema = DuckHunt::Schemas::ArraySchema.new
326
+ schema.optional_items
327
+ }.must_raise ArgumentError
328
+ end
329
+
330
+ it "should allow the uniqueness flag to be set during initialization" do
331
+ schema = DuckHunt::Schemas::ArraySchema.new(:validates_uniqueness => true)
332
+ schema.integer
333
+
334
+ schema.validates_uniqueness?.must_equal true
335
+ schema.validates_uniqueness.must_equal true
336
+ end
337
+
338
+ it "should allow the min and max size to be set during initialization" do
339
+ schema = DuckHunt::Schemas::ArraySchema.new(:min_size => 10)
340
+ schema.integer
341
+
342
+ schema.min_size.must_equal 10
343
+ schema.max_size.must_be_nil
344
+
345
+ schema = DuckHunt::Schemas::ArraySchema.new :max_size => 10
346
+ schema.integer
347
+
348
+ schema.min_size.must_be_nil
349
+ schema.max_size.must_equal 10
350
+
351
+ schema = DuckHunt::Schemas::ArraySchema.new :min_size => 5, :max_size => 10
352
+ schema.integer
353
+
354
+ schema.min_size.must_equal 5
355
+ schema.max_size.must_equal 10
356
+ end
357
+
358
+ it "should allow the 'allow nil' flag to be set during initialization" do
359
+ schema = DuckHunt::Schemas::ArraySchema.new(:allow_nil => true)
360
+ schema.integer
361
+
362
+ schema.allow_nil.must_equal true
363
+ schema.allow_nil?.must_equal true
364
+ end
365
+
366
+ it "should default the uniqueness flag to false" do
367
+ schema = DuckHunt::Schemas::ArraySchema.new
368
+ schema.integer
369
+
370
+ schema.validates_uniqueness.must_equal false
371
+ schema.validates_uniqueness?.must_equal false
372
+ end
373
+
374
+ it "should default the min and max size to nil" do
375
+ schema = DuckHunt::Schemas::ArraySchema.new
376
+ schema.integer
377
+
378
+ schema.min_size.must_be_nil
379
+ schema.max_size.must_be_nil
380
+ end
381
+
382
+ it "should default the 'allow nil' flag to false" do
383
+ schema = DuckHunt::Schemas::ArraySchema.new
384
+ schema.integer
385
+
386
+ schema.allow_nil.must_equal false
387
+ schema.allow_nil?.must_equal false
388
+ end
389
+ end
390
+
391
+ describe DuckHunt::Schemas::ArraySchema, "single-type validation" do
392
+ before do
393
+ @schema = DuckHunt::Schemas::ArraySchema.define do |s|
394
+ s.integer
395
+ end
396
+ end
397
+
398
+ it "should return false if the object provided is not an array" do
399
+ @schema.validate?("hello").must_equal false
400
+ @schema.errors.size.must_equal 1
401
+ @schema.errors["base"].must_equal ["wrong type"]
402
+ end
403
+
404
+ it "should return true if there are no entries in the array" do
405
+ @schema.validate?([]).must_equal true
406
+ @schema.errors.size.must_equal 0
407
+ end
408
+
409
+ it "should return true if every entry in the array is of the correct type" do
410
+ @schema.validate?([1,2,3]).must_equal true
411
+ @schema.errors.size.must_equal 0
412
+ end
413
+
414
+ it "should return false if any entry in the array is not of the correct type, and have a base error mesage" do
415
+ @schema.validate?([1,"boo",3]).must_equal false
416
+ @schema.errors.size.must_equal 1
417
+ @schema.errors["1"].must_equal ["wrong type"]
418
+ end
419
+
420
+ it "should empty the errors array each time we validate" do
421
+ @schema.validate?([1,"boo",3]).must_equal false
422
+ @schema.errors.size.must_equal 1
423
+ @schema.errors["1"].must_equal ["wrong type"]
424
+
425
+ @schema.validate?(["boo",2,3]).must_equal false
426
+ @schema.errors.size.must_equal 1
427
+ @schema.errors["0"].must_equal ["wrong type"]
428
+ end
429
+ end
430
+
431
+ describe DuckHunt::Schemas::ArraySchema, "tuple validation (no optional items)" do
432
+ before do
433
+ @schema = DuckHunt::Schemas::ArraySchema.define do |s|
434
+ s.items do |x|
435
+ x.always_right_type
436
+ x.integer
437
+ end
438
+ end
439
+ end
440
+
441
+ it "should return false if the object provided is not an array" do
442
+ @schema.validate?("hello").must_equal false
443
+ @schema.errors.size.must_equal 1
444
+ @schema.errors["base"].must_equal ["wrong type"]
445
+ end
446
+
447
+ it "should return false if there are no items in the array" do
448
+ @schema.validate?([]).must_equal false
449
+ @schema.errors.size.must_equal 1
450
+ @schema.errors["base"].must_equal ["expected at least 2 item(s) but got 0 item(s)"]
451
+ end
452
+
453
+ it "should return false if there are fewer items in the array than what is defined in the tuple" do
454
+ @schema.validate?([1]).must_equal false
455
+ @schema.errors.size.must_equal 1
456
+ @schema.errors["base"].must_equal ["expected at least 2 item(s) but got 1 item(s)"]
457
+ end
458
+
459
+ it "should return false if there are more items in the array than what is defined in the tuple" do
460
+ @schema.validate?([1,2,3]).must_equal false
461
+ @schema.errors.size.must_equal 1
462
+ @schema.errors["base"].must_equal ["expected at most 2 item(s) but got 3 item(s)"]
463
+ end
464
+
465
+ it "should return false if any of the items are not the correct type specified for that index" do
466
+ @schema.validate?([1, "hello"]).must_equal false
467
+ @schema.errors.size.must_equal 1
468
+ @schema.errors["1"].must_equal ["wrong type"]
469
+ end
470
+
471
+ it "should return true if the items in the array match their defined type" do
472
+ @schema.validate?([1, 2]).must_equal true
473
+ @schema.errors.size.must_equal 0
474
+ end
475
+
476
+ it "should empty the errors array each time we validate" do
477
+ @schema.validate?([1, "hello"]).must_equal false
478
+ @schema.errors.size.must_equal 1
479
+ @schema.errors["1"].must_equal ["wrong type"]
480
+
481
+ @schema.validate?([1]).must_equal false
482
+ @schema.errors.size.must_equal 1
483
+ @schema.errors["base"].must_equal ["expected at least 2 item(s) but got 1 item(s)"]
484
+ end
485
+ end
486
+
487
+ describe DuckHunt::Schemas::ArraySchema, "tuple validation (with optional items)" do
488
+ before do
489
+ @schema = DuckHunt::Schemas::ArraySchema.define do |s|
490
+ s.items do |x|
491
+ x.always_right_type
492
+ x.integer
493
+ end
494
+
495
+ s.optional_items do |y|
496
+ y.integer
497
+ y.always_right_type
498
+ end
499
+ end
500
+ end
501
+
502
+ it "should return false if there are no items in the array" do
503
+ @schema.validate?([]).must_equal false
504
+ @schema.errors.size.must_equal 1
505
+ @schema.errors["base"].must_equal ["expected at least 2 item(s) but got 0 item(s)"]
506
+ end
507
+
508
+ it "should return false if there are fewer items in the array than what is defined in the tuple" do
509
+ @schema.validate?([1]).must_equal false
510
+ @schema.errors.size.must_equal 1
511
+ @schema.errors["base"].must_equal ["expected at least 2 item(s) but got 1 item(s)"]
512
+ end
513
+
514
+ it "should return true if we have extended beyond the required tuple items and into the optional items" do
515
+ @schema.validate?([1,2,3,4]).must_equal true
516
+ @schema.errors.size.must_equal 0
517
+ end
518
+
519
+ it "should return false if there are more items in the array than what is defined in the tuple (including the optional items)" do
520
+ @schema.validate?([1,2,3,4,5]).must_equal false
521
+ @schema.errors.size.must_equal 1
522
+ @schema.errors["base"].must_equal ["expected at most 4 item(s) but got 5 item(s)"]
523
+ end
524
+
525
+ it "should return false if any of the required items are not the correct type specified for that index" do
526
+ @schema.validate?([1, "hello"]).must_equal false
527
+ @schema.errors.size.must_equal 1
528
+ @schema.errors["1"].must_equal ["wrong type"]
529
+ end
530
+
531
+ it "should return false if any of the optional items are not the correct type specified for that index" do
532
+ @schema.validate?([1,2,"hello"]).must_equal false
533
+ @schema.errors.size.must_equal 1
534
+ @schema.errors["2"].must_equal ["wrong type"]
535
+ end
536
+
537
+ it "should return true if the items in the array match their defined type" do
538
+ @schema.validate?([1,2,3,4]).must_equal true
539
+ @schema.errors.size.must_equal 0
540
+ end
541
+
542
+ it "should return true if we only have the required items in the array" do
543
+ @schema.validate?([1,2]).must_equal true
544
+ @schema.errors.size.must_equal 0
545
+ end
546
+
547
+ it "should return true if we only have some of the optional items in the array" do
548
+ @schema.validate?([1,2,3]).must_equal true
549
+ @schema.errors.size.must_equal 0
550
+ end
551
+
552
+ it "should empty the errors array each time we validate" do
553
+ @schema.validate?([1, "hello"]).must_equal false
554
+ @schema.errors.size.must_equal 1
555
+ @schema.errors["1"].must_equal ["wrong type"]
556
+
557
+ @schema.validate?([1]).must_equal false
558
+ @schema.errors.size.must_equal 1
559
+ @schema.errors["base"].must_equal ["expected at least 2 item(s) but got 1 item(s)"]
560
+
561
+ @schema.validate?([1,2,"hello"]).must_equal false
562
+ @schema.errors.size.must_equal 1
563
+ @schema.errors["2"].must_equal ["wrong type"]
564
+ end
565
+ end
566
+
567
+ describe DuckHunt::Schemas::ArraySchema, "tuple validation (all optional items)" do
568
+ before do
569
+ @schema = DuckHunt::Schemas::ArraySchema.define do |s|
570
+ s.optional_items do |y|
571
+ y.integer
572
+ y.always_right_type
573
+ end
574
+ end
575
+ end
576
+
577
+ it "should return true if there are no items in the array" do
578
+ @schema.validate?([]).must_equal true
579
+ @schema.errors.size.must_equal 0
580
+ end
581
+
582
+ it "should return true if there are fewer items in the array than what is defined in the tuple" do
583
+ @schema.validate?([1]).must_equal true
584
+ @schema.errors.size.must_equal 0
585
+ end
586
+
587
+ it "should return false if there are more items in the array than what is defined in the tuple" do
588
+ @schema.validate?([1,2,3]).must_equal false
589
+ @schema.errors.size.must_equal 1
590
+ @schema.errors["base"].must_equal ["expected at most 2 item(s) but got 3 item(s)"]
591
+ end
592
+
593
+ it "should return false if any of the items are not the correct type specified for that index" do
594
+ @schema.validate?(["hello",2]).must_equal false
595
+ @schema.errors.size.must_equal 1
596
+ @schema.errors["0"].must_equal ["wrong type"]
597
+ end
598
+
599
+ it "should return true if the items in the array match their defined type" do
600
+ @schema.validate?([1,2]).must_equal true
601
+ @schema.errors.size.must_equal 0
602
+ end
603
+
604
+ it "should return true if we only have some of the optional items in the array" do
605
+ @schema.validate?([1]).must_equal true
606
+ @schema.errors.size.must_equal 0
607
+ end
608
+
609
+ it "should empty the errors array each time we validate" do
610
+ @schema.validate?(["hello",2]).must_equal false
611
+ @schema.errors.size.must_equal 1
612
+ @schema.errors["0"].must_equal ["wrong type"]
613
+
614
+ @schema.validate?([1,2,3]).must_equal false
615
+ @schema.errors.size.must_equal 1
616
+ @schema.errors["base"].must_equal ["expected at most 2 item(s) but got 3 item(s)"]
617
+ end
618
+ end
619
+
620
+ describe DuckHunt::Schemas::ArraySchema, "validating uniqueness" do
621
+ it "should return false if there were duplicates in a single-type array" do
622
+ schema = DuckHunt::Schemas::ArraySchema.define :validates_uniqueness => true do |s|
623
+ s.integer
624
+ end
625
+
626
+ schema.validate?([1,2,1]).must_equal false
627
+ schema.errors.size.must_equal 1
628
+ schema.errors["base"].must_equal ["duplicate items are not allowed"]
629
+ end
630
+
631
+ it "should return false if there were duplicates in a tuple array (no optional items)" do
632
+ schema = DuckHunt::Schemas::ArraySchema.define :validates_uniqueness => true do |s|
633
+ s.items do |x|
634
+ x.integer
635
+ x.integer
636
+ x.integer
637
+ end
638
+ end
639
+
640
+ schema.validate?([1,2,1]).must_equal false
641
+ schema.errors.size.must_equal 1
642
+ schema.errors["base"].must_equal ["duplicate items are not allowed"]
643
+ end
644
+
645
+ it "should return false if there were duplicates in a tuple array (with optional items)" do
646
+ schema = DuckHunt::Schemas::ArraySchema.define :validates_uniqueness => true do |s|
647
+ s.items do |x|
648
+ x.integer
649
+ x.integer
650
+ end
651
+
652
+ s.optional_items do |x|
653
+ x.integer
654
+ end
655
+ end
656
+
657
+ schema.validate?([1,2,1]).must_equal false
658
+ schema.errors.size.must_equal 1
659
+ schema.errors["base"].must_equal ["duplicate items are not allowed"]
660
+ end
661
+
662
+ it "should return false if there were duplicates in a tuple array (all optional items)" do
663
+ schema = DuckHunt::Schemas::ArraySchema.define :validates_uniqueness => true do |s|
664
+ s.optional_items do |x|
665
+ x.integer
666
+ x.integer
667
+ x.integer
668
+ end
669
+ end
670
+
671
+ schema.validate?([1,2,1]).must_equal false
672
+ schema.errors.size.must_equal 1
673
+ schema.errors["base"].must_equal ["duplicate items are not allowed"]
674
+ end
675
+ end
676
+
677
+ describe DuckHunt::Schemas::ArraySchema, "validating minimum size" do
678
+ it "should return false if there were not enough items in a single-type array" do
679
+ schema = DuckHunt::Schemas::ArraySchema.define :min_size => 3 do |s|
680
+ s.integer
681
+ end
682
+
683
+ schema.validate?([1,2]).must_equal false
684
+ schema.errors.size.must_equal 1
685
+ schema.errors["base"].must_equal ["expected at least 3 item(s) but got 2 item(s)"]
686
+ end
687
+
688
+ it "should return true if there were just enough items in a single-type array" do
689
+ schema = DuckHunt::Schemas::ArraySchema.define :min_size => 3 do |s|
690
+ s.integer
691
+ end
692
+
693
+ schema.validate?([1,2,3]).must_equal true
694
+ schema.errors.size.must_equal 0
695
+ end
696
+
697
+ it "should return true if there were more than enough items in a single-type array" do
698
+ schema = DuckHunt::Schemas::ArraySchema.define :min_size => 3 do |s|
699
+ s.integer
700
+ end
701
+
702
+ schema.validate?([1,2,3,4]).must_equal true
703
+ schema.errors.size.must_equal 0
704
+ end
705
+ end
706
+
707
+ describe DuckHunt::Schemas::ArraySchema, "validating maximum size" do
708
+ it "should return false if there were too many items in a single-type array" do
709
+ schema = DuckHunt::Schemas::ArraySchema.define :max_size => 3 do |s|
710
+ s.integer
711
+ end
712
+
713
+ schema.validate?([1,2,3,4]).must_equal false
714
+ schema.errors.size.must_equal 1
715
+ schema.errors["base"].must_equal ["expected at most 3 item(s) but got 4 item(s)"]
716
+ end
717
+
718
+ it "should return true if we were at the limit of items in a single-type array" do
719
+ schema = DuckHunt::Schemas::ArraySchema.define :max_size => 3 do |s|
720
+ s.integer
721
+ end
722
+
723
+ schema.validate?([1,2,3]).must_equal true
724
+ schema.errors.size.must_equal 0
725
+ end
726
+
727
+ it "should return true if we were not close to the limit in a single-type array" do
728
+ schema = DuckHunt::Schemas::ArraySchema.define :max_size => 3 do |s|
729
+ s.integer
730
+ end
731
+
732
+ schema.validate?([1]).must_equal true
733
+ schema.errors.size.must_equal 0
734
+ end
735
+ end
736
+
737
+ describe DuckHunt::Schemas::ArraySchema, "validating minimum and maximum size" do
738
+ before do
739
+ @schema = DuckHunt::Schemas::ArraySchema.define :min_size => 3, :max_size => 5 do |s|
740
+ s.integer
741
+ end
742
+ end
743
+
744
+ it "should return false if it is below the minimum" do
745
+ @schema.validate?([1,2]).must_equal false
746
+ @schema.errors.size.must_equal 1
747
+ @schema.errors["base"].must_equal ["expected at least 3 item(s) but got 2 item(s)"]
748
+ end
749
+
750
+ it "should return false if it is above the maximum" do
751
+ @schema.validate?([1,2,3,4,5,6]).must_equal false
752
+ @schema.errors.size.must_equal 1
753
+ @schema.errors["base"].must_equal ["expected at most 5 item(s) but got 6 item(s)"]
754
+ end
755
+
756
+ it "should return true if it is at the minimum" do
757
+ @schema.validate?([1,2,3]).must_equal true
758
+ @schema.errors.size.must_equal 0
759
+ end
760
+
761
+ it "should return true if it is at the maximum" do
762
+ @schema.validate?([1,2,3,4,5]).must_equal true
763
+ @schema.errors.size.must_equal 0
764
+ end
765
+
766
+ it "should return true if it is within the range" do
767
+ @schema.validate?([1,2,3,4]).must_equal true
768
+ @schema.errors.size.must_equal 0
769
+ end
770
+
771
+ it "should return true if the min and max are the same value" do
772
+ schema = DuckHunt::Schemas::ArraySchema.define :min_size => 3, :max_size => 3 do |s|
773
+ s.integer
774
+ end
775
+ schema.validate?([1,2,3]).must_equal true
776
+ schema.errors.size.must_equal 0
777
+ end
778
+ end
779
+
780
+ describe DuckHunt::Schemas::ArraySchema, "validating `allow nil`" do
781
+ it "should return false if nil is not allowed and a nil object is given" do
782
+ schema = DuckHunt::Schemas::ArraySchema.define :allow_nil => false do |s|
783
+ s.integer
784
+ end
785
+ schema.validate?(nil).must_equal false
786
+ schema.errors.size.must_equal 1
787
+ schema.errors["base"].must_equal ["nil object not allowed"]
788
+ end
789
+
790
+ it "should return true if nil is allowed and a nil object is given" do
791
+ schema = DuckHunt::Schemas::ArraySchema.define :allow_nil => true do |s|
792
+ s.integer
793
+ end
794
+ schema.validate?(nil).must_equal true
795
+ schema.errors.size.must_equal 0
796
+ end
797
+ end