schemacop 2.4.7 → 3.0.0.rc0
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/.rubocop.yml +25 -1
- data/.travis.yml +2 -1
- data/CHANGELOG.md +8 -0
- data/README.md +41 -708
- data/README_V2.md +775 -0
- data/README_V3.md +683 -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 +26 -0
- data/lib/schemacop/{caster.rb → v2/caster.rb} +16 -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/{node_supporting_field.rb → v2/node_supporting_field.rb} +8 -10
- data/lib/schemacop/{node_supporting_type.rb → v2/node_supporting_type.rb} +6 -3
- data/lib/schemacop/{node_with_block.rb → v2/node_with_block.rb} +3 -2
- data/lib/schemacop/v2/root_node.rb +6 -0
- 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 +219 -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 +217 -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 +214 -0
- data/lib/schemacop/v3/node_registry.rb +49 -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 +49 -0
- data/lib/schemacop/v3/result.rb +58 -0
- data/lib/schemacop/v3/string_node.rb +124 -0
- data/lib/schemacop/v3/symbol_node.rb +13 -0
- data/schemacop.gemspec +24 -27
- data/test/lib/test_helper.rb +152 -0
- data/test/schemas/nested/group.rb +6 -0
- data/test/schemas/user.rb +7 -0
- data/test/unit/schemacop/v2/casting_test.rb +120 -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 +95 -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 +199 -0
- data/test/unit/schemacop/v3/any_of_node_test.rb +218 -0
- data/test/unit/schemacop/v3/array_node_test.rb +805 -0
- data/test/unit/schemacop/v3/boolean_node_test.rb +126 -0
- data/test/unit/schemacop/v3/global_context_test.rb +164 -0
- data/test/unit/schemacop/v3/hash_node_test.rb +775 -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 +148 -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 +351 -0
- data/test/unit/schemacop/v3/string_node_test.rb +334 -0
- data/test/unit/schemacop/v3/symbol_node_test.rb +75 -0
- metadata +152 -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/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,126 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
# rubocop:disable Lint/BooleanSymbol
|
3
|
+
|
4
|
+
module Schemacop
|
5
|
+
module V3
|
6
|
+
class BooleanNodeTest < V3Test
|
7
|
+
EXP_INVALID_TYPE = 'Invalid type, expected "boolean".'.freeze
|
8
|
+
|
9
|
+
def test_basic
|
10
|
+
schema :boolean
|
11
|
+
|
12
|
+
assert_validation true
|
13
|
+
assert_validation false
|
14
|
+
|
15
|
+
assert_json(type: :boolean)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_required
|
19
|
+
schema :boolean, required: true
|
20
|
+
|
21
|
+
assert_validation true
|
22
|
+
assert_validation false
|
23
|
+
assert_validation nil do
|
24
|
+
error '/', 'Value must be given.'
|
25
|
+
end
|
26
|
+
|
27
|
+
assert_json(type: :boolean)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_hash
|
31
|
+
schema { boo! :alive }
|
32
|
+
assert_json(
|
33
|
+
type: :object,
|
34
|
+
properties: {
|
35
|
+
alive: { type: :boolean }
|
36
|
+
},
|
37
|
+
required: %i[alive],
|
38
|
+
additionalProperties: false
|
39
|
+
)
|
40
|
+
assert_validation alive: true
|
41
|
+
assert_validation alive: false
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_type
|
45
|
+
schema :boolean
|
46
|
+
|
47
|
+
assert_json(type: :boolean)
|
48
|
+
|
49
|
+
assert_validation 42 do
|
50
|
+
error '/', EXP_INVALID_TYPE
|
51
|
+
end
|
52
|
+
|
53
|
+
[:true, 'true', :false, 'false', 0, 1].each do |value|
|
54
|
+
assert_validation value do
|
55
|
+
error '/', EXP_INVALID_TYPE
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
schema { boo? :name }
|
60
|
+
|
61
|
+
assert_json(
|
62
|
+
type: :object,
|
63
|
+
properties: {
|
64
|
+
name: { type: :boolean }
|
65
|
+
},
|
66
|
+
additionalProperties: false
|
67
|
+
)
|
68
|
+
|
69
|
+
[:true, 'true', :false, 'false', 0, 1].each do |value|
|
70
|
+
assert_validation name: value do
|
71
|
+
error '/name', EXP_INVALID_TYPE
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_enum_schema
|
77
|
+
schema :boolean, enum: [1, 2, 'foo', :bar, { qux: 42 }, true]
|
78
|
+
|
79
|
+
assert_json({
|
80
|
+
type: :boolean,
|
81
|
+
enum: [1, 2, 'foo', :bar, { qux: 42 }, true]
|
82
|
+
})
|
83
|
+
|
84
|
+
assert_validation(nil)
|
85
|
+
assert_validation(true)
|
86
|
+
|
87
|
+
# Even we put those types in the enum, they need to fail the validations,
|
88
|
+
# as they are not booleans
|
89
|
+
assert_validation('foo') do
|
90
|
+
error '/', 'Invalid type, expected "boolean".'
|
91
|
+
end
|
92
|
+
assert_validation(:bar) do
|
93
|
+
error '/', 'Invalid type, expected "boolean".'
|
94
|
+
end
|
95
|
+
assert_validation({ qux: 42 }) do
|
96
|
+
error '/', 'Invalid type, expected "boolean".'
|
97
|
+
end
|
98
|
+
|
99
|
+
# These need to fail validation, as they are not in the enum list
|
100
|
+
assert_validation(false) do
|
101
|
+
error '/', 'Value not included in enum [1, 2, "foo", :bar, {:qux=>42}, true].'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_with_generic_keywords
|
106
|
+
schema :boolean, enum: [1, 'foo', true],
|
107
|
+
title: 'Boolean schema',
|
108
|
+
description: 'Boolean schema holding generic keywords',
|
109
|
+
examples: [
|
110
|
+
true
|
111
|
+
]
|
112
|
+
|
113
|
+
assert_json({
|
114
|
+
type: :boolean,
|
115
|
+
enum: [1, 'foo', true],
|
116
|
+
title: 'Boolean schema',
|
117
|
+
description: 'Boolean schema holding generic keywords',
|
118
|
+
examples: [
|
119
|
+
true
|
120
|
+
]
|
121
|
+
})
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
# rubocop:enable Lint/BooleanSymbol
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Schemacop
|
4
|
+
module V3
|
5
|
+
class GlobalContextTest < V3Test
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
GlobalContext.instance_variable_set(:@instance, GlobalContext.send(:new))
|
9
|
+
Schemacop.load_paths = ['test/schemas']
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_instance
|
13
|
+
assert_equal GlobalContext.instance, GlobalContext.instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_eager_load
|
17
|
+
refute GlobalContext.instance.instance_variable_get(:@eager_loaded)
|
18
|
+
GlobalContext.instance.eager_load!
|
19
|
+
assert GlobalContext.instance.instance_variable_get(:@eager_loaded)
|
20
|
+
|
21
|
+
assert_raises_with_message RuntimeError, /can't be eager loaded more than once/ do
|
22
|
+
GlobalContext.instance.eager_load!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_schemas
|
27
|
+
assert_equal({}, GlobalContext.instance.schemas)
|
28
|
+
GlobalContext.instance.eager_load!
|
29
|
+
assert_equal(%i[nested/group user], GlobalContext.instance.schemas.keys)
|
30
|
+
assert_is_a Node, GlobalContext.instance.schemas.values.first
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_schema_for_w_eager_loading
|
34
|
+
GlobalContext.instance.eager_load!
|
35
|
+
|
36
|
+
2.times do
|
37
|
+
assert_is_a HashNode, GlobalContext.instance.schema_for('user')
|
38
|
+
assert_equal(%i[nested/group user], GlobalContext.instance.schemas.keys)
|
39
|
+
assert_is_a HashNode, GlobalContext.instance.schema_for('user')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_schema_for_wo_eager_loading
|
44
|
+
assert_is_a HashNode, GlobalContext.instance.schema_for('user')
|
45
|
+
assert_equal(%i[user], GlobalContext.instance.schemas.keys)
|
46
|
+
assert_is_a HashNode, GlobalContext.instance.schema_for('user')
|
47
|
+
assert_is_a HashNode, GlobalContext.instance.schema_for('nested/group')
|
48
|
+
assert_equal(%i[user nested/group], GlobalContext.instance.schemas.keys)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_file_reload
|
52
|
+
dir = Dir.mktmpdir
|
53
|
+
Schemacop.load_paths << dir
|
54
|
+
IO.write(File.join(dir, 'foo.rb'), %(schema :string))
|
55
|
+
assert_is_a StringNode, GlobalContext.instance.schema_for('foo')
|
56
|
+
IO.write(File.join(dir, 'foo.rb'), %(schema :integer))
|
57
|
+
assert_is_a IntegerNode, GlobalContext.instance.schema_for('foo')
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_file_not_reloaded_in_eager
|
61
|
+
dir = Dir.mktmpdir
|
62
|
+
Schemacop.load_paths << dir
|
63
|
+
|
64
|
+
IO.write(File.join(dir, 'foo.rb'), %(schema :string))
|
65
|
+
|
66
|
+
GlobalContext.instance.eager_load!
|
67
|
+
|
68
|
+
assert_is_a StringNode, GlobalContext.instance.schema_for('foo')
|
69
|
+
IO.write(File.join(dir, 'foo.rb'), %(schema :integer))
|
70
|
+
assert_is_a StringNode, GlobalContext.instance.schema_for('foo')
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_schema_not_found
|
74
|
+
assert_nil GlobalContext.instance.schema_for('foo')
|
75
|
+
GlobalContext.instance.eager_load!
|
76
|
+
assert_nil GlobalContext.instance.schema_for('foo')
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_inter_references
|
80
|
+
schema = GlobalContext.instance.schema_for('user')
|
81
|
+
|
82
|
+
assert schema.validate(
|
83
|
+
first_name: 'John',
|
84
|
+
last_name: 'Doe',
|
85
|
+
groups: [
|
86
|
+
{ name: 'Group 1' }
|
87
|
+
]
|
88
|
+
).valid?
|
89
|
+
|
90
|
+
refute schema.validate(
|
91
|
+
first_name: 'John',
|
92
|
+
last_name: 'Doe',
|
93
|
+
groups: [
|
94
|
+
{ name_x: 'Group 1' }
|
95
|
+
]
|
96
|
+
).valid?
|
97
|
+
|
98
|
+
schema = GlobalContext.instance.schema_for('nested/group')
|
99
|
+
|
100
|
+
assert schema.validate(
|
101
|
+
name: 'Group 1',
|
102
|
+
users: [
|
103
|
+
{ first_name: 'John', last_name: 'Doe' }
|
104
|
+
]
|
105
|
+
).valid?
|
106
|
+
|
107
|
+
refute schema.validate(
|
108
|
+
name: 'Group 1',
|
109
|
+
users: [
|
110
|
+
{ first_name_x: 'John', last_name: 'Doe' }
|
111
|
+
]
|
112
|
+
).valid?
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_empty_schema
|
116
|
+
dir = Dir.mktmpdir
|
117
|
+
Schemacop.load_paths << dir
|
118
|
+
IO.write(File.join(dir, 'foo.rb'), %())
|
119
|
+
assert_raises_with_message RuntimeError, /does not define any schema/ do
|
120
|
+
GlobalContext.instance.schema_for('foo')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_multiple_schemas
|
125
|
+
dir = Dir.mktmpdir
|
126
|
+
Schemacop.load_paths << dir
|
127
|
+
IO.write(File.join(dir, 'foo.rb'), %(schema :string\nschema :integer))
|
128
|
+
assert_raises_with_message RuntimeError, /Schema "#{File.join(dir, 'foo.rb')}" defines multiple schemas/ do
|
129
|
+
GlobalContext.instance.schema_for('foo')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_invalid_schema
|
134
|
+
dir = Dir.mktmpdir
|
135
|
+
Schemacop.load_paths << dir
|
136
|
+
IO.write(File.join(dir, 'foo.rb'), %(foobarbaz))
|
137
|
+
|
138
|
+
assert_raises_with_message RuntimeError, /Could not load schema/ do
|
139
|
+
GlobalContext.schema_for('foo')
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_overrides_with_eager_load
|
144
|
+
dir = Dir.mktmpdir
|
145
|
+
Schemacop.load_paths << dir
|
146
|
+
IO.write(File.join(dir, 'user.rb'), %(schema :string))
|
147
|
+
|
148
|
+
assert_raises_with_message RuntimeError, %r{in both load paths "test/schemas" and "#{dir}"} do
|
149
|
+
GlobalContext.eager_load!
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_overrides_with_lazy_load
|
154
|
+
dir = Dir.mktmpdir
|
155
|
+
Schemacop.load_paths << dir
|
156
|
+
IO.write(File.join(dir, 'user.rb'), %(schema :string))
|
157
|
+
|
158
|
+
assert_raises_with_message RuntimeError, %r{in both load paths "test/schemas" and "#{dir}"} do
|
159
|
+
GlobalContext.instance.schema_for('user')
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,775 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Schemacop
|
4
|
+
module V3
|
5
|
+
class HashNodeTest < V3Test
|
6
|
+
EXP_INVALID_TYPE = 'Invalid type, expected "hash".'.freeze
|
7
|
+
|
8
|
+
def test_basic
|
9
|
+
schema
|
10
|
+
assert_validation({})
|
11
|
+
assert_json(type: :object, additionalProperties: false)
|
12
|
+
|
13
|
+
schema :hash
|
14
|
+
assert_validation({})
|
15
|
+
|
16
|
+
assert_json(type: :object, additionalProperties: false)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_additional_properties_false
|
20
|
+
schema
|
21
|
+
assert_validation({})
|
22
|
+
assert_validation(foo: :bar, bar: :baz) do
|
23
|
+
error '/', 'Obsolete property "foo".'
|
24
|
+
error '/', 'Obsolete property "bar".'
|
25
|
+
end
|
26
|
+
assert_json(type: :object, additionalProperties: false)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_additional_properties_true
|
30
|
+
schema :hash, additional_properties: true
|
31
|
+
assert_validation({})
|
32
|
+
assert_validation(foo: :bar)
|
33
|
+
assert_validation(foo: { bar: :baz })
|
34
|
+
|
35
|
+
assert_json(type: :object, additionalProperties: true)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_additional_properties_schema
|
39
|
+
schema :hash do
|
40
|
+
str! :foo
|
41
|
+
add :string
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_validation(foo: 'bar', baz: 'foo', answer: '42')
|
45
|
+
assert_validation(foo: 'bar', baz: 'foo', answer: 42) do
|
46
|
+
error '/answer', 'Invalid type, expected "string".'
|
47
|
+
end
|
48
|
+
|
49
|
+
assert_json(
|
50
|
+
properties: {
|
51
|
+
foo: { type: :string }
|
52
|
+
},
|
53
|
+
required: %i[foo],
|
54
|
+
type: :object,
|
55
|
+
additionalProperties: { type: :string }
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_property_names
|
60
|
+
schema :hash, additional_properties: true, property_names: '^[a-zA-Z0-9]+$'
|
61
|
+
assert_validation({})
|
62
|
+
assert_validation(foo: :bar)
|
63
|
+
assert_validation('foo' => 'bar')
|
64
|
+
assert_validation('_foo39sjfdoi 345893(%' => 'bar', 'foo' => 'bar') do
|
65
|
+
error '/', 'Property name "_foo39sjfdoi 345893(%" does not match "^[a-zA-Z0-9]+$".'
|
66
|
+
end
|
67
|
+
|
68
|
+
assert_json(
|
69
|
+
type: :object,
|
70
|
+
additionalProperties: true,
|
71
|
+
propertyNames: '^[a-zA-Z0-9]+$'
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_required
|
76
|
+
schema do
|
77
|
+
str! :foo
|
78
|
+
int? :bar
|
79
|
+
end
|
80
|
+
|
81
|
+
assert_validation(foo: 'sdfsd')
|
82
|
+
assert_validation(foo: 'sdfsd', bar: 42)
|
83
|
+
|
84
|
+
assert_validation(bar: 42) do
|
85
|
+
error '/foo', 'Value must be given.'
|
86
|
+
end
|
87
|
+
|
88
|
+
assert_validation({}) do
|
89
|
+
error '/foo', 'Value must be given.'
|
90
|
+
end
|
91
|
+
|
92
|
+
assert_json(
|
93
|
+
type: :object,
|
94
|
+
properties: {
|
95
|
+
foo: { type: :string },
|
96
|
+
bar: { type: :integer }
|
97
|
+
},
|
98
|
+
required: %i[foo],
|
99
|
+
additionalProperties: false
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_min_properties
|
104
|
+
schema :hash, min_properties: 2, additional_properties: true
|
105
|
+
assert_validation(foo: :bar, bar: :baz)
|
106
|
+
assert_validation(foo: :bar, bar: :baz, baz: :foo)
|
107
|
+
|
108
|
+
assert_validation(foo: :bar) do
|
109
|
+
error '/', 'Has 1 properties but needs at least 2.'
|
110
|
+
end
|
111
|
+
|
112
|
+
assert_validation({}) do
|
113
|
+
error '/', 'Has 0 properties but needs at least 2.'
|
114
|
+
end
|
115
|
+
|
116
|
+
assert_json(
|
117
|
+
type: :object,
|
118
|
+
minProperties: 2,
|
119
|
+
additionalProperties: true
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_max_properties
|
124
|
+
schema :hash, max_properties: 3, additional_properties: true
|
125
|
+
assert_validation(foo: :bar, bar: :baz)
|
126
|
+
assert_validation(foo: :bar, bar: :baz, baz: :foo)
|
127
|
+
|
128
|
+
assert_validation(foo: :bar, bar: :baz, baz: :foo, answer: 42) do
|
129
|
+
error '/', 'Has 4 properties but needs at most 3.'
|
130
|
+
end
|
131
|
+
|
132
|
+
assert_json(
|
133
|
+
type: :object,
|
134
|
+
maxProperties: 3,
|
135
|
+
additionalProperties: true
|
136
|
+
)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_min_max_properties
|
140
|
+
schema :hash, min_properties: 3, max_properties: 3, additional_properties: true
|
141
|
+
assert_validation(foo: :bar, bar: :baz, baz: :foo)
|
142
|
+
|
143
|
+
assert_validation(foo: :bar, bar: :baz, baz: :foo, answer: 42) do
|
144
|
+
error '/', 'Has 4 properties but needs at most 3.'
|
145
|
+
end
|
146
|
+
|
147
|
+
assert_validation(foo: :bar, bar: :baz) do
|
148
|
+
error '/', 'Has 2 properties but needs at least 3.'
|
149
|
+
end
|
150
|
+
|
151
|
+
assert_json(
|
152
|
+
type: :object,
|
153
|
+
minProperties: 3,
|
154
|
+
maxProperties: 3,
|
155
|
+
additionalProperties: true
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_dependencies
|
160
|
+
schema :hash do
|
161
|
+
str! :name
|
162
|
+
str? :credit_card
|
163
|
+
str? :billing_address
|
164
|
+
str? :phone_number
|
165
|
+
|
166
|
+
dep :credit_card, :billing_address, :phone_number
|
167
|
+
dep :billing_address, :credit_card
|
168
|
+
end
|
169
|
+
|
170
|
+
assert_validation(name: 'John')
|
171
|
+
assert_validation(name: 'John', credit_card: '23423523', billing_address: 'Example 3', phone_number: '234')
|
172
|
+
|
173
|
+
assert_validation(name: 'John', credit_card: '23423523') do
|
174
|
+
error '/', 'Missing property "billing_address" because "credit_card" is given.'
|
175
|
+
error '/', 'Missing property "phone_number" because "credit_card" is given.'
|
176
|
+
end
|
177
|
+
|
178
|
+
assert_validation(name: 'John', billing_address: 'Example 3') do
|
179
|
+
error '/', 'Missing property "credit_card" because "billing_address" is given.'
|
180
|
+
end
|
181
|
+
|
182
|
+
assert_json(
|
183
|
+
type: :object,
|
184
|
+
properties: {
|
185
|
+
name: { type: :string },
|
186
|
+
credit_card: { type: :string },
|
187
|
+
billing_address: { type: :string },
|
188
|
+
phone_number: { type: :string }
|
189
|
+
},
|
190
|
+
required: %i[name],
|
191
|
+
dependencies: {
|
192
|
+
credit_card: %i[billing_address phone_number],
|
193
|
+
billing_address: %i[credit_card]
|
194
|
+
},
|
195
|
+
additionalProperties: false
|
196
|
+
)
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_pattern_properties_wo_additional
|
200
|
+
schema additional_properties: false do
|
201
|
+
str! :name
|
202
|
+
str?(/^foo_.*$/)
|
203
|
+
int?(/^bar_.*$/)
|
204
|
+
end
|
205
|
+
|
206
|
+
assert_validation(name: 'John', foo_bar: 'John')
|
207
|
+
assert_validation(name: 'John', foo_bar: 'John', bar_baz: 42, foo_baz: '42')
|
208
|
+
assert_validation(name: 'John', foo_baz: 'John', bar_baz: 42)
|
209
|
+
|
210
|
+
assert_validation(name: 'John', xy: 'John', bar_baz: 'Doe') do
|
211
|
+
error '/', 'Obsolete property "xy".'
|
212
|
+
error '/bar_baz', 'Invalid type, expected "integer".'
|
213
|
+
end
|
214
|
+
|
215
|
+
assert_json(
|
216
|
+
type: :object,
|
217
|
+
properties: {
|
218
|
+
name: { type: :string }
|
219
|
+
},
|
220
|
+
patternProperties: {
|
221
|
+
'^foo_.*$': { type: :string },
|
222
|
+
'^bar_.*$': { type: :integer }
|
223
|
+
},
|
224
|
+
additionalProperties: false,
|
225
|
+
required: %i[name]
|
226
|
+
)
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_pattern_properties_w_additional
|
230
|
+
schema additional_properties: true do
|
231
|
+
int? :builtin
|
232
|
+
str?(/^S_/)
|
233
|
+
int?(/^I_/)
|
234
|
+
add :string
|
235
|
+
end
|
236
|
+
|
237
|
+
assert_validation(builtin: 42)
|
238
|
+
assert_validation(keyword: 'value')
|
239
|
+
|
240
|
+
assert_validation(keyword: 42) do
|
241
|
+
error '/keyword', 'Invalid type, expected "string".'
|
242
|
+
end
|
243
|
+
|
244
|
+
assert_json(
|
245
|
+
type: 'object',
|
246
|
+
properties: {
|
247
|
+
builtin: { type: :integer }
|
248
|
+
},
|
249
|
+
patternProperties: {
|
250
|
+
'^S_': { type: :string },
|
251
|
+
'^I_': { type: :integer }
|
252
|
+
},
|
253
|
+
additionalProperties: { type: :string }
|
254
|
+
)
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_defaults
|
258
|
+
schema do
|
259
|
+
str? :first_name, default: 'John'
|
260
|
+
str? :last_name, default: 'Doe'
|
261
|
+
str! :active, format: :boolean
|
262
|
+
hsh? :address, default: {} do
|
263
|
+
str? :street, default: 'Example 42'
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
data = { last_name: 'Doeringer', active: 'true' }
|
268
|
+
data_was = data.dup
|
269
|
+
|
270
|
+
assert_equal({ first_name: 'John', last_name: 'Doeringer', active: true, address: { street: 'Example 42' } }, @schema.validate(data).data)
|
271
|
+
assert_equal data_was, data
|
272
|
+
|
273
|
+
schema do
|
274
|
+
hsh? :address do
|
275
|
+
str? :street, default: 'Example 42'
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
assert_equal({}, @schema.validate({}).data)
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_all_of
|
283
|
+
schema do
|
284
|
+
all_of! :str do
|
285
|
+
str min_length: 3
|
286
|
+
str max_length: 5
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
assert_validation(str: '123')
|
291
|
+
assert_validation(str: '1234')
|
292
|
+
assert_validation(str: '12345')
|
293
|
+
assert_validation(str: '0') do
|
294
|
+
error '/str', 'Does not match all allOf conditions.'
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_one_of_required
|
299
|
+
schema do
|
300
|
+
one_of! :str do
|
301
|
+
str min_length: 4
|
302
|
+
str min_length: 0, max_length: 4
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
assert_validation(str: '12345')
|
307
|
+
assert_validation(str: '123')
|
308
|
+
assert_validation(str: nil) do
|
309
|
+
error '/str', 'Value must be given.'
|
310
|
+
end
|
311
|
+
assert_validation(str: '1234') do
|
312
|
+
error '/str', 'Matches 2 definitions but should match exactly 1.'
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_one_of_optional
|
317
|
+
schema do
|
318
|
+
one_of? :str do
|
319
|
+
str min_length: 4
|
320
|
+
str min_length: 0, max_length: 4
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
assert_validation(str: '12345')
|
325
|
+
assert_validation(str: '123')
|
326
|
+
assert_validation(str: nil)
|
327
|
+
assert_validation({})
|
328
|
+
assert_validation(str: '1234') do
|
329
|
+
error '/str', 'Matches 2 definitions but should match exactly 1.'
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
def test_any_of_required
|
334
|
+
schema do
|
335
|
+
any_of! :str_or_int do
|
336
|
+
str
|
337
|
+
int
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
assert_validation(str_or_int: 'Hello World')
|
342
|
+
assert_validation(str_or_int: 42)
|
343
|
+
assert_validation(str_or_int: :foo) do
|
344
|
+
error '/str_or_int', 'Does not match any anyOf condition.'
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_any_of_optional
|
349
|
+
schema do
|
350
|
+
any_of? :str_or_int do
|
351
|
+
str
|
352
|
+
int
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
assert_validation(str_or_int: 'Hello World')
|
357
|
+
assert_validation(str_or_int: 42)
|
358
|
+
assert_validation(str_or_int: nil)
|
359
|
+
assert_validation({})
|
360
|
+
assert_validation(str_or_int: :foo) do
|
361
|
+
error '/str_or_int', 'Does not match any anyOf condition.'
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def test_is_not_required
|
366
|
+
schema do
|
367
|
+
is_not! :foo, required: true do
|
368
|
+
str
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
assert_validation(foo: 42)
|
373
|
+
assert_validation(foo: true)
|
374
|
+
assert_validation(foo: { bar: :baz })
|
375
|
+
assert_validation(foo: nil) do
|
376
|
+
error '/foo', 'Value must be given.'
|
377
|
+
end
|
378
|
+
assert_validation(foo: 'string') do
|
379
|
+
error '/foo', 'Must not match schema: {"type"=>"string"}.'
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_is_not_optional
|
384
|
+
schema do
|
385
|
+
is_not? :foo do
|
386
|
+
str
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
assert_validation(foo: 42)
|
391
|
+
assert_validation(foo: true)
|
392
|
+
assert_validation(foo: { bar: :baz })
|
393
|
+
assert_validation(foo: nil)
|
394
|
+
assert_validation(foo: 'string') do
|
395
|
+
error '/foo', 'Must not match schema: {"type"=>"string"}.'
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Helper function that checks for all the options if the option is
|
400
|
+
# an integer or something else, in which case it needs to raise
|
401
|
+
def validate_self_should_error(value_to_check)
|
402
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
403
|
+
'Option "min_properties" must be an "integer"' do
|
404
|
+
schema :hash, min_properties: value_to_check
|
405
|
+
end
|
406
|
+
|
407
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
408
|
+
'Option "max_properties" must be an "integer"' do
|
409
|
+
schema :hash, max_properties: value_to_check
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
def test_validate_self
|
414
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
415
|
+
'Pattern properties can\'t be required.' do
|
416
|
+
schema :hash do
|
417
|
+
str!(/[a-z]+/)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
validate_self_should_error(1.0)
|
422
|
+
validate_self_should_error(4r)
|
423
|
+
validate_self_should_error(true)
|
424
|
+
validate_self_should_error(false)
|
425
|
+
validate_self_should_error((4 + 6i))
|
426
|
+
validate_self_should_error('13')
|
427
|
+
validate_self_should_error('Lorem ipsum')
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_doc_example
|
431
|
+
schema :hash do
|
432
|
+
scm :address do
|
433
|
+
str! :street
|
434
|
+
int! :number
|
435
|
+
str! :zip
|
436
|
+
end
|
437
|
+
int? :id
|
438
|
+
str! :name
|
439
|
+
ref! :address, :address
|
440
|
+
ary! :additional_addresses, default: [] do
|
441
|
+
ref :address
|
442
|
+
end
|
443
|
+
ary? :comments, :array, default: [] do
|
444
|
+
str
|
445
|
+
end
|
446
|
+
hsh! :jobs, min_properties: 1 do
|
447
|
+
str?(/^[0-9]+$/)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
assert_validation(
|
452
|
+
id: 42,
|
453
|
+
name: 'John Doe',
|
454
|
+
address: {
|
455
|
+
street: 'Silver Street',
|
456
|
+
number: 4,
|
457
|
+
zip: '38234C'
|
458
|
+
},
|
459
|
+
additional_addresses: [
|
460
|
+
{ street: 'Example street', number: 42, zip: '8048' }
|
461
|
+
],
|
462
|
+
comments: [
|
463
|
+
'This is a comment'
|
464
|
+
],
|
465
|
+
jobs: {
|
466
|
+
2020 => 'Software Engineer'
|
467
|
+
}
|
468
|
+
)
|
469
|
+
end
|
470
|
+
|
471
|
+
def test_cast_without_additional
|
472
|
+
schema :hash do
|
473
|
+
str! :foo, format: :integer
|
474
|
+
end
|
475
|
+
|
476
|
+
assert_validation(nil)
|
477
|
+
assert_validation(foo: '1')
|
478
|
+
assert_cast({ foo: '1' }, { foo: 1 })
|
479
|
+
|
480
|
+
assert_validation(foo: '1', bar: '2') do
|
481
|
+
error '/', 'Obsolete property "bar".'
|
482
|
+
end
|
483
|
+
|
484
|
+
assert_json(
|
485
|
+
type: 'object',
|
486
|
+
properties: {
|
487
|
+
foo: {
|
488
|
+
type: :string,
|
489
|
+
format: :integer
|
490
|
+
}
|
491
|
+
},
|
492
|
+
additionalProperties: false,
|
493
|
+
required: %i[foo]
|
494
|
+
)
|
495
|
+
end
|
496
|
+
|
497
|
+
def test_cast_with_additional
|
498
|
+
schema :hash, additional_properties: true do
|
499
|
+
str! :foo, format: :integer
|
500
|
+
end
|
501
|
+
|
502
|
+
assert_validation(nil)
|
503
|
+
assert_validation(foo: '1')
|
504
|
+
assert_cast({ foo: '1' }, { foo: 1 })
|
505
|
+
|
506
|
+
assert_validation(foo: '1', bar: nil)
|
507
|
+
assert_validation(foo: '1', bar: '2')
|
508
|
+
assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' })
|
509
|
+
|
510
|
+
assert_json(
|
511
|
+
type: 'object',
|
512
|
+
properties: {
|
513
|
+
foo: {
|
514
|
+
type: :string,
|
515
|
+
format: :integer
|
516
|
+
}
|
517
|
+
},
|
518
|
+
additionalProperties: true,
|
519
|
+
required: %i[foo]
|
520
|
+
)
|
521
|
+
end
|
522
|
+
|
523
|
+
def test_multiple_add_in_schema
|
524
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
525
|
+
'You can only use "add" once to specify additional properties.' do
|
526
|
+
schema :hash do
|
527
|
+
add :integer
|
528
|
+
add :string
|
529
|
+
end
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
def test_cast_with_additional_in_block
|
534
|
+
schema :hash do
|
535
|
+
str! :foo, format: :integer
|
536
|
+
add :string
|
537
|
+
end
|
538
|
+
|
539
|
+
assert_validation(nil)
|
540
|
+
assert_validation(foo: '1')
|
541
|
+
assert_cast({ foo: '1' }, { foo: 1 })
|
542
|
+
|
543
|
+
assert_validation(foo: '1', bar: nil)
|
544
|
+
assert_validation(foo: '1', bar: '2')
|
545
|
+
assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' })
|
546
|
+
|
547
|
+
assert_json(
|
548
|
+
type: 'object',
|
549
|
+
properties: {
|
550
|
+
foo: {
|
551
|
+
type: :string,
|
552
|
+
format: :integer
|
553
|
+
}
|
554
|
+
},
|
555
|
+
additionalProperties: { type: :string },
|
556
|
+
required: %i[foo]
|
557
|
+
)
|
558
|
+
end
|
559
|
+
|
560
|
+
def test_cast_with_additional_in_block_with_casting
|
561
|
+
schema :hash do
|
562
|
+
str! :foo, format: :integer
|
563
|
+
add :string, format: :integer
|
564
|
+
end
|
565
|
+
|
566
|
+
assert_validation(nil)
|
567
|
+
assert_validation(foo: '1')
|
568
|
+
assert_cast({ foo: '1' }, { foo: 1 })
|
569
|
+
|
570
|
+
assert_validation(foo: '1', bar: nil)
|
571
|
+
assert_validation(foo: '1', bar: '2')
|
572
|
+
assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: 2 })
|
573
|
+
end
|
574
|
+
|
575
|
+
def test_cast_with_additional_any_of
|
576
|
+
schema :hash do
|
577
|
+
str! :foo, format: :integer
|
578
|
+
add :any_of do
|
579
|
+
str
|
580
|
+
int
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
assert_validation(nil)
|
585
|
+
assert_validation(foo: '1')
|
586
|
+
assert_cast({ foo: '1' }, { foo: 1 })
|
587
|
+
|
588
|
+
assert_validation(foo: '1', bar: nil)
|
589
|
+
assert_validation(foo: '1', bar: '2')
|
590
|
+
assert_validation(foo: '1', bar: '2', baz: 3)
|
591
|
+
assert_validation(foo: '1', bar: '2', baz: 3, qux: [1, 2]) do
|
592
|
+
error '/qux', 'Does not match any anyOf condition.'
|
593
|
+
end
|
594
|
+
|
595
|
+
assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' })
|
596
|
+
|
597
|
+
assert_json(
|
598
|
+
type: 'object',
|
599
|
+
properties: {
|
600
|
+
foo: {
|
601
|
+
type: :string,
|
602
|
+
format: :integer
|
603
|
+
}
|
604
|
+
},
|
605
|
+
additionalProperties: {
|
606
|
+
anyOf: [
|
607
|
+
{ type: :string },
|
608
|
+
{ type: :integer }
|
609
|
+
]
|
610
|
+
},
|
611
|
+
required: %i[foo]
|
612
|
+
)
|
613
|
+
end
|
614
|
+
|
615
|
+
def test_cast_with_additional_any_of_with_casting
|
616
|
+
schema :hash do
|
617
|
+
str! :foo, format: :integer
|
618
|
+
add :any_of do
|
619
|
+
str format: :integer
|
620
|
+
str format: :date
|
621
|
+
int
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
assert_validation(nil)
|
626
|
+
assert_validation(foo: '1')
|
627
|
+
assert_cast({ foo: '1' }, { foo: 1 })
|
628
|
+
|
629
|
+
assert_validation(foo: '1', bar: nil)
|
630
|
+
assert_validation(foo: '1', bar: '2')
|
631
|
+
assert_validation(foo: '1', bar: '2', baz: 3)
|
632
|
+
assert_validation(foo: '1', bar: '2', baz: 3, qux: [1, 2]) do
|
633
|
+
error '/qux', 'Does not match any anyOf condition.'
|
634
|
+
end
|
635
|
+
|
636
|
+
assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: 2 })
|
637
|
+
assert_cast({ foo: '1', bar: '2', qux: '2020-01-13', asd: 1 }, { foo: 1, bar: 2, qux: Date.new(2020, 1, 13), asd: 1 })
|
638
|
+
|
639
|
+
assert_json(
|
640
|
+
type: 'object',
|
641
|
+
properties: {
|
642
|
+
foo: {
|
643
|
+
type: :string,
|
644
|
+
format: :integer
|
645
|
+
}
|
646
|
+
},
|
647
|
+
additionalProperties: {
|
648
|
+
anyOf: [
|
649
|
+
{
|
650
|
+
type: :string,
|
651
|
+
format: :integer
|
652
|
+
},
|
653
|
+
{
|
654
|
+
type: :string,
|
655
|
+
format: :date
|
656
|
+
},
|
657
|
+
{
|
658
|
+
type: :integer
|
659
|
+
}
|
660
|
+
]
|
661
|
+
},
|
662
|
+
required: %i[foo]
|
663
|
+
)
|
664
|
+
end
|
665
|
+
|
666
|
+
def test_enum_schema
|
667
|
+
schema :hash do
|
668
|
+
str! :foo, enum: ['bar', 'qux', 123, :faz]
|
669
|
+
end
|
670
|
+
|
671
|
+
assert_json({
|
672
|
+
type: :object,
|
673
|
+
additionalProperties: false,
|
674
|
+
properties: {
|
675
|
+
foo: {
|
676
|
+
type: :string,
|
677
|
+
enum: ['bar', 'qux', 123, :faz]
|
678
|
+
}
|
679
|
+
},
|
680
|
+
required: [:foo]
|
681
|
+
})
|
682
|
+
|
683
|
+
assert_validation(nil)
|
684
|
+
assert_validation({ foo: 'bar' })
|
685
|
+
assert_validation({ foo: 'qux' })
|
686
|
+
|
687
|
+
# Even we put those types in the enum, they need to fail the validations,
|
688
|
+
# as they are not strings
|
689
|
+
assert_validation({ foo: 123 }) do
|
690
|
+
error '/foo', 'Invalid type, expected "string".'
|
691
|
+
end
|
692
|
+
assert_validation({ foo: :faz }) do
|
693
|
+
error '/foo', 'Invalid type, expected "string".'
|
694
|
+
end
|
695
|
+
|
696
|
+
# These need to fail validation, as they are not in the enum list
|
697
|
+
assert_validation({ foo: 'Lorem ipsum' }) do
|
698
|
+
error '/foo', 'Value not included in enum ["bar", "qux", 123, :faz].'
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
def test_with_generic_keywords
|
703
|
+
schema :hash, title: 'Hash', description: 'A hash with a description' do
|
704
|
+
str! :foo,
|
705
|
+
enum: ['bar', 'qux', 123, :faz],
|
706
|
+
title: 'A string',
|
707
|
+
description: 'A string in the hash',
|
708
|
+
examples: [
|
709
|
+
'foo'
|
710
|
+
]
|
711
|
+
end
|
712
|
+
|
713
|
+
assert_json({
|
714
|
+
type: :object,
|
715
|
+
additionalProperties: false,
|
716
|
+
title: 'Hash',
|
717
|
+
description: 'A hash with a description',
|
718
|
+
properties: {
|
719
|
+
foo: {
|
720
|
+
type: :string,
|
721
|
+
enum: ['bar', 'qux', 123, :faz],
|
722
|
+
title: 'A string',
|
723
|
+
examples: ['foo'],
|
724
|
+
description: 'A string in the hash'
|
725
|
+
}
|
726
|
+
},
|
727
|
+
required: [:foo]
|
728
|
+
})
|
729
|
+
end
|
730
|
+
|
731
|
+
def test_hash_with_indifferent_access
|
732
|
+
schema :hash do
|
733
|
+
str! :foo
|
734
|
+
int? :bar
|
735
|
+
add :symbol
|
736
|
+
end
|
737
|
+
|
738
|
+
# Test with symbol notation
|
739
|
+
hash = ActiveSupport::HashWithIndifferentAccess.new
|
740
|
+
|
741
|
+
assert_validation(hash) do
|
742
|
+
error '/foo', 'Value must be given.'
|
743
|
+
end
|
744
|
+
hash[:foo] = 'Foo'
|
745
|
+
assert_validation(hash)
|
746
|
+
hash[:bar] = 123
|
747
|
+
assert_validation(hash)
|
748
|
+
hash[:qux] = :ruby
|
749
|
+
assert_validation(hash)
|
750
|
+
|
751
|
+
# Test with string notation
|
752
|
+
hash = ActiveSupport::HashWithIndifferentAccess.new
|
753
|
+
|
754
|
+
assert_validation(hash) do
|
755
|
+
error '/foo', 'Value must be given.'
|
756
|
+
end
|
757
|
+
hash['foo'] = 'Foo'
|
758
|
+
assert_validation(hash)
|
759
|
+
hash['bar'] = 123
|
760
|
+
assert_validation(hash)
|
761
|
+
hash['qux'] = :ruby
|
762
|
+
assert_validation(hash)
|
763
|
+
end
|
764
|
+
|
765
|
+
def test_invalid_schema
|
766
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
767
|
+
'Child nodes must have a name.' do
|
768
|
+
schema :hash do
|
769
|
+
int!
|
770
|
+
end
|
771
|
+
end
|
772
|
+
end
|
773
|
+
end
|
774
|
+
end
|
775
|
+
end
|