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,264 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+
4
+ describe DuckHunt::Schemas::HashSchema, "defining an object through a block" do
5
+ it "should be able to define a property in the schema" do
6
+ schema = DuckHunt::Schemas::HashSchema.define do |s|
7
+ s.test "name"
8
+ end
9
+
10
+ schema.properties.size.must_equal 1
11
+ schema.properties["name"].wont_be_nil
12
+ schema.properties["name"].required?.must_equal true
13
+ end
14
+
15
+ it "should be able to set the options of a property in the schema" do
16
+ schema = DuckHunt::Schemas::HashSchema.define do |s|
17
+ s.test "name", :required => false
18
+ end
19
+
20
+ schema.properties.size.must_equal 1
21
+ schema.properties["name"].wont_be_nil
22
+ schema.properties["name"].required?.must_equal false
23
+ end
24
+
25
+ it "should default the `strict mode` to `true`" do
26
+ schema = DuckHunt::Schemas::HashSchema.define do |s|
27
+ end
28
+
29
+ schema.strict_mode.must_equal true
30
+ schema.strict_mode?.must_equal true
31
+ end
32
+
33
+ it "should allow the strict mode to be set to false" do
34
+ schema = DuckHunt::Schemas::HashSchema.define :strict_mode => false do |s|
35
+ s.test "name"
36
+ end
37
+ schema.strict_mode.must_equal false
38
+ schema.strict_mode?.must_equal false
39
+ end
40
+ end
41
+
42
+ describe DuckHunt::Schemas::HashSchema, "defining an object without a block" do
43
+ it "should default the strict mode to true" do
44
+ schema = DuckHunt::Schemas::HashSchema.new
45
+ schema.strict_mode.must_equal true
46
+ schema.strict_mode?.must_equal true
47
+ end
48
+
49
+ it "should allow the strict mode to be set to false" do
50
+ schema = DuckHunt::Schemas::HashSchema.new(:strict_mode => false)
51
+ schema.strict_mode.must_equal false
52
+ schema.strict_mode?.must_equal false
53
+ end
54
+ end
55
+
56
+
57
+ describe DuckHunt::Schemas::HashSchema, "defining properties" do
58
+ it "should be able to add a new property to the schema, which is required by default" do
59
+ schema = DuckHunt::Schemas::HashSchema.new
60
+ schema.test "name"
61
+ schema.properties.size.must_equal 1
62
+ schema.properties["name"].wont_be_nil
63
+ schema.properties["name"].required.must_equal true
64
+ schema.properties["name"].required?.must_equal true
65
+ end
66
+
67
+ it "should allow a property to be explictly set as required" do
68
+ schema = DuckHunt::Schemas::HashSchema.new
69
+ schema.test "name", :required => true
70
+ schema.test "item", "required" => true
71
+
72
+ schema.properties.size.must_equal 2
73
+
74
+ schema.properties["name"].wont_be_nil
75
+ schema.properties["name"].required.must_equal true
76
+ schema.properties["name"].required?.must_equal true
77
+ schema.properties["item"].wont_be_nil
78
+ schema.properties["item"].required.must_equal true
79
+ schema.properties["item"].required?.must_equal true
80
+ end
81
+
82
+ it "should allow a property to be set as not required" do
83
+ schema = DuckHunt::Schemas::HashSchema.new
84
+
85
+ schema.test "name", :required => false
86
+ schema.test "item", "required" => false
87
+
88
+ schema.properties.size.must_equal 2
89
+ schema.properties["name"].wont_be_nil
90
+ schema.properties["name"].required.must_equal false
91
+ schema.properties["name"].required?.must_equal false
92
+ schema.properties["item"].wont_be_nil
93
+ schema.properties["item"].required.must_equal false
94
+ schema.properties["item"].required?.must_equal false
95
+ end
96
+
97
+ it "should require that properties are named" do
98
+ schema = DuckHunt::Schemas::HashSchema.new
99
+ lambda{
100
+ schema.test
101
+ }.must_raise(ArgumentError)
102
+
103
+ lambda{
104
+ schema.test ""
105
+ }.must_raise(ArgumentError)
106
+ end
107
+
108
+
109
+ it "should prevent a property from being defined multiple times in a schema" do
110
+ schema = DuckHunt::Schemas::HashSchema.new
111
+ schema.test "name"
112
+
113
+ lambda {
114
+ schema.test "name"
115
+ }.must_raise(DuckHunt::PropertyAlreadyDefined)
116
+ end
117
+
118
+ it "should ensure the list of properties cannot be modified" do
119
+ schema = DuckHunt::Schemas::HashSchema.new
120
+ schema.test "name"
121
+ schema.properties.size.must_equal 1
122
+
123
+ schema.properties["malicious"] = "muwah ha ha"
124
+ schema.properties.size.must_equal 1
125
+
126
+ lambda{
127
+ schema.properties = {:malicious => "mwuah ha ha"}
128
+ }.must_raise(NameError)
129
+ end
130
+
131
+ it "should ensure the list of required properties cannot be modified" do
132
+ schema = DuckHunt::Schemas::HashSchema.new
133
+ schema.test "name"
134
+ lambda{
135
+ schema.required_properties = {:malicious => "mwuah ha ha"}
136
+ }.must_raise(NameError)
137
+ end
138
+
139
+ it "should pass a block down to the property being defined" do
140
+ schema = DuckHunt::Schemas::HashSchema.new
141
+ schema.test_block_passed "name" do
142
+ 1+1
143
+ end
144
+
145
+ schema.properties["name"].block_passed.must_equal true
146
+ end
147
+ end
148
+
149
+ describe DuckHunt::Schemas::HashSchema, "validation (strict mode)" do
150
+ it "should return false if the object provided is not a hash" do
151
+ schema = DuckHunt::Schemas::HashSchema.define do |s|
152
+ s.test "name"
153
+ end
154
+
155
+ schema.validate?("hello").must_equal false
156
+ schema.errors.size.must_equal 1
157
+ schema.errors["base"].must_equal ["wrong type"]
158
+ end
159
+
160
+ it "should return false if one of the properties is not valid" do
161
+ schema = DuckHunt::Schemas::HashSchema.define do |s|
162
+ s.always_wrong_type "name"
163
+ end
164
+
165
+ schema.validate?({:name => "hello"}).must_equal false
166
+ schema.errors.size.must_equal 1
167
+ schema.errors["name"].must_equal ["wrong type"]
168
+ end
169
+
170
+ it "should return false if the object is missing a required property" do
171
+ schema = DuckHunt::Schemas::HashSchema.define do |s|
172
+ s.test "name", :required => true
173
+ s.always_right_type "hello", :required => false
174
+ end
175
+
176
+ schema.validate?({:hello => "hello"}).must_equal false
177
+ schema.errors.size.must_equal 1
178
+ schema.errors["name"].must_equal ["required"]
179
+ end
180
+
181
+ it "should return false if the schema has been set to strict mode and the hash provided has extra properties" do
182
+ schema = DuckHunt::Schemas::HashSchema.define do |s|
183
+ s.test "name", :required => true
184
+ end
185
+
186
+ schema.validate?({:name => "hello", :hello => "hello"}).must_equal false
187
+ schema.errors.size.must_equal 1
188
+ schema.errors["base"].must_equal ["has properties not defined in schema"]
189
+ end
190
+
191
+ it "should not retain the 'has properties not defined in schema' error message when validated twice" do
192
+ schema = DuckHunt::Schemas::HashSchema.define do |s|
193
+ s.always_right_type "name", :required => true
194
+ end
195
+
196
+ schema.validate?({:name => "hello", :hello => "hello"}).must_equal false
197
+ schema.errors.size.must_equal 1
198
+ schema.errors["base"].must_equal ["has properties not defined in schema"]
199
+
200
+ schema.validate?({:name => "hello"}).must_equal true
201
+ schema.errors.size.must_equal 0
202
+ end
203
+ end
204
+
205
+ describe DuckHunt::Schemas::HashSchema, "validation (relaxed mode)" do
206
+ it "should return false if the object provided is not a hash" do
207
+ schema = DuckHunt::Schemas::HashSchema.define :strict_mode => false do |s|
208
+ s.test "name"
209
+ end
210
+
211
+ schema.validate?("hello").must_equal false
212
+ schema.errors.size.must_equal 1
213
+ schema.errors["base"].must_equal ["wrong type"]
214
+ end
215
+
216
+ it "should return false if one of the properties is not valid" do
217
+ schema = DuckHunt::Schemas::HashSchema.define :strict_mode => false do |s|
218
+ s.always_wrong_type "name"
219
+ end
220
+
221
+ schema.validate?({:name => "hello"}).must_equal false
222
+ schema.errors.size.must_equal 1
223
+ schema.errors["name"].must_equal ["wrong type"]
224
+ end
225
+
226
+ it "should return false if the object is missing a required property" do
227
+ schema = DuckHunt::Schemas::HashSchema.define :strict_mode => false do |s|
228
+ s.test "name", :required => true
229
+ s.always_right_type "hello", :required => false
230
+ end
231
+
232
+ schema.validate?({:hello => "hello"}).must_equal false
233
+ schema.errors.size.must_equal 1
234
+ schema.errors["name"].must_equal ["required"]
235
+ end
236
+
237
+ it "should return true if the schema has been set to relaxed mode and the hash provided has extra properties" do
238
+ schema = DuckHunt::Schemas::HashSchema.define :strict_mode => false do |s|
239
+ s.always_right_type "name", :required => true
240
+ end
241
+
242
+ schema.validate?({:name => "hello", :hello => "hello"}).must_equal true
243
+ schema.errors.size.must_equal 0
244
+ end
245
+ end
246
+
247
+ describe DuckHunt::Schemas::HashSchema, "validating `allow nil`" do
248
+ it "should return false if nil is not allowed and a nil object is given" do
249
+ schema = DuckHunt::Schemas::HashSchema.define :allow_nil => false do |s|
250
+ s.test "name"
251
+ end
252
+ schema.validate?(nil).must_equal false
253
+ schema.errors.size.must_equal 1
254
+ schema.errors["base"].must_equal ["nil object not allowed"]
255
+ end
256
+
257
+ it "should return true if nil is allowed and a nil object is given" do
258
+ schema = DuckHunt::Schemas::HashSchema.define :allow_nil => true do |s|
259
+ s.test "name"
260
+ end
261
+ schema.validate?(nil).must_equal true
262
+ schema.errors.size.must_equal 0
263
+ end
264
+ end
@@ -0,0 +1,41 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ class PropertyLookupTestClass
4
+ include DuckHunt::Schemas::PropertyLookup
5
+ end
6
+
7
+ class PropertyLookupBlockPassTestClass
8
+ include DuckHunt::Schemas::PropertyLookup
9
+ attr_reader :block_passed
10
+ def add_property(property_constant, *args, &block)
11
+ @block_passed = true if block_given?
12
+ end
13
+ end
14
+
15
+ describe DuckHunt::Schemas::PropertyLookup, "Adding a property to the schema" do
16
+ it "should raise a `NotImplementedError` if the property definition exists (classes using this module must implement `add_property`" do
17
+ schema = PropertyLookupTestClass.new
18
+ lambda {
19
+ schema.test
20
+ }.must_raise(NotImplementedError)
21
+ end
22
+
23
+ it "should raise NoMethodError if the property definition does not exist (it was not found)" do
24
+ schema = PropertyLookupTestClass.new
25
+ lambda {
26
+ schema.herp
27
+ }.must_raise(NoMethodError)
28
+ end
29
+
30
+ it "should pass the provided block down for property initializers to use" do
31
+ schema = PropertyLookupBlockPassTestClass.new
32
+ schema.test { 1+1 }
33
+ schema.block_passed.must_equal true
34
+ end
35
+
36
+ it "should not break if a block is not provided" do
37
+ schema = PropertyLookupBlockPassTestClass.new
38
+ schema.test
39
+ schema.block_passed.must_be_nil
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ class SchemaDefinitionTestClass
4
+ include DuckHunt::Schemas::SchemaDefinition
5
+
6
+ attr_accessor :other_value
7
+
8
+ def initialize(options=nil)
9
+ self.other_value = "hello"
10
+ self.other_value = options unless options.nil?
11
+ end
12
+
13
+ def setter!
14
+ @value = 1
15
+ end
16
+
17
+ def getter
18
+ @value
19
+ end
20
+ end
21
+
22
+ describe DuckHunt::Schemas::SchemaDefinition, "defining an object through a block" do
23
+ it "should accept a block through the `define` method and use it create a new instance of the class and call instance methods" do
24
+ schema = SchemaDefinitionTestClass.define do |s|
25
+ s.setter!
26
+ end
27
+
28
+ schema.must_be_instance_of SchemaDefinitionTestClass
29
+ schema.getter.must_equal 1
30
+ end
31
+
32
+ it "should still call the `initialize` method defined in the class when `define` is used" do
33
+ schema = SchemaDefinitionTestClass.define do |s|
34
+ s.setter!
35
+ end
36
+
37
+ schema.must_be_instance_of SchemaDefinitionTestClass
38
+ schema.getter.must_equal 1
39
+ schema.other_value.must_equal "hello"
40
+ end
41
+
42
+ it "should pass initialization parameters to the class when `define` is used" do
43
+ schema = SchemaDefinitionTestClass.define "neato!" do |s|
44
+ s.setter!
45
+ end
46
+
47
+ schema.must_be_instance_of SchemaDefinitionTestClass
48
+ schema.getter.must_equal 1
49
+ schema.other_value.must_equal "neato!"
50
+ end
51
+ end
@@ -0,0 +1,29 @@
1
+ # add our ./lib path to the require paths
2
+ $: << File.expand_path(File.dirname(__FILE__) + "/../lib")
3
+
4
+ # add our test path to the require paths (used when loading test helpers)
5
+ $: << File.expand_path(File.dirname(__FILE__))
6
+
7
+ # load our gems installed via Bundler
8
+ require 'rubygems'
9
+ require 'bundler/setup'
10
+
11
+ # try to load common debugging gems
12
+ ["ruby-debug", "debugger"].each{|debugging_library|
13
+ begin
14
+ require debugging_library
15
+ rescue LoadError
16
+ # no big deal; it's only useful in development
17
+ end
18
+ }
19
+
20
+ require 'minitest/autorun'
21
+ require 'minitest/spec'
22
+ require 'minitest/pride'
23
+ require 'mocha/setup'
24
+ require 'set'
25
+ require 'bigdecimal'
26
+ require 'duck-hunt'
27
+
28
+ #require some basic test classes (useful for testing modules independently)
29
+ require 'test_helper/test_classes'
@@ -0,0 +1,74 @@
1
+ class DuckHunt::Properties::Test < DuckHunt::Properties::Property
2
+ end
3
+
4
+ class DuckHunt::Properties::TestBlockPassed < DuckHunt::Properties::Property
5
+ attr_reader :block_passed
6
+ def initialize(options={}, &block)
7
+ @block_passed = true if block_given?
8
+ end
9
+ end
10
+
11
+ class DuckHunt::Properties::AlwaysRightType < DuckHunt::Properties::Property
12
+ def matches_type?(value)
13
+ return true
14
+ end
15
+ end
16
+
17
+ class DuckHunt::Properties::AlwaysWrongType < DuckHunt::Properties::Property
18
+ def matches_type?(value)
19
+ return false
20
+ end
21
+ end
22
+
23
+ class DuckHunt::Validators::Test < DuckHunt::Validators::Validator
24
+ end
25
+
26
+ class DuckHunt::Validators::AlwaysWrong < DuckHunt::Validators::Validator
27
+ def valid?(value)
28
+ return false
29
+ end
30
+
31
+ def error_message
32
+ "Always Wrong"
33
+ end
34
+ end
35
+
36
+ class DuckHunt::Validators::WrongAgain < DuckHunt::Validators::Validator
37
+ def valid?(value)
38
+ return false
39
+ end
40
+
41
+ def error_message
42
+ "Wrong Again"
43
+ end
44
+ end
45
+
46
+ class DuckHunt::Validators::AlwaysRight < DuckHunt::Validators::Validator
47
+ def valid?(value)
48
+ return true
49
+ end
50
+
51
+ def error_message
52
+ "How did this happen?"
53
+ end
54
+ end
55
+
56
+ class DuckHunt::Validators::RightAgain < DuckHunt::Validators::Validator
57
+ def valid?(value)
58
+ return true
59
+ end
60
+
61
+ def error_message
62
+ "Wha?"
63
+ end
64
+ end
65
+
66
+ class DuckHunt::Validators::AlwaysRaiseException < DuckHunt::Validators::Validator
67
+ def valid?(value)
68
+ raise Exception, "Bad!"
69
+ end
70
+
71
+ def error_message
72
+ "Bad!"
73
+ end
74
+ end