respect 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +289 -0
  3. data/RELATED_WORK.md +40 -0
  4. data/RELEASE_NOTES.md +23 -0
  5. data/Rakefile +31 -0
  6. data/STATUS_MATRIX.html +137 -0
  7. data/lib/respect.rb +231 -0
  8. data/lib/respect/any_schema.rb +22 -0
  9. data/lib/respect/array_def.rb +28 -0
  10. data/lib/respect/array_schema.rb +203 -0
  11. data/lib/respect/boolean_schema.rb +32 -0
  12. data/lib/respect/composite_schema.rb +86 -0
  13. data/lib/respect/core_statements.rb +206 -0
  14. data/lib/respect/datetime_schema.rb +27 -0
  15. data/lib/respect/def_without_name.rb +6 -0
  16. data/lib/respect/divisible_by_validator.rb +20 -0
  17. data/lib/respect/doc_helper.rb +24 -0
  18. data/lib/respect/doc_parser.rb +37 -0
  19. data/lib/respect/dsl_dumper.rb +181 -0
  20. data/lib/respect/equal_to_validator.rb +20 -0
  21. data/lib/respect/fake_name_proxy.rb +116 -0
  22. data/lib/respect/float_schema.rb +27 -0
  23. data/lib/respect/format_validator.rb +136 -0
  24. data/lib/respect/global_def.rb +79 -0
  25. data/lib/respect/greater_than_or_equal_to_validator.rb +19 -0
  26. data/lib/respect/greater_than_validator.rb +19 -0
  27. data/lib/respect/has_constraints.rb +34 -0
  28. data/lib/respect/hash_def.rb +40 -0
  29. data/lib/respect/hash_schema.rb +218 -0
  30. data/lib/respect/in_validator.rb +19 -0
  31. data/lib/respect/integer_schema.rb +27 -0
  32. data/lib/respect/ip_addr_schema.rb +23 -0
  33. data/lib/respect/ipv4_addr_schema.rb +27 -0
  34. data/lib/respect/ipv6_addr_schema.rb +27 -0
  35. data/lib/respect/items_def.rb +21 -0
  36. data/lib/respect/json_schema_html_formatter.rb +143 -0
  37. data/lib/respect/less_than_or_equal_to_validator.rb +19 -0
  38. data/lib/respect/less_than_validator.rb +19 -0
  39. data/lib/respect/match_validator.rb +19 -0
  40. data/lib/respect/max_length_validator.rb +20 -0
  41. data/lib/respect/min_length_validator.rb +20 -0
  42. data/lib/respect/multiple_of_validator.rb +10 -0
  43. data/lib/respect/null_schema.rb +26 -0
  44. data/lib/respect/numeric_schema.rb +33 -0
  45. data/lib/respect/org3_dumper.rb +213 -0
  46. data/lib/respect/regexp_schema.rb +19 -0
  47. data/lib/respect/schema.rb +285 -0
  48. data/lib/respect/schema_def.rb +16 -0
  49. data/lib/respect/string_schema.rb +21 -0
  50. data/lib/respect/unit_test_helper.rb +37 -0
  51. data/lib/respect/uri_schema.rb +23 -0
  52. data/lib/respect/utc_time_schema.rb +17 -0
  53. data/lib/respect/validator.rb +51 -0
  54. data/lib/respect/version.rb +3 -0
  55. data/test/any_schema_test.rb +79 -0
  56. data/test/array_def_test.rb +113 -0
  57. data/test/array_schema_test.rb +487 -0
  58. data/test/boolean_schema_test.rb +89 -0
  59. data/test/composite_schema_test.rb +30 -0
  60. data/test/datetime_schema_test.rb +83 -0
  61. data/test/doc_helper_test.rb +34 -0
  62. data/test/doc_parser_test.rb +109 -0
  63. data/test/dsl_dumper_test.rb +395 -0
  64. data/test/fake_name_proxy_test.rb +138 -0
  65. data/test/float_schema_test.rb +146 -0
  66. data/test/format_validator_test.rb +224 -0
  67. data/test/hash_def_test.rb +126 -0
  68. data/test/hash_schema_test.rb +613 -0
  69. data/test/integer_schema_test.rb +142 -0
  70. data/test/ip_addr_schema_test.rb +78 -0
  71. data/test/ipv4_addr_schema_test.rb +71 -0
  72. data/test/ipv6_addr_schema_test.rb +71 -0
  73. data/test/json_schema_html_formatter_test.rb +214 -0
  74. data/test/null_schema_test.rb +46 -0
  75. data/test/numeric_schema_test.rb +294 -0
  76. data/test/org3_dumper_test.rb +784 -0
  77. data/test/regexp_schema_test.rb +54 -0
  78. data/test/respect_test.rb +108 -0
  79. data/test/schema_def_test.rb +405 -0
  80. data/test/schema_test.rb +290 -0
  81. data/test/string_schema_test.rb +209 -0
  82. data/test/support/circle.rb +11 -0
  83. data/test/support/color.rb +24 -0
  84. data/test/support/point.rb +11 -0
  85. data/test/support/respect/circle_schema.rb +16 -0
  86. data/test/support/respect/color_def.rb +19 -0
  87. data/test/support/respect/color_schema.rb +33 -0
  88. data/test/support/respect/point_schema.rb +19 -0
  89. data/test/support/respect/rgba_schema.rb +20 -0
  90. data/test/support/respect/universal_validator.rb +25 -0
  91. data/test/support/respect/user_macros.rb +12 -0
  92. data/test/support/rgba.rb +11 -0
  93. data/test/test_helper.rb +90 -0
  94. data/test/uri_schema_test.rb +54 -0
  95. data/test/utc_time_schema_test.rb +63 -0
  96. data/test/validator_test.rb +22 -0
  97. metadata +288 -0
