schemacop 2.4.7 → 3.0.0.rc4
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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.releaser_config +0 -1
- data/.rubocop.yml +25 -1
- data/.travis.yml +3 -1
- data/CHANGELOG.md +37 -0
- data/README.md +53 -710
- data/README_V2.md +775 -0
- data/README_V3.md +1253 -0
- data/Rakefile +8 -12
- data/VERSION +1 -1
- data/lib/schemacop.rb +35 -37
- data/lib/schemacop/base_schema.rb +37 -0
- data/lib/schemacop/railtie.rb +10 -0
- data/lib/schemacop/schema.rb +1 -60
- data/lib/schemacop/schema2.rb +22 -0
- data/lib/schemacop/schema3.rb +21 -0
- data/lib/schemacop/scoped_env.rb +25 -13
- data/lib/schemacop/v2.rb +25 -0
- data/lib/schemacop/{caster.rb → v2/caster.rb} +17 -2
- data/lib/schemacop/{collector.rb → v2/collector.rb} +5 -2
- data/lib/schemacop/{dupper.rb → v2/dupper.rb} +1 -1
- data/lib/schemacop/{field_node.rb → v2/field_node.rb} +4 -3
- data/lib/schemacop/v2/node.rb +142 -0
- data/lib/schemacop/{node_resolver.rb → v2/node_resolver.rb} +1 -1
- data/lib/schemacop/v2/node_supporting_field.rb +70 -0
- data/lib/schemacop/{node_supporting_type.rb → v2/node_supporting_type.rb} +8 -5
- data/lib/schemacop/{node_with_block.rb → v2/node_with_block.rb} +3 -2
- data/lib/schemacop/v2/validator/array_validator.rb +32 -0
- data/lib/schemacop/{validator → v2/validator}/boolean_validator.rb +1 -1
- data/lib/schemacop/v2/validator/float_validator.rb +7 -0
- data/lib/schemacop/v2/validator/hash_validator.rb +37 -0
- data/lib/schemacop/v2/validator/integer_validator.rb +7 -0
- data/lib/schemacop/{validator → v2/validator}/nil_validator.rb +1 -1
- data/lib/schemacop/v2/validator/number_validator.rb +21 -0
- data/lib/schemacop/v2/validator/object_validator.rb +29 -0
- data/lib/schemacop/v2/validator/string_validator.rb +39 -0
- data/lib/schemacop/{validator → v2/validator}/symbol_validator.rb +1 -1
- data/lib/schemacop/v3.rb +45 -0
- data/lib/schemacop/v3/all_of_node.rb +27 -0
- data/lib/schemacop/v3/any_of_node.rb +28 -0
- data/lib/schemacop/v3/array_node.rb +218 -0
- data/lib/schemacop/v3/boolean_node.rb +16 -0
- data/lib/schemacop/v3/combination_node.rb +45 -0
- data/lib/schemacop/v3/context.rb +17 -0
- data/lib/schemacop/v3/dsl_scope.rb +46 -0
- data/lib/schemacop/v3/global_context.rb +114 -0
- data/lib/schemacop/v3/hash_node.rb +267 -0
- data/lib/schemacop/v3/integer_node.rb +13 -0
- data/lib/schemacop/v3/is_not_node.rb +32 -0
- data/lib/schemacop/v3/node.rb +219 -0
- data/lib/schemacop/v3/node_registry.rb +45 -0
- data/lib/schemacop/v3/number_node.rb +18 -0
- data/lib/schemacop/v3/numeric_node.rb +76 -0
- data/lib/schemacop/v3/object_node.rb +40 -0
- data/lib/schemacop/v3/one_of_node.rb +28 -0
- data/lib/schemacop/v3/reference_node.rb +55 -0
- data/lib/schemacop/v3/result.rb +58 -0
- data/lib/schemacop/v3/string_node.rb +132 -0
- data/lib/schemacop/v3/symbol_node.rb +13 -0
- data/schemacop.gemspec +24 -27
- data/test/lib/test_helper.rb +167 -0
- data/test/schemas/nested/group.rb +6 -0
- data/test/schemas/user.rb +7 -0
- data/test/unit/schemacop/v2/casting_test.rb +157 -0
- data/test/unit/schemacop/v2/collector_test.rb +47 -0
- data/test/unit/schemacop/v2/custom_check_test.rb +95 -0
- data/test/unit/schemacop/v2/custom_if_test.rb +97 -0
- data/test/unit/schemacop/v2/defaults_test.rb +95 -0
- data/test/unit/schemacop/v2/empty_test.rb +16 -0
- data/test/unit/schemacop/v2/nil_dis_allow_test.rb +43 -0
- data/test/unit/schemacop/v2/node_resolver_test.rb +28 -0
- data/test/unit/schemacop/v2/short_forms_test.rb +351 -0
- data/test/unit/schemacop/v2/types_test.rb +88 -0
- data/test/unit/schemacop/v2/validator_array_test.rb +99 -0
- data/test/unit/schemacop/v2/validator_boolean_test.rb +17 -0
- data/test/unit/schemacop/v2/validator_float_test.rb +59 -0
- data/test/unit/schemacop/v2/validator_hash_test.rb +106 -0
- data/test/unit/schemacop/v2/validator_integer_test.rb +48 -0
- data/test/unit/schemacop/v2/validator_nil_test.rb +15 -0
- data/test/unit/schemacop/v2/validator_number_test.rb +62 -0
- data/test/unit/schemacop/v2/validator_object_test.rb +141 -0
- data/test/unit/schemacop/v2/validator_string_test.rb +78 -0
- data/test/unit/schemacop/v2/validator_symbol_test.rb +18 -0
- data/test/unit/schemacop/v3/all_of_node_test.rb +198 -0
- data/test/unit/schemacop/v3/any_of_node_test.rb +218 -0
- data/test/unit/schemacop/v3/array_node_test.rb +815 -0
- data/test/unit/schemacop/v3/boolean_node_test.rb +126 -0
- data/test/unit/schemacop/v3/global_context_test.rb +166 -0
- data/test/unit/schemacop/v3/hash_node_test.rb +972 -0
- data/test/unit/schemacop/v3/integer_node_test.rb +323 -0
- data/test/unit/schemacop/v3/is_not_node_test.rb +173 -0
- data/test/unit/schemacop/v3/node_test.rb +162 -0
- data/test/unit/schemacop/v3/number_node_test.rb +292 -0
- data/test/unit/schemacop/v3/object_node_test.rb +170 -0
- data/test/unit/schemacop/v3/one_of_node_test.rb +187 -0
- data/test/unit/schemacop/v3/reference_node_test.rb +367 -0
- data/test/unit/schemacop/v3/string_node_test.rb +372 -0
- data/test/unit/schemacop/v3/symbol_node_test.rb +75 -0
- metadata +151 -145
- data/doc/Schemacop.html +0 -146
- data/doc/Schemacop/ArrayValidator.html +0 -329
- data/doc/Schemacop/BooleanValidator.html +0 -145
- data/doc/Schemacop/Caster.html +0 -379
- data/doc/Schemacop/Collector.html +0 -787
- data/doc/Schemacop/Dupper.html +0 -214
- data/doc/Schemacop/Exceptions.html +0 -115
- data/doc/Schemacop/Exceptions/InvalidSchemaError.html +0 -124
- data/doc/Schemacop/Exceptions/ValidationError.html +0 -124
- data/doc/Schemacop/FieldNode.html +0 -421
- data/doc/Schemacop/FloatValidator.html +0 -158
- data/doc/Schemacop/HashValidator.html +0 -293
- data/doc/Schemacop/IntegerValidator.html +0 -158
- data/doc/Schemacop/NilValidator.html +0 -145
- data/doc/Schemacop/Node.html +0 -1438
- data/doc/Schemacop/NodeResolver.html +0 -258
- data/doc/Schemacop/NodeSupportingField.html +0 -590
- data/doc/Schemacop/NodeSupportingType.html +0 -612
- data/doc/Schemacop/NodeWithBlock.html +0 -289
- data/doc/Schemacop/NumberValidator.html +0 -232
- data/doc/Schemacop/ObjectValidator.html +0 -298
- data/doc/Schemacop/RootNode.html +0 -171
- data/doc/Schemacop/Schema.html +0 -699
- data/doc/Schemacop/StringValidator.html +0 -295
- data/doc/Schemacop/SymbolValidator.html +0 -145
- data/doc/ScopedEnv.html +0 -351
- data/doc/_index.html +0 -379
- data/doc/class_list.html +0 -51
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -58
- data/doc/css/style.css +0 -496
- data/doc/file.README.html +0 -833
- data/doc/file_list.html +0 -56
- data/doc/frames.html +0 -17
- data/doc/index.html +0 -833
- data/doc/inheritance.graphml +0 -524
- data/doc/inheritance.pdf +0 -825
- data/doc/js/app.js +0 -303
- data/doc/js/full_list.js +0 -216
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -587
- data/doc/top-level-namespace.html +0 -112
- data/lib/schemacop/node.rb +0 -139
- data/lib/schemacop/node_supporting_field.rb +0 -58
- data/lib/schemacop/root_node.rb +0 -4
- data/lib/schemacop/validator/array_validator.rb +0 -30
- data/lib/schemacop/validator/float_validator.rb +0 -5
- data/lib/schemacop/validator/hash_validator.rb +0 -35
- data/lib/schemacop/validator/integer_validator.rb +0 -5
- data/lib/schemacop/validator/number_validator.rb +0 -19
- data/lib/schemacop/validator/object_validator.rb +0 -27
- data/lib/schemacop/validator/string_validator.rb +0 -37
- data/test/casting_test.rb +0 -118
- data/test/collector_test.rb +0 -45
- data/test/custom_check_test.rb +0 -93
- data/test/custom_if_test.rb +0 -95
- data/test/defaults_test.rb +0 -93
- data/test/empty_test.rb +0 -14
- data/test/nil_dis_allow_test.rb +0 -41
- data/test/node_resolver_test.rb +0 -26
- data/test/short_forms_test.rb +0 -349
- data/test/test_helper.rb +0 -13
- data/test/types_test.rb +0 -84
- data/test/validator_array_test.rb +0 -97
- data/test/validator_boolean_test.rb +0 -15
- data/test/validator_float_test.rb +0 -57
- data/test/validator_hash_test.rb +0 -93
- data/test/validator_integer_test.rb +0 -46
- data/test/validator_nil_test.rb +0 -13
- data/test/validator_number_test.rb +0 -60
- data/test/validator_object_test.rb +0 -139
- data/test/validator_string_test.rb +0 -76
- data/test/validator_symbol_test.rb +0 -16
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Schemacop
|
4
|
+
module V3
|
5
|
+
class ObjectNodeTest < V3Test
|
6
|
+
def test_basic
|
7
|
+
schema :object
|
8
|
+
|
9
|
+
assert_validation nil
|
10
|
+
assert_validation true
|
11
|
+
assert_validation false
|
12
|
+
assert_validation Object.new
|
13
|
+
assert_validation 'foo'
|
14
|
+
|
15
|
+
assert_json({})
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_required_with_no_types
|
19
|
+
schema :object, required: true
|
20
|
+
|
21
|
+
assert_validation nil do
|
22
|
+
error '/', 'Value must be given.'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_with_classes
|
27
|
+
schema :object, classes: [String, Date]
|
28
|
+
assert_validation 'foo'
|
29
|
+
assert_validation Date.today
|
30
|
+
assert_validation({}.with_indifferent_access) do
|
31
|
+
error '/', 'Invalid type, expected "Date" or "String".'
|
32
|
+
end
|
33
|
+
assert_validation DateTime.now do
|
34
|
+
error '/', 'Invalid type, expected "Date" or "String".'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_non_strict
|
39
|
+
schema :object, classes: [String, Date, Hash], strict: false
|
40
|
+
assert_validation 'foo'
|
41
|
+
assert_validation 'foo'.html_safe
|
42
|
+
assert_validation Date.today
|
43
|
+
assert_validation nil
|
44
|
+
assert_validation DateTime.now
|
45
|
+
assert_validation({}.with_indifferent_access)
|
46
|
+
assert_validation Time.now do
|
47
|
+
error '/', 'Invalid type, expected "Date" or "Hash" or "String".'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_required
|
52
|
+
schema :object, required: true
|
53
|
+
|
54
|
+
assert_validation true
|
55
|
+
assert_validation false
|
56
|
+
assert_validation nil do
|
57
|
+
error '/', 'Value must be given.'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_hash
|
62
|
+
schema { obj! :myobj, String }
|
63
|
+
assert_json(
|
64
|
+
type: :object,
|
65
|
+
properties: {
|
66
|
+
myobj: {}
|
67
|
+
},
|
68
|
+
required: %i[myobj],
|
69
|
+
additionalProperties: false
|
70
|
+
)
|
71
|
+
assert_validation myobj: ''
|
72
|
+
assert_validation myobj: '42'
|
73
|
+
assert_validation myobj: Date.today do
|
74
|
+
error '/myobj', 'Invalid type, expected "String".'
|
75
|
+
end
|
76
|
+
assert_validation({}) do
|
77
|
+
error '/myobj', 'Value must be given.'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_enum_schema
|
82
|
+
schema :object, enum: [true, 'foo', :baz, [], { qux: '123' }]
|
83
|
+
|
84
|
+
# Can't represent a Ruby Object as a JSON value
|
85
|
+
assert_json({})
|
86
|
+
|
87
|
+
# As we didn't provide any classes, any object (i.e. everything) will
|
88
|
+
# be validated. However, only those elements we put into the enum list
|
89
|
+
# will be allowed
|
90
|
+
assert_validation(nil)
|
91
|
+
assert_validation(true)
|
92
|
+
assert_validation('foo')
|
93
|
+
assert_validation(:baz)
|
94
|
+
assert_validation([])
|
95
|
+
assert_validation({ qux: '123' })
|
96
|
+
|
97
|
+
# These will fail, as we didn't put them into the enum list
|
98
|
+
assert_validation(1) do
|
99
|
+
error '/', 'Value not included in enum [true, "foo", :baz, [], {:qux=>"123"}].'
|
100
|
+
end
|
101
|
+
assert_validation(:bar) do
|
102
|
+
error '/', 'Value not included in enum [true, "foo", :baz, [], {:qux=>"123"}].'
|
103
|
+
end
|
104
|
+
assert_validation({ qux: 42 }) do
|
105
|
+
error '/', 'Value not included in enum [true, "foo", :baz, [], {:qux=>"123"}].'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_enum_schema_with_classes
|
110
|
+
schema :object, classes: [String, Symbol, TrueClass], enum: [true, 'foo', :baz, [], { qux: '123' }, false]
|
111
|
+
|
112
|
+
# Can't represent a Ruby Object as a JSON value
|
113
|
+
assert_json({})
|
114
|
+
|
115
|
+
# Values need to be one of the classed we defined above, as well as in the
|
116
|
+
# enum list for the validation to pass
|
117
|
+
assert_validation(nil)
|
118
|
+
assert_validation(true)
|
119
|
+
assert_validation('foo')
|
120
|
+
assert_validation(:baz)
|
121
|
+
|
122
|
+
# These will fail, as they aren't of one of the classed we defined above
|
123
|
+
assert_validation([]) do
|
124
|
+
error '/', 'Invalid type, expected "String" or "Symbol" or "TrueClass".'
|
125
|
+
end
|
126
|
+
assert_validation({ qux: '123' }) do
|
127
|
+
error '/', 'Invalid type, expected "String" or "Symbol" or "TrueClass".'
|
128
|
+
end
|
129
|
+
assert_validation(false) do
|
130
|
+
error '/', 'Invalid type, expected "String" or "Symbol" or "TrueClass".'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_with_generic_keywords
|
135
|
+
schema :object, enum: [1, 'foo'],
|
136
|
+
title: 'Object schema',
|
137
|
+
description: 'Object schema holding generic keywords',
|
138
|
+
examples: [
|
139
|
+
'foo'
|
140
|
+
]
|
141
|
+
|
142
|
+
assert_json({})
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_validate_self
|
146
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
147
|
+
'Option "strict" must be a "boolean".' do
|
148
|
+
schema :object, strict: 'false'
|
149
|
+
end
|
150
|
+
|
151
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
152
|
+
'Option "strict" must be a "boolean".' do
|
153
|
+
schema :object, strict: 123
|
154
|
+
end
|
155
|
+
|
156
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
157
|
+
'Option "strict" must be a "boolean".' do
|
158
|
+
schema :object, strict: [1, 2, 3]
|
159
|
+
end
|
160
|
+
|
161
|
+
# rubocop:disable Lint/BooleanSymbol
|
162
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
163
|
+
'Option "strict" must be a "boolean".' do
|
164
|
+
schema :object, strict: :false
|
165
|
+
end
|
166
|
+
# rubocop:enable Lint/BooleanSymbol
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Schemacop
|
4
|
+
module V3
|
5
|
+
class OneOfNodeTest < V3Test
|
6
|
+
def test_optional
|
7
|
+
schema :one_of do
|
8
|
+
num multiple_of: 2
|
9
|
+
num multiple_of: 3
|
10
|
+
str
|
11
|
+
end
|
12
|
+
|
13
|
+
assert_validation(nil)
|
14
|
+
assert_validation(4)
|
15
|
+
assert_validation(9)
|
16
|
+
assert_validation('foo')
|
17
|
+
assert_validation(12) do
|
18
|
+
error '/', 'Matches 2 definitions but should match exactly 1.'
|
19
|
+
end
|
20
|
+
assert_validation(1) do
|
21
|
+
error '/', 'Matches 0 definitions but should match exactly 1.'
|
22
|
+
end
|
23
|
+
assert_validation(:foo) do
|
24
|
+
error '/', 'Matches 0 definitions but should match exactly 1.'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_required
|
29
|
+
schema :one_of, required: true do
|
30
|
+
num multiple_of: 2
|
31
|
+
num multiple_of: 3
|
32
|
+
str
|
33
|
+
end
|
34
|
+
|
35
|
+
assert_validation(8)
|
36
|
+
assert_validation(9)
|
37
|
+
|
38
|
+
assert_validation(nil) do
|
39
|
+
error '/', 'Value must be given.'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_nested
|
44
|
+
schema :one_of do
|
45
|
+
hsh do
|
46
|
+
one_of! :foo do
|
47
|
+
num multiple_of: 2
|
48
|
+
num multiple_of: 3
|
49
|
+
end
|
50
|
+
end
|
51
|
+
hsh do
|
52
|
+
num? :foo, multiple_of: 7
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
assert_validation(foo: 2)
|
57
|
+
assert_validation(foo: 9)
|
58
|
+
assert_validation(foo: 7)
|
59
|
+
assert_validation(foo: 14) do
|
60
|
+
error '/', 'Matches 2 definitions but should match exactly 1.'
|
61
|
+
end
|
62
|
+
assert_validation(foo: 12) do
|
63
|
+
error '/', 'Matches 0 definitions but should match exactly 1.'
|
64
|
+
end
|
65
|
+
|
66
|
+
assert_json(
|
67
|
+
oneOf: [
|
68
|
+
{
|
69
|
+
type: :object,
|
70
|
+
properties: {
|
71
|
+
foo: {
|
72
|
+
oneOf: [
|
73
|
+
{ type: :number, multipleOf: 2 },
|
74
|
+
{ type: :number, multipleOf: 3 }
|
75
|
+
]
|
76
|
+
}
|
77
|
+
},
|
78
|
+
required: %i[foo],
|
79
|
+
additionalProperties: false
|
80
|
+
},
|
81
|
+
{
|
82
|
+
type: :object,
|
83
|
+
properties: {
|
84
|
+
foo: { type: :number, multipleOf: 7 }
|
85
|
+
},
|
86
|
+
additionalProperties: false
|
87
|
+
}
|
88
|
+
]
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_casting
|
93
|
+
schema do
|
94
|
+
one_of! :created_at do
|
95
|
+
str format: :date
|
96
|
+
str format: :date_time
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
assert_validation(created_at: '2020-01-01')
|
101
|
+
assert_validation(created_at: '2020-01-01T17:38:20')
|
102
|
+
|
103
|
+
assert_cast(
|
104
|
+
{ created_at: '2020-01-01' },
|
105
|
+
{ created_at: Date.new(2020, 1, 1) }.with_indifferent_access
|
106
|
+
)
|
107
|
+
assert_cast(
|
108
|
+
{ created_at: '2020-01-01T17:38:20' },
|
109
|
+
{ created_at: DateTime.new(2020, 1, 1, 17, 38, 20) }.with_indifferent_access
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_defaults
|
114
|
+
schema do
|
115
|
+
one_of! :foo do
|
116
|
+
hsh { str? :bar }
|
117
|
+
hsh { str? :baz, default: 'Baz' }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
assert_validation(foo: { bar: 'Bar' })
|
122
|
+
assert_validation(foo: { baz: 'Baz' })
|
123
|
+
|
124
|
+
assert_validation(foo: { xyz: 'Baz' }) do
|
125
|
+
error '/foo', 'Matches 0 definitions but should match exactly 1.'
|
126
|
+
end
|
127
|
+
|
128
|
+
assert_cast(
|
129
|
+
{ foo: { bar: nil } },
|
130
|
+
{ foo: { bar: nil } }.with_indifferent_access
|
131
|
+
)
|
132
|
+
|
133
|
+
assert_cast(
|
134
|
+
{ foo: { baz: nil } },
|
135
|
+
{ foo: { baz: 'Baz' } }.with_indifferent_access
|
136
|
+
)
|
137
|
+
|
138
|
+
schema do
|
139
|
+
one_of! :foo do
|
140
|
+
hsh { str? :bar, format: :date }
|
141
|
+
hsh { str? :bar, default: 'Baz', format: :date_time }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
assert_cast(
|
146
|
+
{ foo: { bar: '1990-01-13' } },
|
147
|
+
{ foo: { bar: Date.new(1990, 1, 13) } }.with_indifferent_access
|
148
|
+
)
|
149
|
+
|
150
|
+
assert_cast(
|
151
|
+
{ foo: { bar: '1990-01-13T10:00:00Z' } },
|
152
|
+
{ foo: { bar: DateTime.new(1990, 1, 13, 10, 0, 0) } }.with_indifferent_access
|
153
|
+
)
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_with_generic_keywords
|
157
|
+
schema :one_of, title: 'oneOf schema',
|
158
|
+
description: 'oneOf schema holding generic keywords',
|
159
|
+
examples: [
|
160
|
+
'foo'
|
161
|
+
] do
|
162
|
+
str
|
163
|
+
int
|
164
|
+
end
|
165
|
+
|
166
|
+
assert_json({
|
167
|
+
oneOf: [
|
168
|
+
{ type: :string },
|
169
|
+
{ type: :integer }
|
170
|
+
],
|
171
|
+
title: 'oneOf schema',
|
172
|
+
description: 'oneOf schema holding generic keywords',
|
173
|
+
examples: [
|
174
|
+
'foo'
|
175
|
+
]
|
176
|
+
})
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_invalid_schema
|
180
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
181
|
+
'Node "one_of" makes only sense with at least 2 items.' do
|
182
|
+
schema :one_of
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,367 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Schemacop
|
4
|
+
module V3
|
5
|
+
class ReferenceNodeTest < V3Test
|
6
|
+
def test_in_hash
|
7
|
+
context = Context.new
|
8
|
+
context.schema :MyString, :string
|
9
|
+
context.schema :MyInteger, :integer
|
10
|
+
|
11
|
+
Schemacop.with_context context do
|
12
|
+
schema do
|
13
|
+
ref? :foo, :MyString
|
14
|
+
ref? :int, :MyInteger
|
15
|
+
hsh? :bar do
|
16
|
+
ref? :foo, :MyString
|
17
|
+
hsh? :baz do
|
18
|
+
ref! :foo, :MyInteger
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_validation({})
|
24
|
+
assert_validation(foo: 'String')
|
25
|
+
assert_validation(bar: { foo: 'String' })
|
26
|
+
assert_validation(bar: { foo: 'String', baz: { foo: 42 } })
|
27
|
+
|
28
|
+
assert_validation(foo: 42) do
|
29
|
+
error '/foo', 'Invalid type, expected "string".'
|
30
|
+
end
|
31
|
+
assert_validation(bar: { foo: 42 }) do
|
32
|
+
error '/bar/foo', 'Invalid type, expected "string".'
|
33
|
+
end
|
34
|
+
assert_validation(bar: { foo: 'String', baz: { foo: '42' } }) do
|
35
|
+
error '/bar/baz/foo', 'Invalid type, expected "integer".'
|
36
|
+
end
|
37
|
+
|
38
|
+
assert_json({
|
39
|
+
properties: {
|
40
|
+
foo: {
|
41
|
+
'$ref' => '#/definitions/MyString'
|
42
|
+
},
|
43
|
+
int: {
|
44
|
+
'$ref' => '#/definitions/MyInteger'
|
45
|
+
},
|
46
|
+
bar: {
|
47
|
+
properties: {
|
48
|
+
foo: {
|
49
|
+
'$ref' => '#/definitions/MyString'
|
50
|
+
},
|
51
|
+
baz: {
|
52
|
+
properties: {
|
53
|
+
foo: {
|
54
|
+
'$ref' => '#/definitions/MyInteger'
|
55
|
+
}
|
56
|
+
},
|
57
|
+
additionalProperties: false,
|
58
|
+
required: ['foo'],
|
59
|
+
type: :object
|
60
|
+
}
|
61
|
+
},
|
62
|
+
additionalProperties: false,
|
63
|
+
type: :object
|
64
|
+
}
|
65
|
+
},
|
66
|
+
additionalProperties: false,
|
67
|
+
type: :object
|
68
|
+
})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_schema_not_found
|
73
|
+
assert_raises_with_message RuntimeError, 'Schema "MyInteger" not found.' do
|
74
|
+
schema do
|
75
|
+
ref? :int, :MyInteger
|
76
|
+
end
|
77
|
+
assert_validation(int: 5)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_multiple_schemas
|
82
|
+
schema do
|
83
|
+
scm :Address do
|
84
|
+
str! :street
|
85
|
+
str! :zip_code
|
86
|
+
str! :location
|
87
|
+
str! :country
|
88
|
+
end
|
89
|
+
|
90
|
+
scm :Person do
|
91
|
+
str! :first_name
|
92
|
+
str! :last_name
|
93
|
+
str! :birthday, format: :date
|
94
|
+
end
|
95
|
+
|
96
|
+
ref! :person_info, :Person
|
97
|
+
ref! :shipping_address, :Address
|
98
|
+
ref! :billing_address, :Address
|
99
|
+
end
|
100
|
+
|
101
|
+
assert_json({
|
102
|
+
definitions: {
|
103
|
+
Address: {
|
104
|
+
properties: {
|
105
|
+
street: {
|
106
|
+
type: :string
|
107
|
+
},
|
108
|
+
zip_code: {
|
109
|
+
type: :string
|
110
|
+
},
|
111
|
+
location: {
|
112
|
+
type: :string
|
113
|
+
},
|
114
|
+
country: {
|
115
|
+
type: :string
|
116
|
+
}
|
117
|
+
},
|
118
|
+
additionalProperties: false,
|
119
|
+
required: %w[street zip_code location country],
|
120
|
+
type: :object
|
121
|
+
},
|
122
|
+
Person: {
|
123
|
+
properties: {
|
124
|
+
first_name: {
|
125
|
+
type: :string
|
126
|
+
},
|
127
|
+
last_name: {
|
128
|
+
type: :string
|
129
|
+
},
|
130
|
+
birthday: {
|
131
|
+
type: :string,
|
132
|
+
format: :date
|
133
|
+
}
|
134
|
+
},
|
135
|
+
additionalProperties: false,
|
136
|
+
required: %w[first_name last_name birthday],
|
137
|
+
type: :object
|
138
|
+
}
|
139
|
+
},
|
140
|
+
properties: {
|
141
|
+
person_info: {
|
142
|
+
'$ref' => '#/definitions/Person'
|
143
|
+
},
|
144
|
+
shipping_address: {
|
145
|
+
'$ref' => '#/definitions/Address'
|
146
|
+
},
|
147
|
+
billing_address: {
|
148
|
+
'$ref' => '#/definitions/Address'
|
149
|
+
}
|
150
|
+
},
|
151
|
+
type: :object,
|
152
|
+
additionalProperties: false,
|
153
|
+
required: %w[
|
154
|
+
person_info
|
155
|
+
shipping_address
|
156
|
+
billing_address
|
157
|
+
]
|
158
|
+
})
|
159
|
+
|
160
|
+
assert_validation(nil)
|
161
|
+
assert_validation({
|
162
|
+
person_info: {
|
163
|
+
first_name: 'Joe',
|
164
|
+
last_name: 'Doe',
|
165
|
+
birthday: '1990-01-01'
|
166
|
+
},
|
167
|
+
billing_address: {
|
168
|
+
street: 'Badenerstrasse 530',
|
169
|
+
zip_code: '8048',
|
170
|
+
location: 'Zürich',
|
171
|
+
country: 'Switzerland'
|
172
|
+
},
|
173
|
+
shipping_address: {
|
174
|
+
street: 'Badenerstrasse 530',
|
175
|
+
zip_code: '8048',
|
176
|
+
location: 'Zürich',
|
177
|
+
country: 'Switzerland'
|
178
|
+
}
|
179
|
+
})
|
180
|
+
|
181
|
+
assert_validation({}) do
|
182
|
+
error '/person_info', 'Value must be given.'
|
183
|
+
error '/shipping_address', 'Value must be given.'
|
184
|
+
error '/billing_address', 'Value must be given.'
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_nested_schemas
|
189
|
+
schema do
|
190
|
+
scm :User do
|
191
|
+
str! :first_name
|
192
|
+
str! :last_name
|
193
|
+
ary? :groups do
|
194
|
+
list :reference, path: :Group
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
scm :Group do
|
199
|
+
str! :name
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
assert_json({
|
204
|
+
additionalProperties: false,
|
205
|
+
definitions: {
|
206
|
+
User: {
|
207
|
+
properties: {
|
208
|
+
first_name: {
|
209
|
+
type: :string
|
210
|
+
},
|
211
|
+
last_name: {
|
212
|
+
type: :string
|
213
|
+
},
|
214
|
+
groups: {
|
215
|
+
type: :array,
|
216
|
+
items: {
|
217
|
+
'$ref' => '#/definitions/Group'
|
218
|
+
}
|
219
|
+
}
|
220
|
+
},
|
221
|
+
additionalProperties: false,
|
222
|
+
required: %w[first_name last_name],
|
223
|
+
type: :object
|
224
|
+
},
|
225
|
+
Group: {
|
226
|
+
properties: {
|
227
|
+
name: {
|
228
|
+
type: :string
|
229
|
+
}
|
230
|
+
},
|
231
|
+
additionalProperties: false,
|
232
|
+
required: ['name'],
|
233
|
+
type: :object
|
234
|
+
}
|
235
|
+
},
|
236
|
+
type: :object
|
237
|
+
})
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_in_hash_recursion
|
241
|
+
schema do
|
242
|
+
scm :Node do
|
243
|
+
str! :name
|
244
|
+
ary? :children, min_items: 1 do
|
245
|
+
list :reference, path: :Node
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
ref? :node, :Node
|
250
|
+
end
|
251
|
+
|
252
|
+
assert_equal(@schema.root.used_external_schemas, [])
|
253
|
+
|
254
|
+
assert_validation({})
|
255
|
+
assert_validation(node: { name: '1', children: [{ name: '1' }, { name: '2' }] })
|
256
|
+
assert_validation(
|
257
|
+
node: {
|
258
|
+
name: '1',
|
259
|
+
children: [
|
260
|
+
{ name: '1.1' },
|
261
|
+
{
|
262
|
+
name: '1.2',
|
263
|
+
children: [
|
264
|
+
{ name: '1.2.1' }
|
265
|
+
]
|
266
|
+
}
|
267
|
+
]
|
268
|
+
}
|
269
|
+
)
|
270
|
+
|
271
|
+
assert_validation(
|
272
|
+
node: {
|
273
|
+
name: '1',
|
274
|
+
children: [
|
275
|
+
{ name: '1.1' },
|
276
|
+
{
|
277
|
+
name: '1.2',
|
278
|
+
children: [
|
279
|
+
{ name: '1.2.1', children: [] }
|
280
|
+
]
|
281
|
+
},
|
282
|
+
{ name: '1.3', foo: :bar }
|
283
|
+
]
|
284
|
+
}
|
285
|
+
) do
|
286
|
+
error '/node/children/[1]/children/[0]/children', 'Array has 0 items but needs at least 1.'
|
287
|
+
error '/node/children/[2]', 'Obsolete property "foo".'
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_external_schemas
|
292
|
+
context = Context.new
|
293
|
+
|
294
|
+
context.schema :Person do
|
295
|
+
str! :first_name
|
296
|
+
str! :last_name
|
297
|
+
ref? :info, :PersonInfo
|
298
|
+
end
|
299
|
+
|
300
|
+
context.schema :PersonInfo do
|
301
|
+
str! :born_at, format: :date
|
302
|
+
end
|
303
|
+
|
304
|
+
schema :reference, path: :Person
|
305
|
+
|
306
|
+
with_context context do
|
307
|
+
assert_validation(first_name: 'John', last_name: 'Doe')
|
308
|
+
assert_validation(first_name: 'John', last_name: 42) do
|
309
|
+
error '/last_name', 'Invalid type, expected "string".'
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
with_context context do
|
314
|
+
schema do
|
315
|
+
ref! :person, :Person
|
316
|
+
end
|
317
|
+
|
318
|
+
assert_equal(@schema.root.used_external_schemas, %i[Person PersonInfo])
|
319
|
+
|
320
|
+
assert_validation(person: { first_name: 'John', last_name: 'Doe' })
|
321
|
+
assert_validation(person: { first_name: 'John', last_name: 'Doe', info: { born_at: '1990-01-13' } })
|
322
|
+
assert_validation(person: { first_name_x: 'John', last_name: 'Doe' }) do
|
323
|
+
error '/person', 'Obsolete property "first_name_x".'
|
324
|
+
error '/person/first_name', 'Value must be given.'
|
325
|
+
end
|
326
|
+
assert_validation(person: { first_name: 'John', last_name: 'Doe', info: { born_at: 'never' } }) do
|
327
|
+
error '/person/info/born_at', 'String does not match format "date".'
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
with_context context do
|
332
|
+
schema do
|
333
|
+
scm :PersonNode do
|
334
|
+
ref! :person, :Person
|
335
|
+
end
|
336
|
+
|
337
|
+
ref! :personNode, :PersonNode
|
338
|
+
end
|
339
|
+
|
340
|
+
assert_equal(@schema.root.used_external_schemas, %i[Person PersonInfo])
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_defaults
|
345
|
+
schema do
|
346
|
+
scm :Person do
|
347
|
+
str? :foo, default: 'bar'
|
348
|
+
end
|
349
|
+
ref? :person, :Person, default: {}
|
350
|
+
end
|
351
|
+
|
352
|
+
assert_cast({}, { person: { foo: 'bar' } }.with_indifferent_access)
|
353
|
+
end
|
354
|
+
|
355
|
+
def test_casting
|
356
|
+
schema do
|
357
|
+
scm :Person do
|
358
|
+
str! :born_at, format: :date
|
359
|
+
end
|
360
|
+
ref? :person, :Person, default: {}
|
361
|
+
end
|
362
|
+
|
363
|
+
assert_cast({ person: { born_at: '1990-01-13' } }, { person: { born_at: Date.new(1990, 1, 13) } }.with_indifferent_access)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|