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