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