@@ -0,0 +1,46 @@
1
+ require "test_helper"
2
+
3
+ class NullSchemaTest < Test::Unit::TestCase
4
+ def test_null_schema_validate_format
5
+ # Malformed document.
6
+ [
7
+ [ "42", false, "integer in string" ],
8
+ [ { "test" => 42 }, false, "hash" ],
9
+ [ "true", false, "true in string" ],
10
+ [ "false", false, "false in string" ],
11
+ [ "string", false, "string" ],
12
+ [ "nil", false, "nil in string" ],
13
+ [ nil, true, "nil" ],
14
+ [ "null", true, "null in string" ],
15
+ ].each do |data|
16
+ s = Respect::NullSchema.new
17
+ assert_nil s.sanitized_object
18
+ validated = s.validate?(data[0])
19
+ assert_equal data[1], validated, data[2]
20
+ if validated
21
+ assert_nil s.sanitized_object, data[2]
22
+ end
23
+ end
24
+ end
25
+
26
+ def test_failed_validation_reset_sanitized_object
27
+ s = Respect::NullSchema.new
28
+ assert_schema_validate(s, nil)
29
+ assert_equal(nil, s.sanitized_object)
30
+ assert_schema_invalidate(s, 42)
31
+ assert_equal(nil, s.sanitized_object)
32
+ end
33
+
34
+ def test_allow_nil
35
+ s = Respect::NullSchema.new(allow_nil: true)
36
+ assert_schema_validate s, nil
37
+ assert_equal(nil, s.sanitized_object)
38
+ end
39
+
40
+ def test_disallow_nil
41
+ s = Respect::NullSchema.new
42
+ assert !s.allow_nil?
43
+ assert_schema_validate s, nil
44
+ assert_equal(nil, s.sanitized_object)
45
+ end
46
+ end
@@ -0,0 +1,294 @@
1
+ require "test_helper"
2
+
3
+ class NumericSchemaTest < Test::Unit::TestCase
4
+ def test_expected_value_are_not_converted
5
+ s = Respect::NumericSchema.new(equal_to: "42.5")
6
+ assert_raise(Respect::ValidationError) do
7
+ s.validate(42.5)
8
+ end
9
+ s = Respect::NumericSchema.new(equal_to: "42")
10
+ assert_raise(Respect::ValidationError) do
11
+ s.validate(42)
12
+ end
13
+ end
14
+
15
+ def test_malformed_string_value_raise_exception
16
+ s = Respect::NumericSchema.new
17
+ [
18
+ "s42.5",
19
+ "4s2.5",
20
+ "42.5s",
21
+ "4-2.5",
22
+ "42.5-",
23
+ "-+42.5",
24
+ "+-42.5",
25
+ "s42",
26
+ "4s2",
27
+ "42s",
28
+ "4-2",
29
+ "42-",
30
+ "-+42",
31
+ "+-42",
32
+ ].each do |test_value|
33
+ assert_schema_invalidate s, test_value, "#{test_value} is invalid"
34
+ end
35
+ end
36
+
37
+ def test_string_value_get_converted
38
+ [
39
+ [ "-42.5", -42.5 ],
40
+ [ "+42.54", 42.54 ],
41
+ [ "42.123", 42.123 ],
42
+ [ "-42", -42 ],
43
+ [ "+42", 42 ],
44
+ [ "42", 42 ],
45
+ ].each do |test_data|
46
+ s = Respect::NumericSchema.new
47
+ assert_equal test_data[1], s.validate_type(test_data[0])
48
+ assert_nil s.sanitized_object
49
+ s.validate(test_data[0])
50
+ assert_equal test_data[1], s.sanitized_object
51
+ end
52
+ end
53
+
54
+ def test_greater_than_constraint_works
55
+ s = Respect::NumericSchema.new(greater_than: 0)
56
+ assert s.validate(42.5)
57
+ assert s.validate(42)
58
+ [ 0, -42, 0.0, -42.5 ].each do |test_value|
59
+ assert_raise(Respect::ValidationError) do
60
+ s.validate(test_value)
61
+ end
62
+ end
63
+ end
64
+
65
+ def test_greater_than_or_equal_to_constraint_works
66
+ s = Respect::NumericSchema.new(greater_than_or_equal_to: 0)
67
+ assert s.validate(42.5)
68
+ assert s.validate(0.0)
69
+ assert s.validate(42)
70
+ assert s.validate(0)
71
+ [ -42, -42.5 ].each do |test_value|
72
+ assert_raise(Respect::ValidationError) do
73
+ s.validate(test_value)
74
+ end
75
+ end
76
+ end
77
+
78
+ def test_less_than_constraint_works
79
+ s = Respect::NumericSchema.new(less_than: 0)
80
+ assert s.validate(-1.5)
81
+ assert s.validate(-1)
82
+ [ 0.0, 1.5, 0, 1 ].each do |test_value|
83
+ assert_raise(Respect::ValidationError) do
84
+ s.validate(test_value)
85
+ end
86
+ end
87
+ end
88
+
89
+ def test_less_than_or_equal_to_constraint_works
90
+ s = Respect::NumericSchema.new(less_than_or_equal_to: 0)
91
+ assert s.validate(-1.5)
92
+ assert s.validate(0.0)
93
+ assert s.validate(-1)
94
+ assert s.validate(0)
95
+ [ 1.5, 1 ].each do |test_value|
96
+ assert_raise(Respect::ValidationError) do
97
+ s.validate(test_value)
98
+ end
99
+ end
100
+ end
101
+
102
+ def test_schema_definition_accept_numeric
103
+ s = Respect::Schema.define do |s|
104
+ s.numeric equal_to: 1.5
105
+ end
106
+ assert_schema_validate s, "1.5"
107
+ assert_schema_validate s, 1.5
108
+
109
+ s = Respect::Schema.define do |s|
110
+ s.numeric equal_to: 1
111
+ end
112
+ assert_schema_validate s, "1"
113
+ assert_schema_validate s, 1
114
+ end
115
+
116
+ def test_schema_definition_accept_numeric_with_no_option
117
+ s = Respect::Schema.define do |s|
118
+ s.numeric
119
+ end
120
+ assert_schema_validate s, 42
121
+ assert_schema_validate s, 42.5
122
+ end
123
+
124
+ def test_hash_schema_definition_accept_numeric
125
+ s = Respect::HashSchema.define do |s|
126
+ s.numeric "test", equal_to: 1.5
127
+ s.extra do |s|
128
+ s.numeric "opt", equal_to: 4
129
+ end
130
+ end
131
+ assert_schema_validate s, { "test" => "1.5", "opt" => "4" }
132
+ assert_schema_validate s, { "test" => 1.5, "opt" => 4 }
133
+ end
134
+
135
+ def test_array_schema_definition_accept_numeric
136
+ s = Respect::ArraySchema.define do |s|
137
+ s.numeric equal_to: 1.5
138
+ end
139
+ assert_schema_validate s, ["1.5"]
140
+ assert_schema_validate s, [1.5]
141
+
142
+ s = Respect::ArraySchema.define do |s|
143
+ s.numeric equal_to: 1
144
+ end
145
+ assert_schema_validate s, ["1"]
146
+ assert_schema_validate s, [1]
147
+ end
148
+
149
+ def test_numeric_is_in_set
150
+ s = Respect::NumericSchema.new(in: [42.5, 51.5, 42, 51])
151
+ assert_schema_validate s, 42.5
152
+ assert_schema_validate s, 51.5
153
+ assert_schema_validate s, 42
154
+ assert_schema_validate s, 51
155
+ assert_schema_invalidate s, 1664.5
156
+ assert_schema_invalidate s, 1664
157
+ end
158
+
159
+ def test_numeric_value_is_in_range
160
+ s = Respect::NumericSchema.new(in: 1.5..4.5)
161
+ assert_schema_invalidate s, 0.0
162
+ assert_schema_invalidate s, 1.4
163
+ assert_schema_validate s, 1.5
164
+ assert_schema_validate s, 2.0
165
+ assert_schema_validate s, 3.0
166
+ assert_schema_validate s, 4.0
167
+ assert_schema_validate s, 4.5
168
+ assert_schema_invalidate s, 4.6
169
+ assert_schema_invalidate s, 5.0
170
+
171
+ s = Respect::NumericSchema.new(in: 1.5...4.5)
172
+ assert_schema_invalidate s, 0.0
173
+ assert_schema_invalidate s, 1.4
174
+ assert_schema_validate s, 1.5
175
+ assert_schema_validate s, 2.0
176
+ assert_schema_validate s, 3.0
177
+ assert_schema_validate s, 4.0
178
+ assert_schema_invalidate s, 4.5
179
+ assert_schema_invalidate s, 4.6
180
+ assert_schema_invalidate s, 5.0
181
+
182
+ s = Respect::NumericSchema.new(in: 1..4)
183
+ assert_schema_invalidate s, 0
184
+ assert_schema_validate s, 1
185
+ assert_schema_validate s, 2
186
+ assert_schema_validate s, 3
187
+ assert_schema_validate s, 4
188
+ assert_schema_invalidate s, 5
189
+
190
+ s = Respect::NumericSchema.new(in: 1...4)
191
+ assert_schema_invalidate s, 0
192
+ assert_schema_validate s, 1
193
+ assert_schema_validate s, 2
194
+ assert_schema_validate s, 3
195
+ assert_schema_invalidate s, 4
196
+ assert_schema_invalidate s, 5
197
+ end
198
+
199
+ def test_numeric_accept_equal_to_constraint
200
+ s = Respect::NumericSchema.new(equal_to: 41)
201
+ assert_schema_validate s, 41
202
+ assert_schema_validate s, 41.0
203
+ assert_schema_validate s, "41"
204
+ assert_schema_validate s, "41.0"
205
+ assert_schema_invalidate s, 41.55
206
+ assert_schema_invalidate s, 42
207
+ end
208
+
209
+ def test_divisible_by_and_multiple_of_option_works
210
+ [ :divisible_by, :multiple_of ].each do |opt|
211
+ # Works with integer
212
+ s = Respect::NumericSchema.new(opt => 2)
213
+ assert_schema_validate s, 4, "validate #{opt}"
214
+ assert_schema_validate s, 2, "validate #{opt}"
215
+ assert_schema_invalidate s, 1, "invalidate #{opt}"
216
+ assert_schema_invalidate s, 3, "invalidate #{opt}"
217
+ # Works with float
218
+ s = Respect::NumericSchema.new(opt => 2.1)
219
+ assert_schema_validate s, 4.2, "validate #{opt}"
220
+ assert_schema_validate s, 2.1, "validate #{opt}"
221
+ assert_schema_invalidate s, 1.4, "invalidate #{opt}"
222
+ assert_schema_invalidate s, 3.4, "invalidate #{opt}"
223
+ end
224
+ end
225
+
226
+ def test_divisible_by_option_mention_operands_in_error
227
+ begin
228
+ Respect::NumericSchema.new(divisible_by: 2).validate(3)
229
+ assert false
230
+ rescue Respect::ValidationError => e
231
+ assert_match(/\b3\b/, e.message)
232
+ assert_match(/\b2\b/, e.message)
233
+ assert_match(/\bdivisible by\b/, e.message)
234
+ end
235
+ end
236
+
237
+ def test_multiple_of_option_mention_operands_in_error
238
+ begin
239
+ Respect::NumericSchema.new(multiple_of: 2).validate(3)
240
+ assert false
241
+ rescue Respect::ValidationError => e
242
+ assert_match(/\b3\b/, e.message)
243
+ assert_match(/\b2\b/, e.message)
244
+ assert_match(/\ba multiple of\b/, e.message)
245
+ end
246
+ end
247
+
248
+ def test_failed_validation_reset_sanitized_object
249
+ s = Respect::NumericSchema.new equal_to: 42
250
+ assert_schema_validate(s, 42)
251
+ assert_equal(42, s.sanitized_object)
252
+ assert_schema_invalidate(s, "wrong")
253
+ assert_equal(nil, s.sanitized_object)
254
+ end
255
+
256
+ def test_allow_nil
257
+ s = Respect::NumericSchema.new(allow_nil: true)
258
+ assert_schema_validate s, nil
259
+ assert_equal(nil, s.sanitized_object)
260
+ assert_schema_validate s, 42
261
+ assert_equal(42, s.sanitized_object)
262
+ assert_schema_validate s, "42"
263
+ assert_equal(42, s.sanitized_object)
264
+ end
265
+
266
+ def test_disallow_nil
267
+ s = Respect::NumericSchema.new
268
+ assert !s.allow_nil?
269
+ exception = assert_exception(Respect::ValidationError) { s.validate(nil) }
270
+ assert_match exception.message, /\bNumericSchema\b/
271
+ assert_equal(nil, s.sanitized_object)
272
+ assert_schema_validate s, 42
273
+ assert_equal(42, s.sanitized_object)
274
+ assert_schema_validate s, "42"
275
+ assert_equal(42, s.sanitized_object)
276
+ end
277
+
278
+ def test_allow_nil_with_constraint
279
+ s = Respect::NumericSchema.new(allow_nil: true, equal_to: 42)
280
+ assert_schema_validate s, nil
281
+ assert_equal(nil, s.sanitized_object)
282
+ assert_schema_validate s, 42
283
+ assert_equal(42, s.sanitized_object)
284
+ assert_schema_invalidate s, 51
285
+ assert_equal(nil, s.sanitized_object)
286
+ assert_schema_validate s, "42"
287
+ assert_equal(42, s.sanitized_object)
288
+ end
289
+
290
+ def test_allow_nil_with_wrong_constraint_still_invalidate
291
+ s = Respect::NumericSchema.new(allow_nil: true, equal_to: "42")
292
+ assert_schema_invalidate s, "42"
293
+ end
294
+ end
@@ -0,0 +1,784 @@
1
+ require "test_helper"
2
+
3
+ class Org3DumperTest < Test::Unit::TestCase
4
+ def test_dump_basic_types_statements_with_no_options
5
+ [
6
+ :integer,
7
+ :string,
8
+ :any,
9
+ :boolean,
10
+ :null,
11
+ ].each do |statement|
12
+ s = Respect::Schema.define do |s|
13
+ s.__send__(statement)
14
+ end
15
+ a = Respect::Org3Dumper.new(s).dump
16
+ e = {
17
+ "type" => statement.to_s,
18
+ }
19
+ assert_equal e, a, "dump statement #{statement}"
20
+ end
21
+ end
22
+
23
+ def test_numeric_and_float_schema_are_number_type
24
+ {
25
+ :NumericSchema => "number",
26
+ :FloatSchema => "number",
27
+ }.each do |schema_class, type|
28
+ s = Respect.const_get(schema_class).new
29
+ a = Respect::Org3Dumper.new(s).dump
30
+ e = { "type" => type }
31
+ assert_equal e, a, "dump schema #{schema_class}"
32
+ end
33
+ end
34
+
35
+ def test_dump_extended_simple_schema
36
+ {
37
+ :URISchema => "uri",
38
+ :RegexpSchema => "regex",
39
+ :DatetimeSchema => "date-time",
40
+ :Ipv4AddrSchema => "ip-address",
41
+ :Ipv6AddrSchema => "ipv6",
42
+ }.each do |schema_class, format|
43
+ s = Respect.const_get(schema_class).new
44
+ a = Respect::Org3Dumper.new(s).dump
45
+ e = { "type" => "string", "format" => format}
46
+ assert_equal e, a, "dump schema #{schema_class}"
47
+ end
48
+ end
49
+
50
+ # TODO(Nicolas Despres): Test IPAddrSchema warn that it can not be dumped.
51
+ # TODO(Nicolas Despres): Test UTCTimeSchema warn that it can not be dumped.
52
+
53
+ def test_dump_helper_statement
54
+ {
55
+ :phone_number => "phone",
56
+ :hostname => "host-name",
57
+ :email => "email",
58
+ }.each do |statement, format|
59
+ s = Respect::Schema.define do |s|
60
+ s.__send__(statement)
61
+ end
62
+ a = Respect::Org3Dumper.new(s).dump
63
+ e = {
64
+ "type" => "string",
65
+ "format" => format,
66
+ }
67
+ assert_equal e, a, "dump statement #{statement}"
68
+ end
69
+ end
70
+
71
+ def test_dump_hash_properties
72
+ s = Respect::HashSchema.define do |s|
73
+ s.integer "i"
74
+ s.string "s"
75
+ s.float "f"
76
+ end
77
+ a = Respect::Org3Dumper.new(s).dump
78
+ e = {
79
+ "type" => "object",
80
+ "properties" => {
81
+ "i" => {
82
+ "type" => "integer",
83
+ "required" => true,
84
+ },
85
+ "s" => {
86
+ "type" => "string",
87
+ "required" => true,
88
+ },
89
+ "f" => {
90
+ "type" => "number",
91
+ "required" => true,
92
+ },
93
+ }
94
+ }
95
+ assert_equal e, a
96
+ end
97
+
98
+ def test_dump_hash_optional_properties
99
+ s = Respect::HashSchema.define do |s|
100
+ s.integer "i"
101
+ s.string "s"
102
+ s.extra do |s|
103
+ s.string "o_s"
104
+ s.float "o_f"
105
+ end
106
+ end
107
+ a = Respect::Org3Dumper.new(s).dump
108
+ e = {
109
+ "type" => "object",
110
+ "properties" => {
111
+ "i" => {
112
+ "type" => "integer",
113
+ "required" => true,
114
+ },
115
+ "s" => {
116
+ "type" => "string",
117
+ "required" => true,
118
+ },
119
+ },
120
+ "additionalProperties" => {
121
+ "o_s" => { "type" => "string" },
122
+ "o_f" => { "type" => "number" },
123
+ },
124
+ }
125
+ assert_equal e, a
126
+ end
127
+
128
+ def test_dump_hash_pattern_properties
129
+ s = Respect::HashSchema.define do |s|
130
+ s.integer "i"
131
+ s.string /s.*t/
132
+ end
133
+ a = Respect::Org3Dumper.new(s).dump
134
+ e = {
135
+ "type" => "object",
136
+ "properties" => {
137
+ "i" => {
138
+ "type" => "integer",
139
+ "required" => true,
140
+ },
141
+ },
142
+ "patternProperties" => {
143
+ "s.*t" => {
144
+ "type" => "string",
145
+ "required" => true,
146
+ },
147
+ },
148
+ }
149
+ assert_equal e, a
150
+ end
151
+
152
+ def test_dump_nested_hash
153
+ s = Respect::HashSchema.define do |s|
154
+ s.hash "o1" do |s|
155
+ s.hash "o2" do |s|
156
+ s.hash "o3" do |s|
157
+ s.integer "i"
158
+ end
159
+ end
160
+ end
161
+ end
162
+ a = Respect::Org3Dumper.new(s).dump
163
+ e = {
164
+ "type" => "object",
165
+ "properties" => {
166
+ "o1" => {
167
+ "type" => "object",
168
+ "required" => true,
169
+ "properties" => {
170
+ "o2" => {
171
+ "type" => "object",
172
+ "required" => true,
173
+ "properties" => {
174
+ "o3" => {
175
+ "type" => "object",
176
+ "required" => true,
177
+ "properties" => {
178
+ "i" => {
179
+ "type" => "integer",
180
+ "required" => true,
181
+ },
182
+ },
183
+ },
184
+ },
185
+ },
186
+ },
187
+ },
188
+ },
189
+ }
190
+ assert_equal e, a
191
+ end
192
+
193
+ def test_dump_nested_pattern_properties
194
+ s = Respect::HashSchema.define do |s|
195
+ s.hash /o1/ do |s|
196
+ s.hash /o2/ do |s|
197
+ s.hash /o3/ do |s|
198
+ s.integer "i"
199
+ end
200
+ end
201
+ end
202
+ end
203
+ a = Respect::Org3Dumper.new(s).dump
204
+ e = {
205
+ "type" => "object",
206
+ "patternProperties" => {
207
+ "o1" => {
208
+ "type" => "object",
209
+ "required" => true,
210
+ "patternProperties" => {
211
+ "o2" => {
212
+ "type" => "object",
213
+ "required" => true,
214
+ "patternProperties" => {
215
+ "o3" => {
216
+ "type" => "object",
217
+ "required" => true,
218
+ "properties" => {
219
+ "i" => {
220
+ "type" => "integer",
221
+ "required" => true,
222
+ },
223
+ },
224
+ },
225
+ },
226
+ },
227
+ },
228
+ },
229
+ },
230
+ }
231
+ assert_equal e, a
232
+ end
233
+
234
+ def test_dump_nested_extra_properties
235
+ s = Respect::HashSchema.define do |s|
236
+ s.extra do |s|
237
+ s.hash "o1" do |s|
238
+ s.extra do |s|
239
+ s.hash "o2" do |s|
240
+ s.extra do |s|
241
+ s.hash "o3" do |s|
242
+ s.integer "i"
243
+ end
244
+ end
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
250
+ a = Respect::Org3Dumper.new(s).dump
251
+ e = {
252
+ "type" => "object",
253
+ "additionalProperties" => {
254
+ "o1" => {
255
+ "type" => "object",
256
+ "additionalProperties" => {
257
+ "o2" => {
258
+ "type" => "object",
259
+ "additionalProperties" => {
260
+ "o3" => {
261
+ "type" => "object",
262
+ "properties" => {
263
+ "i" => {
264
+ "type" => "integer",
265
+ "required" => true,
266
+ },
267
+ },
268
+ },
269
+ },
270
+ },
271
+ },
272
+ },
273
+ },
274
+ }
275
+ assert_equal e, a
276
+ end
277
+
278
+ def test_do_not_dump_empty_hash_properties
279
+ s = Respect::HashSchema.define do |s|
280
+ end
281
+ a = Respect::Org3Dumper.new(s).dump
282
+ e = {
283
+ "type" => "object",
284
+ }
285
+ assert_equal e, a
286
+ end
287
+
288
+ def test_do_not_dump_empty_hash_optional_properties
289
+ s = Respect::HashSchema.define do |s|
290
+ s.extra do |s|
291
+ end
292
+ end
293
+ a = Respect::Org3Dumper.new(s).dump
294
+ e = {
295
+ "type" => "object",
296
+ }
297
+ assert_equal e, a
298
+ end
299
+
300
+ def test_dump_hash_in_strict_mode
301
+ s = Respect::HashSchema.define strict: true do |s|
302
+ s.integer "i"
303
+ s.string /s/
304
+ end
305
+ a = Respect::Org3Dumper.new(s).dump
306
+ e = {
307
+ "type" => "object",
308
+ "properties" => { "i" => { "type" => "integer", "required" => true } },
309
+ "patternProperties" => { "s" => { "type" => "string", "required" => true } },
310
+ "additionalProperties" => false,
311
+ }
312
+ assert_equal e, a
313
+ end
314
+
315
+ def test_do_not_dump_nodoc_hash_properties
316
+ s = Respect::HashSchema.define do |s|
317
+ s.integer "enabled"
318
+ s.integer "nodoc", doc: false
319
+ end
320
+ a = Respect::Org3Dumper.new(s).dump
321
+ e = {
322
+ "type" => "object",
323
+ "properties" => { "enabled" => { "type" => "integer", "required" => true } },
324
+ }
325
+ assert_equal e, a
326
+ end
327
+
328
+ def test_do_not_dump_nodoc_hash_optional_properties
329
+ s = Respect::HashSchema.define do |s|
330
+ s.extra do |s|
331
+ s.integer "enabled"
332
+ s.integer "nodoc", doc: false
333
+ end
334
+ end
335
+ a = Respect::Org3Dumper.new(s).dump
336
+ e = {
337
+ "type" => "object",
338
+ "additionalProperties" => { "enabled" => { "type" => "integer" } },
339
+ }
340
+ assert_equal e, a
341
+ end
342
+
343
+ def test_do_not_dump_nodoc_hash_pattern_properties
344
+ s = Respect::HashSchema.define do |s|
345
+ s.integer /enabled/
346
+ s.integer /nodoc/, doc: false
347
+ end
348
+ a = Respect::Org3Dumper.new(s).dump
349
+ e = {
350
+ "type" => "object",
351
+ "patternProperties" => { "enabled" => { "type" => "integer", "required" => true } },
352
+ }
353
+ assert_equal e, a
354
+ end
355
+
356
+ def test_dump_array_item
357
+ s = Respect::ArraySchema.define do |s|
358
+ s.integer
359
+ end
360
+ a = Respect::Org3Dumper.new(s).dump
361
+ e = {
362
+ "type" => "array",
363
+ "items" => {
364
+ "type" => "integer",
365
+ },
366
+ }
367
+ assert_equal e, a
368
+ end
369
+
370
+ def test_dump_array_items
371
+ s = Respect::ArraySchema.define do |s|
372
+ s.items do |s|
373
+ s.integer
374
+ s.string
375
+ s.float
376
+ end
377
+ end
378
+ a = Respect::Org3Dumper.new(s).dump
379
+ e = {
380
+ "type" => "array",
381
+ "items" => [
382
+ { "type" => "integer" },
383
+ { "type" => "string" },
384
+ { "type" => "number" },
385
+ ],
386
+ }
387
+ assert_equal e, a
388
+ end
389
+
390
+ def test_dump_array_items_and_extra_items
391
+ s = Respect::ArraySchema.define do |s|
392
+ s.items do |s|
393
+ s.integer
394
+ end
395
+ s.extra_items do |s|
396
+ s.string
397
+ s.float
398
+ end
399
+ end
400
+ a = Respect::Org3Dumper.new(s).dump
401
+ e = {
402
+ "type" => "array",
403
+ "items" => [
404
+ { "type" => "integer" },
405
+ ],
406
+ "additionalItems" => [
407
+ { "type" => "string" },
408
+ { "type" => "number" },
409
+ ],
410
+ }
411
+ assert_equal e, a
412
+ end
413
+
414
+ def test_dump_array_extra_items
415
+ s = Respect::ArraySchema.define do |s|
416
+ s.extra_items do |s|
417
+ s.string
418
+ s.float
419
+ end
420
+ end
421
+ a = Respect::Org3Dumper.new(s).dump
422
+ e = {
423
+ "type" => "array",
424
+ "additionalItems" => [
425
+ { "type" => "string" },
426
+ { "type" => "number" },
427
+ ],
428
+ }
429
+ assert_equal e, a
430
+ end
431
+
432
+ def test_dump_nested_array_item
433
+ s = Respect::ArraySchema.define do |s|
434
+ s.array do |s|
435
+ s.array do |s|
436
+ s.integer
437
+ end
438
+ end
439
+ end
440
+ a = Respect::Org3Dumper.new(s).dump
441
+ e = {
442
+ "type" => "array",
443
+ "items" => {
444
+ "type" => "array",
445
+ "items" => {
446
+ "type" => "array",
447
+ "items" => {
448
+ "type" => "integer",
449
+ },
450
+ },
451
+ },
452
+ }
453
+ assert_equal e, a
454
+ end
455
+
456
+ def test_dump_nested_array_items
457
+ s = Respect::ArraySchema.define do |s|
458
+ s.items do |s|
459
+ s.array do |s|
460
+ s.items do |s|
461
+ s.array do |s|
462
+ s.items do |s|
463
+ s.integer
464
+ s.string
465
+ end
466
+ end
467
+ s.integer
468
+ s.string
469
+ end
470
+ end
471
+ s.integer
472
+ s.string
473
+ s.float
474
+ end
475
+ end
476
+ a = Respect::Org3Dumper.new(s).dump
477
+ e = {
478
+ "type" => "array",
479
+ "items" => [
480
+ {
481
+ "type" => "array",
482
+ "items" => [
483
+ {
484
+ "type" => "array",
485
+ "items" => [
486
+ { "type" => "integer" },
487
+ { "type" => "string" },
488
+ ],
489
+ },
490
+ { "type" => "integer" },
491
+ { "type" => "string" },
492
+ ],
493
+ },
494
+ { "type" => "integer" },
495
+ { "type" => "string" },
496
+ { "type" => "number" },
497
+ ],
498
+ }
499
+ assert_equal e, a
500
+ end
501
+
502
+ def test_dump_nested_array_extra_items
503
+ s = Respect::ArraySchema.define do |s|
504
+ s.extra_items do |s|
505
+ s.array do |s|
506
+ s.extra_items do |s|
507
+ s.array do |s|
508
+ s.extra_items do |s|
509
+ s.integer
510
+ s.string
511
+ end
512
+ end
513
+ s.integer
514
+ s.string
515
+ end
516
+ end
517
+ s.integer
518
+ s.string
519
+ s.float
520
+ end
521
+ end
522
+ a = Respect::Org3Dumper.new(s).dump
523
+ e = {
524
+ "type" => "array",
525
+ "additionalItems" => [
526
+ {
527
+ "type" => "array",
528
+ "additionalItems" => [
529
+ {
530
+ "type" => "array",
531
+ "additionalItems" => [
532
+ { "type" => "integer" },
533
+ { "type" => "string" },
534
+ ],
535
+ },
536
+ { "type" => "integer" },
537
+ { "type" => "string" },
538
+ ],
539
+ },
540
+ { "type" => "integer" },
541
+ { "type" => "string" },
542
+ { "type" => "number" },
543
+ ],
544
+ }
545
+ assert_equal e, a
546
+ end
547
+
548
+ def test_do_not_dump_empty_array_item
549
+ s = Respect::ArraySchema.define do |s|
550
+ end
551
+ a = Respect::Org3Dumper.new(s).dump
552
+ e = {
553
+ "type" => "array",
554
+ }
555
+ assert_equal e, a
556
+ end
557
+
558
+ def test_do_not_dump_empty_array_items
559
+ s = Respect::ArraySchema.define do |s|
560
+ s.items do |s|
561
+ end
562
+ end
563
+ a = Respect::Org3Dumper.new(s).dump
564
+ e = {
565
+ "type" => "array",
566
+ }
567
+ assert_equal e, a
568
+ end
569
+
570
+ def test_do_not_dump_empty_array_extra_items
571
+ s = Respect::ArraySchema.define do |s|
572
+ s.extra_items do |s|
573
+ end
574
+ end
575
+ a = Respect::Org3Dumper.new(s).dump
576
+ e = {
577
+ "type" => "array",
578
+ }
579
+ assert_equal e, a
580
+ end
581
+
582
+ def test_dump_option_required
583
+ s = Respect::HashSchema.define do |s|
584
+ s.integer "required_i"
585
+ s.integer "default_i", default: 42
586
+ s.integer "non_required_i", required: false
587
+ s.extra do |s|
588
+ s.integer "optional_i"
589
+ end
590
+ end
591
+ a = Respect::Org3Dumper.new(s).dump
592
+ e = {
593
+ "type" => "object",
594
+ "properties" => {
595
+ "required_i" => { "type" => "integer", "required" => true },
596
+ },
597
+ "additionalProperties" => {
598
+ "default_i" => { "type" => "integer", "default" => 42 },
599
+ "non_required_i" => { "type" => "integer" },
600
+ "optional_i" => { "type" => "integer" },
601
+ },
602
+ }
603
+ assert_equal e, a
604
+ end
605
+
606
+ def test_dump_integer_single_option_with_trivial_translation
607
+ {
608
+ integer: {
609
+ divisible_by: { value: 2, trans: { "divisibleBy" => 2 } },
610
+ multiple_of: { value: 2, trans: { "divisibleBy" => 2 } },
611
+ in: { value: [ 2, 3, 4 ], trans: { "enum" => [ 2, 3, 4 ] } },
612
+ equal_to: { value: 2, trans: { "enum" => [ 2 ] } },
613
+ greater_than: { value: 2, trans: { "minimum" => 2, "exclusiveMinimum" => true } },
614
+ greater_than_or_equal_to: { value: 2, trans: { "minimum" => 2 } },
615
+ less_than: { value: 2, trans: { "maximum" => 2, "exclusiveMaximum" => true } },
616
+ less_than_or_equal_to: { value: 2, trans: { "maximum" => 2 } },
617
+ },
618
+ string: {
619
+ match: { value: /s.*t/, trans: { "pattern" => "s.*t" } },
620
+ min_length: { value: 42, trans: { "minLength" => 42 } },
621
+ max_length: { value: 42, trans: { "maxLength" => 42 } },
622
+ },
623
+ array: {
624
+ uniq: { value: true, trans: { "uniqueItems" => true } },
625
+ min_size: { value: 42, trans: { "minItems" => 42 } },
626
+ max_size: { value: 42, trans: { "maxItems" => 42 } },
627
+ },
628
+ }.each do |statement, options|
629
+ options.each do |opt, params|
630
+ s = Respect::Schema.define do |s|
631
+ s.__send__(statement, { opt => params[:value] })
632
+ end
633
+ a = Respect::Org3Dumper.new(s).dump
634
+ e = { "type" => statement.to_s }.merge(params[:trans])
635
+ assert_equal e, a, "dump option #{opt} for statement #{statement}"
636
+ # Test option value are not shared between the hash and the schema.
637
+ params[:trans].each do |k, v|
638
+ unless v.is_a?(Numeric) || v.is_a?(TrueClass) || v.is_a?(FalseClass)
639
+ assert(s.options[opt].object_id != a[k].object_id,
640
+ "non shared option value for option '#{opt}' for statement '#{statement}'")
641
+ end
642
+ end
643
+ end
644
+ end
645
+ end
646
+
647
+ def test_dump_option_format
648
+ {
649
+ email: 'email',
650
+ uri: 'uri',
651
+ regexp: 'regex',
652
+ datetime: 'date-time',
653
+ ipv4_addr: 'ip-address',
654
+ phone_number: 'phone',
655
+ ipv6_addr: 'ipv6',
656
+ hostname: 'host-name',
657
+ }.each do |format, type|
658
+ s = Respect::Schema.define do |s|
659
+ s.string format: format
660
+ end
661
+ a = Respect::Org3Dumper.new(s).dump
662
+ e = {
663
+ "type" => "string",
664
+ "format" => type,
665
+ }
666
+ assert_equal e, a, "dump format #{format}"
667
+ end
668
+ end
669
+
670
+ # FIXME(Nicolas Despres): Test ip_addr format warn that it cannot be dumped
671
+
672
+ def test_dump_documentation
673
+ [
674
+ { doc: "a title\n\na description",
675
+ expected: { "title" => "a title", "description" => "a description" },
676
+ message: "complete documentation",
677
+ },
678
+ { doc: "a long ... \n ... description",
679
+ expected: { "description" => "a long ... \n ... description" },
680
+ message: "documentation with no title",
681
+ },
682
+ { doc: "a title",
683
+ expected: { "title" => "a title" },
684
+ message: "documentation with no description",
685
+ },
686
+ ].each do |data|
687
+ s = Respect::Schema.define do |s|
688
+ s.doc data[:doc]
689
+ s.integer
690
+ end
691
+ a = Respect::Org3Dumper.new(s).dump
692
+ e = { "type" => "integer" }.merge(data[:expected])
693
+ assert_equal e, a, data[:message]
694
+ end
695
+ end
696
+
697
+ def test_no_dump_for_nodoc
698
+ BASIC_STATEMENTS_LIST.each do |statement|
699
+ s = Respect::Schema.define do |s|
700
+ s.__send__(statement, doc: false)
701
+ end
702
+ assert_nil Respect::Org3Dumper.new(s).dump
703
+ end
704
+ end
705
+
706
+ def test_no_dump_for_non_empty_hash
707
+ s = Respect::Schema.define do |s|
708
+ s.hash doc: false do |s|
709
+ s.integer "i"
710
+ s.string "s"
711
+ end
712
+ end
713
+ assert_nil Respect::Org3Dumper.new(s).dump
714
+ end
715
+
716
+ def test_no_dump_for_non_empty_array
717
+ s = Respect::Schema.define do |s|
718
+ s.array doc: false do |s|
719
+ s.integer
720
+ end
721
+ end
722
+ assert_nil Respect::Org3Dumper.new(s).dump
723
+ end
724
+
725
+ def test_dump_composite_schema
726
+ s = Respect::HashSchema.define do |s|
727
+ s.point "origin"
728
+ end
729
+ a = Respect::Org3Dumper.new(s).dump
730
+ e = {
731
+ "type" => "object",
732
+ "properties" => {
733
+ "origin" => {
734
+ "type" => "object",
735
+ "required" => true,
736
+ "properties" => {
737
+ "x" => { "type" => "number", "required" => true },
738
+ "y" => { "type" => "number", "required" => true },
739
+ }
740
+ }
741
+ }
742
+ }
743
+ assert_equal e, a
744
+ end
745
+
746
+ def test_dump_nested_composite_schema
747
+ s = Respect::HashSchema.define do |s|
748
+ s.circle "area"
749
+ end
750
+ a = Respect::Org3Dumper.new(s).dump
751
+ e = {
752
+ "type" => "object",
753
+ "properties" => {
754
+ "area" => {
755
+ "type" => "object",
756
+ "required" => true,
757
+ "properties" => {
758
+ "center" => {
759
+ "type" => "object",
760
+ "required" => true,
761
+ "properties" => {
762
+ "x" => { "type" => "number", "required" => true },
763
+ "y" => { "type" => "number", "required" => true },
764
+ }
765
+ },
766
+ "radius" => {
767
+ "type" => "number",
768
+ "required" => true,
769
+ "minimum" => 0.0,
770
+ "exclusiveMinimum" => true
771
+ }
772
+ }
773
+ }
774
+ }
775
+ }
776
+ assert_equal e, a
777
+ end
778
+
779
+ def test_custom_validator
780
+ assert_equal({ "type" => "integer", "minimum" => 42, "maximum" => 42 },
781
+ Respect::IntegerSchema.new(universal: true).to_h(:org3))
782
+ end
783
+
784
+ end