json_model_rb 0.1.1
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +0 -0
- data/lib/json_model/config/options.rb +29 -0
- data/lib/json_model/config.rb +43 -0
- data/lib/json_model/errors/error.rb +7 -0
- data/lib/json_model/errors/invalid_ref_mode_error.rb +12 -0
- data/lib/json_model/errors/unknown_attribute_error.rb +13 -0
- data/lib/json_model/errors.rb +5 -0
- data/lib/json_model/properties.rb +66 -0
- data/lib/json_model/property.rb +54 -0
- data/lib/json_model/ref_mode.rb +9 -0
- data/lib/json_model/schema.rb +111 -0
- data/lib/json_model/schema_meta.rb +60 -0
- data/lib/json_model/type_spec/array.rb +62 -0
- data/lib/json_model/type_spec/composition/all_of.rb +15 -0
- data/lib/json_model/type_spec/composition/any_of.rb +15 -0
- data/lib/json_model/type_spec/composition/one_of.rb +15 -0
- data/lib/json_model/type_spec/composition.rb +32 -0
- data/lib/json_model/type_spec/enum.rb +33 -0
- data/lib/json_model/type_spec/object.rb +24 -0
- data/lib/json_model/type_spec/primitive/boolean.rb +13 -0
- data/lib/json_model/type_spec/primitive/integer.rb +21 -0
- data/lib/json_model/type_spec/primitive/null.rb +13 -0
- data/lib/json_model/type_spec/primitive/number.rb +14 -0
- data/lib/json_model/type_spec/primitive/numeric.rb +83 -0
- data/lib/json_model/type_spec/primitive/string.rb +150 -0
- data/lib/json_model/type_spec/primitive.rb +26 -0
- data/lib/json_model/type_spec.rb +67 -0
- data/lib/json_model/types/all_of.rb +26 -0
- data/lib/json_model/types/any_of.rb +26 -0
- data/lib/json_model/types/array.rb +26 -0
- data/lib/json_model/types/boolean.rb +7 -0
- data/lib/json_model/types/enum.rb +23 -0
- data/lib/json_model/types/one_of.rb +26 -0
- data/lib/json_model/types.rb +8 -0
- data/lib/json_model/version.rb +5 -0
- data/lib/json_model.rb +31 -0
- data/spec/config_spec.rb +106 -0
- data/spec/json_model_spec.rb +7 -0
- data/spec/properties_spec.rb +76 -0
- data/spec/property_spec.rb +86 -0
- data/spec/schema_meta_spec.rb +78 -0
- data/spec/schema_spec.rb +218 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/type_spec/array_spec.rb +206 -0
- data/spec/type_spec/composition/all_of_spec.rb +20 -0
- data/spec/type_spec/composition/any_of_spec.rb +20 -0
- data/spec/type_spec/composition/one_of_spec.rb +20 -0
- data/spec/type_spec/composition_spec.rb +90 -0
- data/spec/type_spec/enum_spec.rb +93 -0
- data/spec/type_spec/primitive/boolean_spec.rb +12 -0
- data/spec/type_spec/primitive/integer_spec.rb +57 -0
- data/spec/type_spec/primitive/null_spec.rb +12 -0
- data/spec/type_spec/primitive/number_spec.rb +12 -0
- data/spec/type_spec/primitive/numeric_spec.rb +176 -0
- data/spec/type_spec/primitive/string_spec.rb +119 -0
- data/spec/type_spec_spec.rb +32 -0
- metadata +183 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Composition::AnyOf) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('returns an any of schema') do
|
|
8
|
+
expect(
|
|
9
|
+
described_class.new(JsonModel::TypeSpec::Primitive::String.new).as_schema,
|
|
10
|
+
)
|
|
11
|
+
.to(
|
|
12
|
+
eq(
|
|
13
|
+
{
|
|
14
|
+
anyOf: [{ type: 'string' }],
|
|
15
|
+
},
|
|
16
|
+
),
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Composition::OneOf) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('returns a one of schema') do
|
|
8
|
+
expect(
|
|
9
|
+
described_class.new(JsonModel::TypeSpec::Primitive::String.new).as_schema,
|
|
10
|
+
)
|
|
11
|
+
.to(
|
|
12
|
+
eq(
|
|
13
|
+
{
|
|
14
|
+
oneOf: [{ type: 'string' }],
|
|
15
|
+
},
|
|
16
|
+
),
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Composition) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('returns schema of complex types') do
|
|
8
|
+
expect(
|
|
9
|
+
described_class
|
|
10
|
+
.new(
|
|
11
|
+
:allOf,
|
|
12
|
+
JsonModel::TypeSpec::Primitive::String.new,
|
|
13
|
+
Class.new do
|
|
14
|
+
include(JsonModel::Schema)
|
|
15
|
+
|
|
16
|
+
property(:foo, type: String)
|
|
17
|
+
end,
|
|
18
|
+
)
|
|
19
|
+
.as_schema,
|
|
20
|
+
)
|
|
21
|
+
.to(
|
|
22
|
+
eq(
|
|
23
|
+
{
|
|
24
|
+
allOf: [
|
|
25
|
+
{ type: 'string' },
|
|
26
|
+
{
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: { foo: { type: 'string' } },
|
|
29
|
+
required: %i(foo),
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it('uses external references') do
|
|
38
|
+
expect(
|
|
39
|
+
described_class
|
|
40
|
+
.new(
|
|
41
|
+
:allOf,
|
|
42
|
+
Class.new do
|
|
43
|
+
include(JsonModel::Schema)
|
|
44
|
+
|
|
45
|
+
property(:foo, type: String)
|
|
46
|
+
schema_id('https://example.com/schemas/foo.json')
|
|
47
|
+
end,
|
|
48
|
+
)
|
|
49
|
+
.as_schema(ref_mode: JsonModel::RefMode::EXTERNAL),
|
|
50
|
+
)
|
|
51
|
+
.to(
|
|
52
|
+
eq(
|
|
53
|
+
{
|
|
54
|
+
allOf: [
|
|
55
|
+
{ '$ref': 'https://example.com/schemas/foo.json' },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it('uses local references') do
|
|
63
|
+
expect(
|
|
64
|
+
described_class
|
|
65
|
+
.new(
|
|
66
|
+
:allOf,
|
|
67
|
+
Class.new do
|
|
68
|
+
include(JsonModel::Schema)
|
|
69
|
+
|
|
70
|
+
property(:foo, type: String)
|
|
71
|
+
|
|
72
|
+
def self.name
|
|
73
|
+
'Foo'
|
|
74
|
+
end
|
|
75
|
+
end,
|
|
76
|
+
)
|
|
77
|
+
.as_schema(ref_mode: JsonModel::RefMode::LOCAL),
|
|
78
|
+
)
|
|
79
|
+
.to(
|
|
80
|
+
eq(
|
|
81
|
+
{
|
|
82
|
+
allOf: [
|
|
83
|
+
{ '$ref': '#/$defs/Foo' },
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Enum) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('returns an enum schema') do
|
|
8
|
+
expect(described_class.new(1, 'a').as_schema)
|
|
9
|
+
.to(
|
|
10
|
+
eq(
|
|
11
|
+
{
|
|
12
|
+
enum: [1, 'a'],
|
|
13
|
+
},
|
|
14
|
+
),
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe('.register_validations') do
|
|
20
|
+
let(:klass) do
|
|
21
|
+
Class.new do
|
|
22
|
+
include(ActiveModel::Validations)
|
|
23
|
+
|
|
24
|
+
attr_accessor(:foo)
|
|
25
|
+
|
|
26
|
+
def initialize(foo:)
|
|
27
|
+
@foo = foo
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context('for nil values') do
|
|
33
|
+
it('fails the validation if not allowed') do
|
|
34
|
+
described_class
|
|
35
|
+
.new(1)
|
|
36
|
+
.register_validations(:foo, klass)
|
|
37
|
+
instance = klass.new(foo: nil)
|
|
38
|
+
|
|
39
|
+
expect(instance.valid?)
|
|
40
|
+
.to(be(false))
|
|
41
|
+
expect(instance.errors.map(&:type))
|
|
42
|
+
.to(eq(%i(inclusion)))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it('succeeds the validation if allowed') do
|
|
46
|
+
described_class
|
|
47
|
+
.new(nil)
|
|
48
|
+
.register_validations(:foo, klass)
|
|
49
|
+
instance = klass.new(foo: nil)
|
|
50
|
+
|
|
51
|
+
expect(instance.valid?)
|
|
52
|
+
.to(be(true))
|
|
53
|
+
expect(instance.errors)
|
|
54
|
+
.to(be_empty)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context('for non-nil values') do
|
|
59
|
+
before do
|
|
60
|
+
described_class
|
|
61
|
+
.new(1, 'a')
|
|
62
|
+
.register_validations(:foo, klass)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it('fails the validation if nil') do
|
|
66
|
+
instance = klass.new(foo: nil)
|
|
67
|
+
|
|
68
|
+
expect(instance.valid?)
|
|
69
|
+
.to(be(false))
|
|
70
|
+
expect(instance.errors.map(&:type))
|
|
71
|
+
.to(eq(%i(inclusion)))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it('fails the validation if not allowed') do
|
|
75
|
+
instance = klass.new(foo: 0)
|
|
76
|
+
|
|
77
|
+
expect(instance.valid?)
|
|
78
|
+
.to(be(false))
|
|
79
|
+
expect(instance.errors.map(&:type))
|
|
80
|
+
.to(eq(%i(inclusion)))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it('succeeds the validation if allowed') do
|
|
84
|
+
instance = klass.new(foo: 'a')
|
|
85
|
+
|
|
86
|
+
expect(instance.valid?)
|
|
87
|
+
.to(be(true))
|
|
88
|
+
expect(instance.errors)
|
|
89
|
+
.to(be_empty)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Primitive::Boolean) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('returns a boolean schema') do
|
|
8
|
+
expect(subject.as_schema)
|
|
9
|
+
.to(eq({ type: 'boolean' }))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Primitive::Integer) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('returns an integer schema') do
|
|
8
|
+
expect(subject.as_schema)
|
|
9
|
+
.to(eq({ type: 'integer' }))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it('includes the multipleOf attribute') do
|
|
13
|
+
expect(described_class.new(multiple_of: 5).as_schema)
|
|
14
|
+
.to(eq({ type: 'integer', multipleOf: 5 }))
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe('.register_validations') do
|
|
19
|
+
let(:klass) do
|
|
20
|
+
Class.new do
|
|
21
|
+
include(ActiveModel::Validations)
|
|
22
|
+
|
|
23
|
+
attr_accessor(:foo)
|
|
24
|
+
|
|
25
|
+
def initialize(foo:)
|
|
26
|
+
@foo = foo
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context('for integer-ness') do
|
|
32
|
+
before do
|
|
33
|
+
described_class
|
|
34
|
+
.new
|
|
35
|
+
.register_validations(:foo, klass)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it('fails the validation for floats') do
|
|
39
|
+
instance = klass.new(foo: 1.234)
|
|
40
|
+
|
|
41
|
+
expect(instance.valid?)
|
|
42
|
+
.to(be(false))
|
|
43
|
+
expect(instance.errors.map(&:type))
|
|
44
|
+
.to(eq(%i(not_an_integer)))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it('succeeds the validation for integers') do
|
|
48
|
+
instance = klass.new(foo: 1234)
|
|
49
|
+
|
|
50
|
+
expect(instance.valid?)
|
|
51
|
+
.to(be(true))
|
|
52
|
+
expect(instance.errors)
|
|
53
|
+
.to(be_empty)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Primitive::Number) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('returns a number schema') do
|
|
8
|
+
expect(subject.as_schema)
|
|
9
|
+
.to(eq({ type: 'number' }))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Primitive::Numeric) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('includes the multipleOf attribute') do
|
|
8
|
+
expect(described_class.new('number', multiple_of: 5).as_schema)
|
|
9
|
+
.to(eq({ type: 'number', multipleOf: 5 }))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it('includes the minimum attribute') do
|
|
13
|
+
expect(described_class.new('number', minimum: 5).as_schema)
|
|
14
|
+
.to(eq({ type: 'number', minimum: 5 }))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it('includes the maximum attribute') do
|
|
18
|
+
expect(described_class.new('number', maximum: 5).as_schema)
|
|
19
|
+
.to(eq({ type: 'number', maximum: 5 }))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it('includes the exclusiveMinimum attribute') do
|
|
23
|
+
expect(described_class.new('number', exclusive_minimum: 5).as_schema)
|
|
24
|
+
.to(eq({ type: 'number', exclusiveMinimum: 5 }))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it('includes the exclusiveMaximum attribute') do
|
|
28
|
+
expect(described_class.new('number', exclusive_maximum: 5).as_schema)
|
|
29
|
+
.to(eq({ type: 'number', exclusiveMaximum: 5 }))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe('.register_validations') do
|
|
34
|
+
let(:klass) do
|
|
35
|
+
Class.new do
|
|
36
|
+
include(ActiveModel::Validations)
|
|
37
|
+
|
|
38
|
+
attr_accessor(:foo)
|
|
39
|
+
|
|
40
|
+
def initialize(foo:)
|
|
41
|
+
@foo = foo
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context('for multiple of') do
|
|
47
|
+
before do
|
|
48
|
+
described_class
|
|
49
|
+
.new('number', multiple_of: 5)
|
|
50
|
+
.register_validations(:foo, klass)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it('fails the validation for non-multiples') do
|
|
54
|
+
instance = klass.new(foo: 1234)
|
|
55
|
+
|
|
56
|
+
expect(instance.valid?)
|
|
57
|
+
.to(be(false))
|
|
58
|
+
expect(instance.errors.map(&:type))
|
|
59
|
+
.to(eq(%i(multiple_of)))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it('succeeds the validation for integers') do
|
|
63
|
+
instance = klass.new(foo: 12_345)
|
|
64
|
+
|
|
65
|
+
expect(instance.valid?)
|
|
66
|
+
.to(be(true))
|
|
67
|
+
expect(instance.errors)
|
|
68
|
+
.to(be_empty)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context('for minimum') do
|
|
73
|
+
before do
|
|
74
|
+
described_class
|
|
75
|
+
.new('number', minimum: 5)
|
|
76
|
+
.register_validations(:foo, klass)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it('fails the validation for invalid values') do
|
|
80
|
+
instance = klass.new(foo: 4)
|
|
81
|
+
|
|
82
|
+
expect(instance.valid?)
|
|
83
|
+
.to(be(false))
|
|
84
|
+
expect(instance.errors.map(&:type))
|
|
85
|
+
.to(eq(%i(greater_than_or_equal_to)))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it('succeeds the validation for valid values') do
|
|
89
|
+
instance = klass.new(foo: 5)
|
|
90
|
+
|
|
91
|
+
expect(instance.valid?)
|
|
92
|
+
.to(be(true))
|
|
93
|
+
expect(instance.errors)
|
|
94
|
+
.to(be_empty)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
context('for maximum') do
|
|
99
|
+
before do
|
|
100
|
+
described_class
|
|
101
|
+
.new('number', maximum: 5)
|
|
102
|
+
.register_validations(:foo, klass)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it('fails the validation for invalid values') do
|
|
106
|
+
instance = klass.new(foo: 6)
|
|
107
|
+
|
|
108
|
+
expect(instance.valid?)
|
|
109
|
+
.to(be(false))
|
|
110
|
+
expect(instance.errors.map(&:type))
|
|
111
|
+
.to(eq(%i(less_than_or_equal_to)))
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it('succeeds the validation for valid values') do
|
|
115
|
+
instance = klass.new(foo: 5)
|
|
116
|
+
|
|
117
|
+
expect(instance.valid?)
|
|
118
|
+
.to(be(true))
|
|
119
|
+
expect(instance.errors)
|
|
120
|
+
.to(be_empty)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context('for exclusive_minimum') do
|
|
125
|
+
before do
|
|
126
|
+
described_class
|
|
127
|
+
.new('number', exclusive_minimum: 5)
|
|
128
|
+
.register_validations(:foo, klass)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it('fails the validation for invalid values') do
|
|
132
|
+
instance = klass.new(foo: 5)
|
|
133
|
+
|
|
134
|
+
expect(instance.valid?)
|
|
135
|
+
.to(be(false))
|
|
136
|
+
expect(instance.errors.map(&:type))
|
|
137
|
+
.to(eq(%i(greater_than)))
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it('succeeds the validation for valid values') do
|
|
141
|
+
instance = klass.new(foo: 6)
|
|
142
|
+
|
|
143
|
+
expect(instance.valid?)
|
|
144
|
+
.to(be(true))
|
|
145
|
+
expect(instance.errors)
|
|
146
|
+
.to(be_empty)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
context('for exclusive_maximum') do
|
|
151
|
+
before do
|
|
152
|
+
described_class
|
|
153
|
+
.new('number', exclusive_maximum: 5)
|
|
154
|
+
.register_validations(:foo, klass)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it('fails the validation for invalid values') do
|
|
158
|
+
instance = klass.new(foo: 5)
|
|
159
|
+
|
|
160
|
+
expect(instance.valid?)
|
|
161
|
+
.to(be(false))
|
|
162
|
+
expect(instance.errors.map(&:type))
|
|
163
|
+
.to(eq(%i(less_than)))
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it('succeeds the validation for valid values') do
|
|
167
|
+
instance = klass.new(foo: 4)
|
|
168
|
+
|
|
169
|
+
expect(instance.valid?)
|
|
170
|
+
.to(be(true))
|
|
171
|
+
expect(instance.errors)
|
|
172
|
+
.to(be_empty)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec::Primitive::String) do
|
|
6
|
+
describe('#as_schema') do
|
|
7
|
+
it('returns a string schema') do
|
|
8
|
+
expect(subject.as_schema)
|
|
9
|
+
.to(eq({ type: 'string' }))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it('includes the minLength attribute') do
|
|
13
|
+
expect(described_class.new(min_length: 10).as_schema)
|
|
14
|
+
.to(eq({ type: 'string', minLength: 10 }))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it('includes the maxLength attribute') do
|
|
18
|
+
expect(described_class.new(max_length: 10).as_schema)
|
|
19
|
+
.to(eq({ type: 'string', maxLength: 10 }))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it('includes the pattern attribute') do
|
|
23
|
+
expect(described_class.new(pattern: /\A\w+\z/).as_schema)
|
|
24
|
+
.to(eq({ type: 'string', pattern: '\\A\\w+\\z' }))
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe('.register_validations') do
|
|
29
|
+
let(:klass) do
|
|
30
|
+
Class.new do
|
|
31
|
+
include(ActiveModel::Validations)
|
|
32
|
+
|
|
33
|
+
attr_accessor(:foo)
|
|
34
|
+
|
|
35
|
+
def initialize(foo:)
|
|
36
|
+
@foo = foo
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context('for min length') do
|
|
42
|
+
before do
|
|
43
|
+
described_class
|
|
44
|
+
.new(min_length: 3)
|
|
45
|
+
.register_validations(:foo, klass)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it('fails the validation for too short strings') do
|
|
49
|
+
instance = klass.new(foo: 'ba')
|
|
50
|
+
|
|
51
|
+
expect(instance.valid?)
|
|
52
|
+
.to(be(false))
|
|
53
|
+
expect(instance.errors.map(&:type))
|
|
54
|
+
.to(eq(%i(too_short)))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it('succeeds the validation for valid strings') do
|
|
58
|
+
instance = klass.new(foo: 'bar')
|
|
59
|
+
|
|
60
|
+
expect(instance.valid?)
|
|
61
|
+
.to(be(true))
|
|
62
|
+
expect(instance.errors)
|
|
63
|
+
.to(be_empty)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context('for max length') do
|
|
68
|
+
before do
|
|
69
|
+
described_class
|
|
70
|
+
.new(max_length: 2)
|
|
71
|
+
.register_validations(:foo, klass)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it('fails the validation for too short strings') do
|
|
75
|
+
instance = klass.new(foo: 'bar')
|
|
76
|
+
|
|
77
|
+
expect(instance.valid?)
|
|
78
|
+
.to(be(false))
|
|
79
|
+
expect(instance.errors.map(&:type))
|
|
80
|
+
.to(eq(%i(too_long)))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it('succeeds the validation for valid strings') do
|
|
84
|
+
instance = klass.new(foo: 'ba')
|
|
85
|
+
|
|
86
|
+
expect(instance.valid?)
|
|
87
|
+
.to(be(true))
|
|
88
|
+
expect(instance.errors)
|
|
89
|
+
.to(be_empty)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context('for a pattern') do
|
|
94
|
+
before do
|
|
95
|
+
described_class
|
|
96
|
+
.new(pattern: /\A\w+\z/)
|
|
97
|
+
.register_validations(:foo, klass)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it('fails the validation for an invalid value') do
|
|
101
|
+
instance = klass.new(foo: ' bar')
|
|
102
|
+
|
|
103
|
+
expect(instance.valid?)
|
|
104
|
+
.to(be(false))
|
|
105
|
+
expect(instance.errors.map(&:type))
|
|
106
|
+
.to(eq(%i(invalid)))
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it('succeeds the validation for valid strings') do
|
|
110
|
+
instance = klass.new(foo: 'bar')
|
|
111
|
+
|
|
112
|
+
expect(instance.valid?)
|
|
113
|
+
.to(be(true))
|
|
114
|
+
expect(instance.errors)
|
|
115
|
+
.to(be_empty)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require('spec_helper')
|
|
4
|
+
|
|
5
|
+
RSpec.describe(JsonModel::TypeSpec) do
|
|
6
|
+
describe('#resolve') do
|
|
7
|
+
shared_examples_for('primitive type') do |type:, expected_type:|
|
|
8
|
+
it("resolves to a primitive type spec for #{type}") do
|
|
9
|
+
expect(JsonModel::TypeSpec.resolve(type))
|
|
10
|
+
.to(be_a(expected_type))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
shared_examples_for('unsupported type') do |type|
|
|
15
|
+
it("raises an error for #{type}") do
|
|
16
|
+
expect { JsonModel::TypeSpec.resolve(type) }
|
|
17
|
+
.to(raise_error(ArgumentError))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it_behaves_like('primitive type', type: String, expected_type: JsonModel::TypeSpec::Primitive::String)
|
|
22
|
+
it_behaves_like('primitive type', type: Integer, expected_type: JsonModel::TypeSpec::Primitive::Integer)
|
|
23
|
+
it_behaves_like('primitive type', type: Float, expected_type: JsonModel::TypeSpec::Primitive::Number)
|
|
24
|
+
it_behaves_like('primitive type', type: TrueClass, expected_type: JsonModel::TypeSpec::Primitive::Boolean)
|
|
25
|
+
it_behaves_like('primitive type', type: FalseClass, expected_type: JsonModel::TypeSpec::Primitive::Boolean)
|
|
26
|
+
it_behaves_like('primitive type', type: JsonModel::TypeSpec::Primitive::String.new, expected_type: JsonModel::TypeSpec::Primitive::String)
|
|
27
|
+
|
|
28
|
+
it_behaves_like('unsupported type', Class.new)
|
|
29
|
+
it_behaves_like('unsupported type', Object.new)
|
|
30
|
+
it_behaves_like('unsupported type', nil)
|
|
31
|
+
end
|
|
32
|
+
end
|