respect 0.1.0
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.
- data/MIT-LICENSE +20 -0
- data/README.md +289 -0
- data/RELATED_WORK.md +40 -0
- data/RELEASE_NOTES.md +23 -0
- data/Rakefile +31 -0
- data/STATUS_MATRIX.html +137 -0
- data/lib/respect.rb +231 -0
- data/lib/respect/any_schema.rb +22 -0
- data/lib/respect/array_def.rb +28 -0
- data/lib/respect/array_schema.rb +203 -0
- data/lib/respect/boolean_schema.rb +32 -0
- data/lib/respect/composite_schema.rb +86 -0
- data/lib/respect/core_statements.rb +206 -0
- data/lib/respect/datetime_schema.rb +27 -0
- data/lib/respect/def_without_name.rb +6 -0
- data/lib/respect/divisible_by_validator.rb +20 -0
- data/lib/respect/doc_helper.rb +24 -0
- data/lib/respect/doc_parser.rb +37 -0
- data/lib/respect/dsl_dumper.rb +181 -0
- data/lib/respect/equal_to_validator.rb +20 -0
- data/lib/respect/fake_name_proxy.rb +116 -0
- data/lib/respect/float_schema.rb +27 -0
- data/lib/respect/format_validator.rb +136 -0
- data/lib/respect/global_def.rb +79 -0
- data/lib/respect/greater_than_or_equal_to_validator.rb +19 -0
- data/lib/respect/greater_than_validator.rb +19 -0
- data/lib/respect/has_constraints.rb +34 -0
- data/lib/respect/hash_def.rb +40 -0
- data/lib/respect/hash_schema.rb +218 -0
- data/lib/respect/in_validator.rb +19 -0
- data/lib/respect/integer_schema.rb +27 -0
- data/lib/respect/ip_addr_schema.rb +23 -0
- data/lib/respect/ipv4_addr_schema.rb +27 -0
- data/lib/respect/ipv6_addr_schema.rb +27 -0
- data/lib/respect/items_def.rb +21 -0
- data/lib/respect/json_schema_html_formatter.rb +143 -0
- data/lib/respect/less_than_or_equal_to_validator.rb +19 -0
- data/lib/respect/less_than_validator.rb +19 -0
- data/lib/respect/match_validator.rb +19 -0
- data/lib/respect/max_length_validator.rb +20 -0
- data/lib/respect/min_length_validator.rb +20 -0
- data/lib/respect/multiple_of_validator.rb +10 -0
- data/lib/respect/null_schema.rb +26 -0
- data/lib/respect/numeric_schema.rb +33 -0
- data/lib/respect/org3_dumper.rb +213 -0
- data/lib/respect/regexp_schema.rb +19 -0
- data/lib/respect/schema.rb +285 -0
- data/lib/respect/schema_def.rb +16 -0
- data/lib/respect/string_schema.rb +21 -0
- data/lib/respect/unit_test_helper.rb +37 -0
- data/lib/respect/uri_schema.rb +23 -0
- data/lib/respect/utc_time_schema.rb +17 -0
- data/lib/respect/validator.rb +51 -0
- data/lib/respect/version.rb +3 -0
- data/test/any_schema_test.rb +79 -0
- data/test/array_def_test.rb +113 -0
- data/test/array_schema_test.rb +487 -0
- data/test/boolean_schema_test.rb +89 -0
- data/test/composite_schema_test.rb +30 -0
- data/test/datetime_schema_test.rb +83 -0
- data/test/doc_helper_test.rb +34 -0
- data/test/doc_parser_test.rb +109 -0
- data/test/dsl_dumper_test.rb +395 -0
- data/test/fake_name_proxy_test.rb +138 -0
- data/test/float_schema_test.rb +146 -0
- data/test/format_validator_test.rb +224 -0
- data/test/hash_def_test.rb +126 -0
- data/test/hash_schema_test.rb +613 -0
- data/test/integer_schema_test.rb +142 -0
- data/test/ip_addr_schema_test.rb +78 -0
- data/test/ipv4_addr_schema_test.rb +71 -0
- data/test/ipv6_addr_schema_test.rb +71 -0
- data/test/json_schema_html_formatter_test.rb +214 -0
- data/test/null_schema_test.rb +46 -0
- data/test/numeric_schema_test.rb +294 -0
- data/test/org3_dumper_test.rb +784 -0
- data/test/regexp_schema_test.rb +54 -0
- data/test/respect_test.rb +108 -0
- data/test/schema_def_test.rb +405 -0
- data/test/schema_test.rb +290 -0
- data/test/string_schema_test.rb +209 -0
- data/test/support/circle.rb +11 -0
- data/test/support/color.rb +24 -0
- data/test/support/point.rb +11 -0
- data/test/support/respect/circle_schema.rb +16 -0
- data/test/support/respect/color_def.rb +19 -0
- data/test/support/respect/color_schema.rb +33 -0
- data/test/support/respect/point_schema.rb +19 -0
- data/test/support/respect/rgba_schema.rb +20 -0
- data/test/support/respect/universal_validator.rb +25 -0
- data/test/support/respect/user_macros.rb +12 -0
- data/test/support/rgba.rb +11 -0
- data/test/test_helper.rb +90 -0
- data/test/uri_schema_test.rb +54 -0
- data/test/utc_time_schema_test.rb +63 -0
- data/test/validator_test.rb +22 -0
- metadata +288 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class HashDefTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_hash_schema_definition_accept_integer
|
6
|
+
s = Respect::HashSchema.define do |s|
|
7
|
+
s.integer "test", equal_to: 15
|
8
|
+
s.extra do |s|
|
9
|
+
s.integer "opt", equal_to: 43
|
10
|
+
end
|
11
|
+
end
|
12
|
+
assert_schema_validate s, { "test" => "15", "opt" => "43" }
|
13
|
+
assert_schema_validate s, { "test" => 15, "opt" => 43 }
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_hash_schema_definition_accept_null
|
17
|
+
s = Respect::HashSchema.define do |s|
|
18
|
+
s.null "test"
|
19
|
+
s.extra do |s|
|
20
|
+
s.null "opt"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
assert_schema_validate s, { "test" => "null", "opt" => "null" }
|
24
|
+
assert_schema_validate s, { "test" => nil, "opt" => nil }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_hash_schema_definition_accept_float
|
28
|
+
s = Respect::HashSchema.define do |s|
|
29
|
+
s.float "test", equal_to: 1.5
|
30
|
+
s.extra do |s|
|
31
|
+
s.float "opt", equal_to: 4.3
|
32
|
+
end
|
33
|
+
end
|
34
|
+
assert_schema_validate s, { "test" => "1.5", "opt" => "4.3" }
|
35
|
+
assert_schema_validate s, { "test" => 1.5, "opt" => 4.3 }
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_hash_schema_definition_accept_boolean
|
39
|
+
s = Respect::HashSchema.define do |s|
|
40
|
+
s.boolean "test", equal_to: false
|
41
|
+
s.extra do |s|
|
42
|
+
s.boolean "opt", equal_to: false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
assert_schema_validate s, { "test" => "false", "opt" => "false" }
|
46
|
+
assert_schema_validate s, { "test" => false, "opt" => false }
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_hash_schema_definition_accept_array
|
50
|
+
s = Respect::HashSchema.define do |s|
|
51
|
+
s.array "test"
|
52
|
+
s.extra do |s|
|
53
|
+
s.array "opt"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
assert_schema_validate s, { "test" => [], "opt" => [] }
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_cannot_overwrite_property
|
60
|
+
assert_raise(Respect::InvalidSchemaError) do
|
61
|
+
Respect::HashSchema.define do |s|
|
62
|
+
s.integer "id", equal_to: 42
|
63
|
+
s.integer "id", equal_to: 51
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_extra_properties_overwrite_expected_ones
|
69
|
+
assert_raise(Respect::InvalidSchemaError) do
|
70
|
+
Respect::HashSchema.define(strict: true) do |s|
|
71
|
+
s.integer "test", equal_to: 42
|
72
|
+
s.extra do |s|
|
73
|
+
s.integer "test", equal_to: 51
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_hash_scope_accept_options
|
80
|
+
s = Respect::HashSchema.define do |s|
|
81
|
+
s.hash "test", strict: true do |s|
|
82
|
+
s.integer "test", equal_to: 42
|
83
|
+
end
|
84
|
+
end
|
85
|
+
assert s["test"].options[:strict]
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_factor_options_with_with_options
|
89
|
+
s = Respect::HashSchema.define do |s|
|
90
|
+
s.integer "test", equal_to: 42
|
91
|
+
s.with_options required: false do |s|
|
92
|
+
assert_nothing_raised("fake name proxy") do
|
93
|
+
s.target
|
94
|
+
end
|
95
|
+
s.doc "doc opt1"
|
96
|
+
s.integer "opt1", greater_than: 0
|
97
|
+
s.doc "doc opt2"
|
98
|
+
s.integer "opt2", less_than: 0
|
99
|
+
end
|
100
|
+
end
|
101
|
+
assert_equal(42, s["test"].options[:equal_to])
|
102
|
+
assert_equal(true, s["test"].options[:required])
|
103
|
+
assert_equal(false, s["opt1"].options[:required])
|
104
|
+
assert_equal(0, s["opt1"].options[:greater_than])
|
105
|
+
assert_equal("doc opt1", s["opt1"].doc)
|
106
|
+
assert_equal(false, s["opt2"].options[:required])
|
107
|
+
assert_equal(0, s["opt2"].options[:less_than])
|
108
|
+
assert_equal("doc opt2", s["opt2"].doc)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_key_assignment_with_string_value_create_string_schema_with_equal_to_validator
|
112
|
+
h = Respect::HashSchema.define do |h|
|
113
|
+
h["key"] = "value"
|
114
|
+
end
|
115
|
+
assert_equal Respect::StringSchema.new(equal_to: "value"), h["key"]
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_assign_an_object_create_any_with_equal_to_validating_its_string_representation
|
119
|
+
o = Object.new
|
120
|
+
h = Respect::HashSchema.define do |h|
|
121
|
+
h["any"] = o
|
122
|
+
end
|
123
|
+
s = Respect::AnySchema.new(equal_to: o.to_s)
|
124
|
+
assert_equal s, h["any"]
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,613 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class HashSchemaTest < Test::Unit::TestCase
|
4
|
+
def test_validate_return_true_on_success
|
5
|
+
s = Respect::HashSchema.define do |s|
|
6
|
+
s.integer "id", equal_to: 42
|
7
|
+
end
|
8
|
+
assert s.validate({ "id" => 42 })
|
9
|
+
|
10
|
+
s = Respect::HashSchema.new
|
11
|
+
assert s.validate({})
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_validate_raise_exception_on_error
|
15
|
+
s = Respect::HashSchema.define do |s|
|
16
|
+
s.integer "id", equal_to: 42
|
17
|
+
end
|
18
|
+
assert_raise(Respect::ValidationError) do
|
19
|
+
s.validate({ "asdf" => 42 })
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_validate?
|
24
|
+
s = Respect::HashSchema.define do |s|
|
25
|
+
s.integer "id", equal_to: 42
|
26
|
+
end
|
27
|
+
assert_schema_invalidate s, { "asdf" => 42 }
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_recursive_schema
|
31
|
+
s = Respect::HashSchema.define do |s|
|
32
|
+
s.hash "test" do |s|
|
33
|
+
s.integer "test", equal_to: 42
|
34
|
+
end
|
35
|
+
end
|
36
|
+
assert_schema_validate s, { "test" => { "test" => 42 } }
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_hash_validate
|
40
|
+
s = Respect::HashSchema.define do |s|
|
41
|
+
s.integer "test", equal_to: 42
|
42
|
+
end
|
43
|
+
[
|
44
|
+
[ {}, false, "empty hash" ],
|
45
|
+
[ { "foo" => 42 }, false, "no expected property" ],
|
46
|
+
[ { "test" => 42, "foo" => 60 }, true, "extra property" ],
|
47
|
+
].each do |data|
|
48
|
+
assert_schema_validation_is data[1], s, data[0], data[2]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_empty_hash_schema_validate_all_hash
|
53
|
+
s = Respect::HashSchema.define do |s|
|
54
|
+
end
|
55
|
+
[
|
56
|
+
[ {}, true, "empty hash" ],
|
57
|
+
[ { "foo" => 42 }, true, "no expected property" ],
|
58
|
+
[ { "test" => 42, "foo" => 60 }, true, "extra property" ],
|
59
|
+
].each do |data|
|
60
|
+
assert_schema_validation_is data[1], s, data[0], data[2]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_hash_schema_do_not_validate_other_type
|
65
|
+
s = Respect::HashSchema.define do |s|
|
66
|
+
s.integer "test", greater_than: 0
|
67
|
+
end
|
68
|
+
[
|
69
|
+
[ { "test" => 1 } ],
|
70
|
+
42,
|
71
|
+
"test",
|
72
|
+
nil,
|
73
|
+
].each do |doc|
|
74
|
+
assert_raise(Respect::ValidationError) do
|
75
|
+
s.validate(doc)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_hash_stricly_validate
|
81
|
+
s = Respect::Schema.define do |s|
|
82
|
+
s.hash strict: true do |s|
|
83
|
+
s.integer "p1", equal_to: 3
|
84
|
+
s.string "p2", equal_to: "val"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
[
|
88
|
+
[ { "p1" => 3, "p2" => "val" }, true, "valid", ],
|
89
|
+
[ { "p1" => 3 }, false, "not enough properties" ],
|
90
|
+
[ { "p1" => 3, "p2" => "val", "additional" => "foo" }, false, "too many properties" ],
|
91
|
+
].each do |data|
|
92
|
+
assert_schema_validation_is data[1], s, data[0], data[2]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_optional_property
|
97
|
+
s1 = Respect::HashSchema.define do |s|
|
98
|
+
s.integer "test", equal_to: 42
|
99
|
+
s.extra do |s|
|
100
|
+
s.integer "opt", equal_to: 51
|
101
|
+
end
|
102
|
+
end
|
103
|
+
s2 = Respect::HashSchema.define do |s|
|
104
|
+
s.integer "test", equal_to: 42
|
105
|
+
s.integer "opt", equal_to: 51, required: false
|
106
|
+
end
|
107
|
+
[
|
108
|
+
[ {}, false, "empty hash", ],
|
109
|
+
[ { "test" => 42 }, true, "only expected property", ],
|
110
|
+
[ { "test" => 42, "opt" => 51 }, true, "expected and optional properties" ],
|
111
|
+
[ { "test" => 42, "opt" => 64 }, false, "invalid optional property" ],
|
112
|
+
[ { "test" => 54, "opt" => 51 }, false, "invalid expected property" ],
|
113
|
+
[ { "opt" => 51 }, false, "only optional property" ],
|
114
|
+
[ { "test" => 42, "extra" => 1, "opt" => 51 }, true, "extra and optional property" ],
|
115
|
+
[ { "test" => 42, "extra" => 1 }, true, "extra property" ],
|
116
|
+
].each do |data|
|
117
|
+
assert_schema_validation_is data[1], s1, data[0], data[2]
|
118
|
+
assert_schema_validation_is data[1], s2, data[0], data[2]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_optional_property_with_strict_validation
|
123
|
+
s = Respect::HashSchema.define(strict: true) do |s|
|
124
|
+
s.integer "test", equal_to: 42
|
125
|
+
s.extra do |s|
|
126
|
+
s.integer "opt", equal_to: 51
|
127
|
+
end
|
128
|
+
end
|
129
|
+
[
|
130
|
+
[ { "test" => 42, "extra" => 1, "opt" => 51 }, false, "extra and optional property" ],
|
131
|
+
[ { "test" => 42, "extra" => 1 }, false, "extra property" ],
|
132
|
+
[ { "test" => 42, "opt" => 51 }, true, "required and optional properties" ],
|
133
|
+
[ { "test" => 42, }, true, "only required property" ],
|
134
|
+
].each do |data|
|
135
|
+
assert_schema_validation_is data[1], s, data[0], data[2]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_symbolized_property_name_are_kept_verbatim
|
140
|
+
s = Respect::HashSchema.define do |s|
|
141
|
+
s.integer :test, equal_to: 42
|
142
|
+
s.extra do |s|
|
143
|
+
s.integer :opt, equal_to: 51
|
144
|
+
end
|
145
|
+
s.string :foo, required: false
|
146
|
+
s.hash :bar, default: { a: "b" }
|
147
|
+
s.string "a_string"
|
148
|
+
s.string /foo/
|
149
|
+
end
|
150
|
+
assert s.properties.has_key?(:test)
|
151
|
+
assert s.properties.has_key?("a_string")
|
152
|
+
assert s.properties.has_key?(/foo/)
|
153
|
+
assert s.optional_properties.has_key?(:opt)
|
154
|
+
assert s.optional_properties.has_key?(:foo)
|
155
|
+
assert s.optional_properties.has_key?(:bar)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_symbol_key_are_stringified_at_validation
|
159
|
+
s = Respect::HashSchema.define do |s|
|
160
|
+
s.integer :test, equal_to: 42
|
161
|
+
end
|
162
|
+
assert_schema_validate s, { "test" => 42 }
|
163
|
+
assert s.properties.has_key?(:test)
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_can_define_empty_strict_hash_schema
|
167
|
+
s = Respect::Schema.define do |s|
|
168
|
+
s.hash strict: true
|
169
|
+
end
|
170
|
+
assert_equal true, s.options[:strict]
|
171
|
+
assert_schema_validate s, {}
|
172
|
+
assert_schema_invalidate s, { a: "b" }
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_can_define_empty_hash_schema
|
176
|
+
s = Respect::Schema.define do |s|
|
177
|
+
s.hash
|
178
|
+
end
|
179
|
+
assert_equal false, s.options[:strict]
|
180
|
+
assert_schema_validate s, {}
|
181
|
+
assert_schema_validate s, { a: "b" }
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_access_to_extra_properties
|
185
|
+
s = Respect::HashSchema.define do |s|
|
186
|
+
s.integer :test, equal_to: 42
|
187
|
+
s.extra do |s|
|
188
|
+
s.integer :opt, equal_to: 51
|
189
|
+
end
|
190
|
+
s.string :foo, required: false
|
191
|
+
s.hash :bar, default: { a: "b" }
|
192
|
+
end
|
193
|
+
assert s.properties.has_key?(:test)
|
194
|
+
assert s.properties.has_key?(:opt)
|
195
|
+
assert s.properties.has_key?(:foo)
|
196
|
+
assert s.properties.has_key?(:bar)
|
197
|
+
assert !s.optional_properties.has_key?(:test)
|
198
|
+
assert s.optional_properties.has_key?(:opt)
|
199
|
+
assert s.optional_properties.has_key?(:foo)
|
200
|
+
assert s.optional_properties.has_key?(:bar)
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_default_value_used_when_property_unset
|
204
|
+
s = Respect::HashSchema.define do |s|
|
205
|
+
s.integer "test", default: 42
|
206
|
+
end
|
207
|
+
# Empty hash.
|
208
|
+
s.validate({})
|
209
|
+
assert_equal({ "test" => 42 }, s.sanitized_object)
|
210
|
+
# Hash with extra property.
|
211
|
+
s.validate({ "foo" => 51 })
|
212
|
+
assert_equal({ "test" => 42 }, s.sanitized_object)
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_default_value_do_not_overwrite_defined_one
|
216
|
+
s = Respect::HashSchema.define do |s|
|
217
|
+
s.integer "test", default: 42
|
218
|
+
end
|
219
|
+
s.validate({ "test" => 54 })
|
220
|
+
assert_equal({ "test" => 54 }, s.sanitized_object)
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_validate_matched_properties
|
224
|
+
s = Respect::HashSchema.define do |s|
|
225
|
+
s.integer /test/, equal_to: 42
|
226
|
+
end
|
227
|
+
assert_schema_validate s, { "test" => 42, "_test_" => 42, "unmatch" => 51 }
|
228
|
+
assert_schema_invalidate s, { "test" => 42, "_test_" => 51, "unmatch" => 51 }
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_integer_invalid_property_name
|
232
|
+
assert_raises(Respect::InvalidSchemaError) do
|
233
|
+
Respect::HashSchema.define do |s|
|
234
|
+
s.integer 42, equal_to: 42
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_access_to_pattern_properties
|
240
|
+
s = Respect::HashSchema.define do |s|
|
241
|
+
s.integer "test", equal_to: 42
|
242
|
+
s.string /foo/, equal_to: 51
|
243
|
+
end
|
244
|
+
assert s.properties.has_key?("test")
|
245
|
+
assert s.properties.has_key?(/foo/)
|
246
|
+
assert s.pattern_properties.has_key?(/foo/)
|
247
|
+
assert !s.pattern_properties.has_key?("test")
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_hash_schema_statement_expect_name_argument
|
251
|
+
[
|
252
|
+
:hash,
|
253
|
+
:integer,
|
254
|
+
:string,
|
255
|
+
:array,
|
256
|
+
:any,
|
257
|
+
:boolean,
|
258
|
+
:null,
|
259
|
+
:float,
|
260
|
+
:numeric,
|
261
|
+
].each do |meth_name|
|
262
|
+
assert_raise(Respect::InvalidSchemaError) do
|
263
|
+
Respect::HashSchema.define do |s|
|
264
|
+
s.__send__(meth_name, {})
|
265
|
+
end
|
266
|
+
end
|
267
|
+
assert_raise(Respect::InvalidSchemaError) do
|
268
|
+
Respect::HashSchema.define do |s|
|
269
|
+
s.extra do |s|
|
270
|
+
s.__send__(meth_name, {})
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def test_doc_updated_with_sanitized_value
|
278
|
+
s = Respect::HashSchema.define do |s|
|
279
|
+
s.integer "int", equal_to: 42
|
280
|
+
end
|
281
|
+
doc = { "int" => "42" }
|
282
|
+
assert_not_nil s.validate!(doc)
|
283
|
+
assert_equal 42, doc["int"]
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_doc_updated_with_custom_type_sanitized_value
|
287
|
+
s = Respect::HashSchema.define do |s|
|
288
|
+
s.circle "circle"
|
289
|
+
end
|
290
|
+
doc = { "circle" => { "center" => { "x" => "1.0", "y" => "2.0" }, "radius" => "5.5" } }
|
291
|
+
assert s.validate!(doc)
|
292
|
+
assert_equal Circle.new(Point.new(1.0, 2.0), 5.0), doc["circle"]
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_recursive_doc_updated_with_sanitized_value
|
296
|
+
s = Respect::HashSchema.define do |s|
|
297
|
+
s.integer "int", equal_to: 42
|
298
|
+
s.hash "obj" do |s|
|
299
|
+
s.integer "int", equal_to: 51
|
300
|
+
end
|
301
|
+
end
|
302
|
+
doc = { "int" => "42", "obj" => { "int" => "51" } }
|
303
|
+
assert_not_nil s.validate!(doc)
|
304
|
+
assert_equal({ "int" => 42, "obj" => { "int" => 51 } }, doc)
|
305
|
+
end
|
306
|
+
|
307
|
+
def test_only_update_validated_properties
|
308
|
+
s = Respect::HashSchema.define do |s|
|
309
|
+
s.integer "int", equal_to: 42
|
310
|
+
end
|
311
|
+
doc = { "int" => "42", "not_validated" => "51" }
|
312
|
+
assert_not_nil s.validate!(doc)
|
313
|
+
assert_equal({ "int" => 42, "not_validated" => "51" }, doc)
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_only_update_recursive_validated_properties
|
317
|
+
s = Respect::HashSchema.define do |s|
|
318
|
+
s.hash "obj" do |s|
|
319
|
+
s.integer "int", equal_to: 42
|
320
|
+
end
|
321
|
+
end
|
322
|
+
doc = { "obj" => { "int" => "42", "not_validated" => "51" } }
|
323
|
+
assert_not_nil s.validate!(doc)
|
324
|
+
assert_equal({ "obj" => { "int" => 42, "not_validated" => "51" } }, doc)
|
325
|
+
end
|
326
|
+
|
327
|
+
def test_sanitize_simple_document
|
328
|
+
s = Respect::HashSchema.define do |s|
|
329
|
+
s.integer "id", equal_to: 42
|
330
|
+
end
|
331
|
+
doc = { "id" => "42" }
|
332
|
+
assert_nil s.sanitized_object
|
333
|
+
s.validate(doc)
|
334
|
+
assert_equal({ "id" => "42" }, doc)
|
335
|
+
assert_equal({ "id" => 42 }, s.sanitized_object)
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_sanitize_recursive_document
|
339
|
+
s = Respect::HashSchema.define do |s|
|
340
|
+
s.integer "id", equal_to: 42
|
341
|
+
s.hash "obj" do |s|
|
342
|
+
s.integer "id", equal_to: 51
|
343
|
+
end
|
344
|
+
end
|
345
|
+
doc = { "id" => "42", "obj" => { "id" => "51" } }
|
346
|
+
assert_nil s.sanitized_object
|
347
|
+
s.validate(doc)
|
348
|
+
assert_equal({ "id" => "42", "obj" => { "id" => "51" } }, doc)
|
349
|
+
assert_equal({ "id" => 42, "obj" => { "id" => 51 } }, s.sanitized_object)
|
350
|
+
end
|
351
|
+
|
352
|
+
def test_do_not_sanitize_unvalidated_optional_property
|
353
|
+
s = Respect::HashSchema.define do |s|
|
354
|
+
s.integer "id1", equal_to: 42
|
355
|
+
s.integer "id2", equal_to: 51, required: false
|
356
|
+
end
|
357
|
+
doc = { "id1" => "42" }
|
358
|
+
assert_nil s.sanitized_object
|
359
|
+
s.validate(doc)
|
360
|
+
assert_equal({ "id1" => "42" }, doc)
|
361
|
+
assert_equal({ "id1" => 42 }, s.sanitized_object)
|
362
|
+
end
|
363
|
+
|
364
|
+
def test_hash_schema_merge_default_options
|
365
|
+
s = Respect::HashSchema.new
|
366
|
+
assert_equal true, s.options[:required]
|
367
|
+
assert_equal false, s.options[:strict]
|
368
|
+
end
|
369
|
+
|
370
|
+
def test_hash_schema_merge_options
|
371
|
+
s = Respect::HashSchema.new(opt: 1, strict: true)
|
372
|
+
assert_equal true, s.options[:required]
|
373
|
+
assert_equal true, s.options[:strict]
|
374
|
+
assert_equal 1, s.options[:opt]
|
375
|
+
end
|
376
|
+
|
377
|
+
def test_non_default_options
|
378
|
+
s = Respect::HashSchema.new(opt: 1, strict: true)
|
379
|
+
opts = s.non_default_options
|
380
|
+
assert !opts.has_key?(:required)
|
381
|
+
assert_equal true, opts[:strict]
|
382
|
+
assert_equal 1, opts[:opt]
|
383
|
+
end
|
384
|
+
|
385
|
+
def test_has_property
|
386
|
+
s1 = Respect::HashSchema.define do |s|
|
387
|
+
s.integer "s11"
|
388
|
+
end
|
389
|
+
assert s1.has_property?("s11")
|
390
|
+
assert !s1.has_property?("not a property")
|
391
|
+
end
|
392
|
+
|
393
|
+
def test_merge_hash_schema_in_place
|
394
|
+
s1 = Respect::HashSchema.define opt0: false, opt1: false do |s|
|
395
|
+
s.integer "s11"
|
396
|
+
s.integer "s12"
|
397
|
+
end
|
398
|
+
s2 = Respect::HashSchema.define opt1: true, opt2: true do |s|
|
399
|
+
s.integer "s21"
|
400
|
+
s.integer "s22"
|
401
|
+
end
|
402
|
+
s1.merge!(s2)
|
403
|
+
%w(s11 s12 s21 s22).each do |prop|
|
404
|
+
assert s1.has_property?(prop), "has prop #{prop}"
|
405
|
+
end
|
406
|
+
assert_equal false, s1.options[:opt0]
|
407
|
+
assert_equal true, s1.options[:opt1]
|
408
|
+
assert_equal true, s1.options[:opt2]
|
409
|
+
end
|
410
|
+
|
411
|
+
def test_merge_hash_schema
|
412
|
+
s1 = Respect::HashSchema.define do |s|
|
413
|
+
s.integer "s11"
|
414
|
+
s.integer "s12"
|
415
|
+
end
|
416
|
+
s2 = Respect::HashSchema.define do |s|
|
417
|
+
s.integer "s21"
|
418
|
+
s.integer "s22"
|
419
|
+
end
|
420
|
+
s3 = s1.merge(s2)
|
421
|
+
assert(s3.object_id != s1.object_id)
|
422
|
+
assert_equal 2, s1.properties.size
|
423
|
+
assert_equal 2, s2.properties.size
|
424
|
+
assert_equal 4, s3.properties.size
|
425
|
+
%w(s11 s12 s21 s22).each do |prop|
|
426
|
+
assert s3.has_property?(prop), "has prop #{prop}"
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_merge_uses_merge_shebang_on_duplicata
|
431
|
+
s1 = Respect::HashSchema.new
|
432
|
+
s2 = Respect::HashSchema.new
|
433
|
+
result = Respect::HashSchema.new
|
434
|
+
dup_s1 = Respect::HashSchema.new
|
435
|
+
s1.stubs(:dup).returns(dup_s1).once
|
436
|
+
dup_s1.stubs(:merge!).with(s2).returns(result).once
|
437
|
+
assert_equal result, s1.merge(s2)
|
438
|
+
end
|
439
|
+
|
440
|
+
def test_dup_duplicate_properties_and_options
|
441
|
+
s1 = Respect::HashSchema.define strict: true do |s|
|
442
|
+
s.integer "s11"
|
443
|
+
end
|
444
|
+
s2 = s1.dup
|
445
|
+
assert(s2.object_id != s1.object_id)
|
446
|
+
assert(s1.properties.object_id != s2.properties.object_id)
|
447
|
+
assert(s2.has_property?("s11"))
|
448
|
+
assert_equal(true, s2.options[:strict])
|
449
|
+
assert(s1["s11"].object_id == s2["s11"].object_id)
|
450
|
+
end
|
451
|
+
|
452
|
+
def test_eval_add_more_properties
|
453
|
+
s1 = Respect::HashSchema.define do |s|
|
454
|
+
s.integer "s11"
|
455
|
+
end
|
456
|
+
assert s1.has_property?("s11")
|
457
|
+
assert !s1.has_property?("new_prop")
|
458
|
+
s1.eval do |s|
|
459
|
+
s.integer "new_prop"
|
460
|
+
end
|
461
|
+
assert s1.has_property?("s11")
|
462
|
+
assert s1.has_property?("new_prop")
|
463
|
+
end
|
464
|
+
|
465
|
+
def test_documented_properties
|
466
|
+
s = Respect::HashSchema.define do |s|
|
467
|
+
s.integer "documented"
|
468
|
+
s.integer "documented_with_text", doc: "a title"
|
469
|
+
s.integer "nodoc", doc: false
|
470
|
+
end
|
471
|
+
e = %w(documented documented_with_text).sort
|
472
|
+
assert_equal e, s.documented_properties.keys.sort
|
473
|
+
end
|
474
|
+
|
475
|
+
def test_duplicata_are_equal
|
476
|
+
s1 = Respect::HashSchema.define do |s|
|
477
|
+
s.integer "i"
|
478
|
+
end
|
479
|
+
assert_equal s1, s1.dup
|
480
|
+
end
|
481
|
+
|
482
|
+
def test_schema_differs_from_options
|
483
|
+
s1 = Respect::HashSchema.new(required: true)
|
484
|
+
s2 = Respect::HashSchema.new(required: false)
|
485
|
+
assert(s1 != s2)
|
486
|
+
end
|
487
|
+
|
488
|
+
def test_schema_differs_from_doc
|
489
|
+
s1 = Respect::Schema.define do |s|
|
490
|
+
s.doc "hey"
|
491
|
+
s.hash
|
492
|
+
end
|
493
|
+
s2 = Respect::Schema.define do |s|
|
494
|
+
s.doc "ho"
|
495
|
+
s.hash
|
496
|
+
end
|
497
|
+
assert(s1 != s2)
|
498
|
+
end
|
499
|
+
|
500
|
+
def test_schema_differs_from_properties
|
501
|
+
s1 = Respect::HashSchema.new
|
502
|
+
s1["i1"] = Respect::IntegerSchema.new
|
503
|
+
s2 = Respect::HashSchema.new
|
504
|
+
s2["i2"] = Respect::IntegerSchema.new
|
505
|
+
assert(s1 != s2)
|
506
|
+
end
|
507
|
+
|
508
|
+
def test_indifferent_access_to_doc_key
|
509
|
+
s = Respect::HashSchema.define do |s|
|
510
|
+
s.integer "i", equal_to: 42
|
511
|
+
end
|
512
|
+
assert_schema_validate(s, { i: "42" })
|
513
|
+
assert_schema_validate(s, { "i" => "42" })
|
514
|
+
assert_schema_invalidate(s, { })
|
515
|
+
end
|
516
|
+
|
517
|
+
def test_doc_sanitized_in_place_keep_original_access
|
518
|
+
s = Respect::HashSchema.define do |s|
|
519
|
+
s.integer "i_string", equal_to: 42
|
520
|
+
s.integer :i_symbol, equal_to: 51
|
521
|
+
end
|
522
|
+
|
523
|
+
doc = { i_string: "42", "i_symbol" => "51" }
|
524
|
+
assert_schema_validate(s, doc)
|
525
|
+
assert !doc.is_a?(HashWithIndifferentAccess)
|
526
|
+
assert_equal(42, s.sanitized_object[:i_string])
|
527
|
+
assert_equal(42, s.sanitized_object["i_string"])
|
528
|
+
assert_equal(51, s.sanitized_object[:i_symbol])
|
529
|
+
assert_equal(51, s.sanitized_object["i_symbol"])
|
530
|
+
|
531
|
+
assert s.sanitized_object.is_a?(HashWithIndifferentAccess)
|
532
|
+
assert_equal({ "i_string" => 42, "i_symbol" => 51 }, s.sanitized_object)
|
533
|
+
|
534
|
+
s.sanitize_object!(doc)
|
535
|
+
assert_equal({ i_string: 42, "i_symbol" => 51 }, doc)
|
536
|
+
end
|
537
|
+
|
538
|
+
def test_indifferent_access_to_doc_nil_values
|
539
|
+
s = Respect::HashSchema.define do |s|
|
540
|
+
s.null "n"
|
541
|
+
end
|
542
|
+
assert_schema_validate(s, { n: nil })
|
543
|
+
assert_schema_validate(s, { "n" => nil })
|
544
|
+
assert_schema_invalidate(s, { })
|
545
|
+
end
|
546
|
+
|
547
|
+
def test_indifferent_access_to_doc_false_values
|
548
|
+
s = Respect::HashSchema.define do |s|
|
549
|
+
s.boolean "b", equal_to: false
|
550
|
+
end
|
551
|
+
assert_schema_validate(s, { b: false })
|
552
|
+
assert_schema_validate(s, { "b" => false })
|
553
|
+
assert_schema_invalidate(s, { })
|
554
|
+
end
|
555
|
+
|
556
|
+
def test_sanitized_object_only_include_validated_keys
|
557
|
+
s = Respect::HashSchema.define do |s|
|
558
|
+
s.integer "i"
|
559
|
+
end
|
560
|
+
assert_schema_validate(s, { i: "42", foo: "bar" })
|
561
|
+
assert_equal({ "i" => 42 }, s.sanitized_object)
|
562
|
+
end
|
563
|
+
|
564
|
+
def test_sanitized_object_include_optional_keys_when_present
|
565
|
+
s = Respect::HashSchema.define do |s|
|
566
|
+
s.integer "i", required: false
|
567
|
+
end
|
568
|
+
assert_schema_validate(s, { i: "42", foo: "bar" })
|
569
|
+
assert_equal({ "i" => 42 }, s.sanitized_object)
|
570
|
+
assert_schema_validate(s, { foo: "bar" })
|
571
|
+
assert_equal({ }, s.sanitized_object)
|
572
|
+
end
|
573
|
+
|
574
|
+
def test_failed_validation_reset_sanitized_object
|
575
|
+
s = Respect::HashSchema.define do |s|
|
576
|
+
s.integer "i", equal_to: 42
|
577
|
+
end
|
578
|
+
assert_schema_validate(s, {i: 42})
|
579
|
+
assert_equal({"i" => 42}, s.sanitized_object)
|
580
|
+
assert_schema_invalidate(s, {i: 51})
|
581
|
+
assert_equal(nil, s.sanitized_object)
|
582
|
+
end
|
583
|
+
|
584
|
+
def test_integer_property_accept_nil
|
585
|
+
s = Respect::HashSchema.define do |s|
|
586
|
+
s.integer "i", allow_nil: true
|
587
|
+
end
|
588
|
+
assert_schema_validate(s, { i: nil })
|
589
|
+
assert_equal({ "i" => nil }, s.sanitized_object)
|
590
|
+
assert_schema_validate(s, { i: 42 })
|
591
|
+
assert_equal({ "i" => 42 }, s.sanitized_object)
|
592
|
+
assert_schema_invalidate(s, { i: "wrong" })
|
593
|
+
assert_equal(nil, s.sanitized_object)
|
594
|
+
end
|
595
|
+
|
596
|
+
def test_allow_nil
|
597
|
+
s = Respect::HashSchema.new(allow_nil: true)
|
598
|
+
assert_schema_validate s, nil
|
599
|
+
assert_equal(nil, s.sanitized_object)
|
600
|
+
assert_schema_validate s, {}
|
601
|
+
assert_equal({}, s.sanitized_object)
|
602
|
+
end
|
603
|
+
|
604
|
+
def test_disallow_nil
|
605
|
+
s = Respect::HashSchema.new
|
606
|
+
assert !s.allow_nil?
|
607
|
+
exception = assert_exception(Respect::ValidationError) { s.validate(nil) }
|
608
|
+
assert_match exception.message, /\bHashSchema\b/
|
609
|
+
assert_equal(nil, s.sanitized_object)
|
610
|
+
assert_schema_validate s, {}
|
611
|
+
assert_equal({}, s.sanitized_object)
|
612
|
+
end
|
613
|
+
end
|