schemacop 3.0.0.rc1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -115,6 +115,43 @@ module Schemacop
115
115
  assert_equal expected_float, s.validate!(float_field: '')
116
116
  assert_equal expected_float, s.validate!(float_field: ' ')
117
117
  end
118
+
119
+ def test_float_to_integer
120
+ s = Schema.new do
121
+ req :foo, :integer, cast: [Float]
122
+ end
123
+
124
+ assert_equal({ foo: 42 }, s.validate!(foo: 42.0))
125
+ assert_equal({ foo: 42 }, s.validate!(foo: Float(42)))
126
+ end
127
+
128
+ def test_integer_to_float
129
+ s = Schema.new do
130
+ req :foo, :float, cast: [Integer]
131
+ end
132
+
133
+ assert_equal({ foo: 42.0 }, s.validate!(foo: 42))
134
+ assert_equal({ foo: 42.0 }, s.validate!(foo: Integer(42)))
135
+ end
136
+
137
+ def test_invalid_cast_option
138
+ s = Schema.new do
139
+ req :foo, :integer, cast: true
140
+ end
141
+
142
+ assert_raises Schemacop::Exceptions::InvalidSchemaError do
143
+ s.validate!({ foo: '42' })
144
+ end
145
+ end
146
+
147
+ def test_impossible_cast
148
+ s = Schema.new do
149
+ req :foo, :integer, cast: [String]
150
+ end
151
+
152
+ assert_equal({ foo: 42 }, s.validate!(foo: '42'))
153
+ assert_verr { s.validate!(foo: 'foo') }
154
+ end
118
155
  end
119
156
  end
120
157
  end
@@ -90,6 +90,17 @@ module Schemacop
90
90
  assert_verr { s.validate!(o: true) }
91
91
  assert_verr { s.validate!(r: nil, r_nil: false, o: true) }
92
92
  end
93
+
94
+ def test_invalid_hash
95
+ s = Schema.new do
96
+ type :hash do
97
+ req :foo
98
+ end
99
+ end
100
+
101
+ assert_verr { s.validate!({ foo: 42, 'foo' => 42 }) }
102
+ assert_nothing_raised { s.validate!({ foo: 42 }.with_indifferent_access) }
103
+ end
93
104
  end
94
105
  end
95
106
  end
@@ -142,8 +142,7 @@ module Schemacop
142
142
 
143
143
  assert_cast(
144
144
  { foo: '42', bar: '2020-01-15' },
145
- foo: 42,
146
- bar: Date.new(2020, 1, 15)
145
+ { foo: 42, bar: Date.new(2020, 1, 15) }.with_indifferent_access
147
146
  )
148
147
  end
149
148
 
@@ -133,11 +133,11 @@ module Schemacop
133
133
 
134
134
  assert_cast(
135
135
  { created_at: '2020-01-01' },
136
- created_at: Date.new(2020, 1, 1)
136
+ { created_at: Date.new(2020, 1, 1) }.with_indifferent_access
137
137
  )
138
138
  assert_cast(
139
139
  { created_at: '2020-01-01T17:38:20' },
140
- created_at: DateTime.new(2020, 1, 1, 17, 38, 20)
140
+ { created_at: DateTime.new(2020, 1, 1, 17, 38, 20) }.with_indifferent_access
141
141
  )
142
142
  end
143
143
 
@@ -158,12 +158,12 @@ module Schemacop
158
158
 
159
159
  assert_cast(
160
160
  { foo: { bar: nil } },
161
- foo: { bar: nil }
161
+ { foo: { bar: nil } }.with_indifferent_access
162
162
  )
163
163
 
164
164
  assert_cast(
165
165
  { foo: { baz: nil } },
166
- foo: { baz: 'Baz' }
166
+ { foo: { baz: 'Baz' } }.with_indifferent_access
167
167
  )
168
168
 
169
169
  schema do
@@ -175,12 +175,12 @@ module Schemacop
175
175
 
176
176
  assert_cast(
177
177
  { foo: { bar: '1990-01-13' } },
178
- foo: { bar: Date.new(1990, 1, 13) }
178
+ { foo: { bar: Date.new(1990, 1, 13) } }.with_indifferent_access
179
179
  )
180
180
 
181
181
  assert_cast(
182
182
  { foo: { bar: '1990-01-13T10:00:00Z' } },
183
- foo: { bar: DateTime.new(1990, 1, 13, 10, 0, 0) }
183
+ { foo: { bar: DateTime.new(1990, 1, 13, 10, 0, 0) } }.with_indifferent_access
184
184
  )
185
185
  end
186
186
 
@@ -446,8 +446,8 @@ module Schemacop
446
446
  end
447
447
 
448
448
  assert_cast(['foo', 42], ['foo', 42])
449
- assert_cast(['foo', 42, { foo: '1990-01-01' }], ['foo', 42, { foo: Date.new(1990, 1, 1) }])
450
- assert_cast(['foo', 42, { foo: '1990-01-01', bar: :baz }], ['foo', 42, { foo: Date.new(1990, 1, 1), bar: :baz }])
449
+ assert_cast(['foo', 42, { foo: '1990-01-01' }], ['foo', 42, { foo: Date.new(1990, 1, 1) }.with_indifferent_access])
450
+ assert_cast(['foo', 42, { foo: '1990-01-01', bar: :baz }], ['foo', 42, { foo: Date.new(1990, 1, 1), bar: :baz }.with_indifferent_access])
451
451
  end
452
452
 
453
453
  def test_multiple_add_in_schema
@@ -537,7 +537,7 @@ module Schemacop
537
537
  additionalItems: false
538
538
  )
539
539
 
540
- assert_cast [{}], [{ name: 'John' }]
540
+ assert_cast [{}], [{ name: 'John' }.with_indifferent_access]
541
541
  end
542
542
 
543
543
  def test_enum_schema
@@ -800,6 +800,16 @@ module Schemacop
800
800
 
801
801
  assert_cast(%w[foo 1990-01-01], ['foo', Date.new(1990, 1, 1)])
802
802
  end
803
+
804
+ def test_contains_multiple_should_fail
805
+ assert_raises_with_message Exceptions::InvalidSchemaError, 'You can only use "cont" once.' do
806
+ schema :array do
807
+ list :string
808
+ cont :string
809
+ cont :integer
810
+ end
811
+ end
812
+ end
803
813
  end
804
814
  end
805
815
  end
@@ -25,8 +25,10 @@ module Schemacop
25
25
 
26
26
  def test_schemas
27
27
  assert_equal({}, GlobalContext.instance.schemas)
28
+ assert_equal({}, GlobalContext.schemas)
28
29
  GlobalContext.instance.eager_load!
29
30
  assert_equal(%i[nested/group user], GlobalContext.instance.schemas.keys)
31
+ assert_equal(%i[nested/group user], GlobalContext.schemas.keys)
30
32
  assert_is_a Node, GlobalContext.instance.schemas.values.first
31
33
  end
32
34
 
@@ -16,7 +16,7 @@ module Schemacop
16
16
  assert_json(type: :object, additionalProperties: false)
17
17
  end
18
18
 
19
- def test_additional_properties_false
19
+ def test_additional_properties_false_by_default
20
20
  schema
21
21
  assert_validation({})
22
22
  assert_validation(foo: :bar, bar: :baz) do
@@ -26,6 +26,17 @@ module Schemacop
26
26
  assert_json(type: :object, additionalProperties: false)
27
27
  end
28
28
 
29
+ def test_additional_properties_false
30
+ schema :hash, additional_properties: false
31
+
32
+ assert_validation({})
33
+ assert_validation(foo: :bar, bar: :baz) do
34
+ error '/', 'Obsolete property "foo".'
35
+ error '/', 'Obsolete property "bar".'
36
+ end
37
+ assert_json(type: :object, additionalProperties: false)
38
+ end
39
+
29
40
  def test_additional_properties_true
30
41
  schema :hash, additional_properties: true
31
42
  assert_validation({})
@@ -54,6 +65,14 @@ module Schemacop
54
65
  type: :object,
55
66
  additionalProperties: { type: :string }
56
67
  )
68
+
69
+ assert_nothing_raised do
70
+ @schema.validate!({ foo: 'foo' })
71
+ end
72
+
73
+ assert_raises_with_message Exceptions::ValidationError, '/bar: Invalid type, expected "string".' do
74
+ @schema.validate!({ foo: 'foo', bar: :baz })
75
+ end
57
76
  end
58
77
 
59
78
  def test_property_names
@@ -72,8 +91,8 @@ module Schemacop
72
91
  propertyNames: '^[a-zA-Z0-9]+$'
73
92
  )
74
93
 
75
- assert_cast({ foo: 123 }, { foo: 123 })
76
- assert_cast({ Foo: 123 }, { Foo: 123 })
94
+ assert_cast({ foo: 123 }, { foo: 123 }.with_indifferent_access)
95
+ assert_cast({ Foo: 123 }, { Foo: 123 }.with_indifferent_access)
77
96
 
78
97
  # New schema
79
98
  schema :hash, additional_properties: true, property_names: '^[a-z]+$'
@@ -82,13 +101,13 @@ module Schemacop
82
101
  assert_validation(foo: :bar)
83
102
  assert_validation('foo' => 'bar')
84
103
  assert_validation(Foo: :bar) do
85
- error '/', 'Property name :Foo does not match "^[a-z]+$".'
104
+ error '/', 'Property name "Foo" does not match "^[a-z]+$".'
86
105
  end
87
106
  assert_validation('_foo39sjfdoi 345893(%' => 'bar', 'foo' => 'bar') do
88
107
  error '/', 'Property name "_foo39sjfdoi 345893(%" does not match "^[a-z]+$".'
89
108
  end
90
109
 
91
- assert_cast({ foo: 123 }, { foo: 123 })
110
+ assert_cast({ foo: 123 }, { foo: 123 }.with_indifferent_access)
92
111
  end
93
112
 
94
113
  def test_required
@@ -293,9 +312,9 @@ module Schemacop
293
312
  assert_validation({ id_foo: 1, id_bar: 2 })
294
313
  assert_validation({ id_foo: 1, id_bar: 2, value: 4 })
295
314
 
296
- assert_cast({ id_foo: 1 }, { id_foo: 1 })
297
- assert_cast({ id_foo: 1, id_bar: 2 }, { id_foo: 1, id_bar: 2 })
298
- assert_cast({ id_foo: 1, id_bar: 2, value: 4 }, { id_foo: 1, id_bar: 2, value: 4 })
315
+ assert_cast({ id_foo: 1 }, { id_foo: 1 }.with_indifferent_access)
316
+ assert_cast({ id_foo: 1, id_bar: 2 }, { id_foo: 1, id_bar: 2 }.with_indifferent_access)
317
+ assert_cast({ id_foo: 1, id_bar: 2, value: 4 }, { id_foo: 1, id_bar: 2, value: 4 }.with_indifferent_access)
299
318
  end
300
319
 
301
320
  def test_defaults
@@ -311,7 +330,9 @@ module Schemacop
311
330
  data = { last_name: 'Doeringer', active: 'true' }
312
331
  data_was = data.dup
313
332
 
314
- assert_equal({ first_name: 'John', last_name: 'Doeringer', active: true, address: { street: 'Example 42' } }, @schema.validate(data).data)
333
+ expected_data = { first_name: 'John', last_name: 'Doeringer', active: true, address: { street: 'Example 42' } }.with_indifferent_access
334
+
335
+ assert_equal(expected_data, @schema.validate(data).data)
315
336
  assert_equal data_was, data
316
337
 
317
338
  schema do
@@ -526,7 +547,7 @@ module Schemacop
526
547
 
527
548
  assert_validation(nil)
528
549
  assert_validation(foo: '1')
529
- assert_cast({ foo: '1' }, { foo: 1 })
550
+ assert_cast({ foo: '1' }, { foo: 1 }.with_indifferent_access)
530
551
 
531
552
  assert_validation(foo: '1', bar: '2') do
532
553
  error '/', 'Obsolete property "bar".'
@@ -552,11 +573,11 @@ module Schemacop
552
573
 
553
574
  assert_validation(nil)
554
575
  assert_validation(foo: '1')
555
- assert_cast({ foo: '1' }, { foo: 1 })
576
+ assert_cast({ foo: '1' }, { foo: 1 }.with_indifferent_access)
556
577
 
557
578
  assert_validation(foo: '1', bar: nil)
558
579
  assert_validation(foo: '1', bar: '2')
559
- assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' })
580
+ assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' }.with_indifferent_access)
560
581
 
561
582
  assert_json(
562
583
  type: 'object',
@@ -589,11 +610,11 @@ module Schemacop
589
610
 
590
611
  assert_validation(nil)
591
612
  assert_validation(foo: '1')
592
- assert_cast({ foo: '1' }, { foo: 1 })
613
+ assert_cast({ foo: '1' }, { foo: 1 }.with_indifferent_access)
593
614
 
594
615
  assert_validation(foo: '1', bar: nil)
595
616
  assert_validation(foo: '1', bar: '2')
596
- assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' })
617
+ assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' }.with_indifferent_access)
597
618
 
598
619
  assert_json(
599
620
  type: 'object',
@@ -616,11 +637,11 @@ module Schemacop
616
637
 
617
638
  assert_validation(nil)
618
639
  assert_validation(foo: '1')
619
- assert_cast({ foo: '1' }, { foo: 1 })
640
+ assert_cast({ foo: '1' }, { foo: 1 }.with_indifferent_access)
620
641
 
621
642
  assert_validation(foo: '1', bar: nil)
622
643
  assert_validation(foo: '1', bar: '2')
623
- assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: 2 })
644
+ assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: 2 }.with_indifferent_access)
624
645
  end
625
646
 
626
647
  def test_cast_with_additional_any_of
@@ -634,7 +655,7 @@ module Schemacop
634
655
 
635
656
  assert_validation(nil)
636
657
  assert_validation(foo: '1')
637
- assert_cast({ foo: '1' }, { foo: 1 })
658
+ assert_cast({ foo: '1' }, { foo: 1 }.with_indifferent_access)
638
659
 
639
660
  assert_validation(foo: '1', bar: nil)
640
661
  assert_validation(foo: '1', bar: '2')
@@ -643,7 +664,7 @@ module Schemacop
643
664
  error '/qux', 'Does not match any anyOf condition.'
644
665
  end
645
666
 
646
- assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' })
667
+ assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: '2' }.with_indifferent_access)
647
668
 
648
669
  assert_json(
649
670
  type: 'object',
@@ -675,7 +696,7 @@ module Schemacop
675
696
 
676
697
  assert_validation(nil)
677
698
  assert_validation(foo: '1')
678
- assert_cast({ foo: '1' }, { foo: 1 })
699
+ assert_cast({ foo: '1' }, { foo: 1 }.with_indifferent_access)
679
700
 
680
701
  assert_validation(foo: '1', bar: nil)
681
702
  assert_validation(foo: '1', bar: '2')
@@ -684,8 +705,8 @@ module Schemacop
684
705
  error '/qux', 'Does not match any anyOf condition.'
685
706
  end
686
707
 
687
- assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: 2 })
688
- assert_cast({ foo: '1', bar: '2', qux: '2020-01-13', asd: 1 }, { foo: 1, bar: 2, qux: Date.new(2020, 1, 13), asd: 1 })
708
+ assert_cast({ foo: '1', bar: '2' }, { foo: 1, bar: 2 }.with_indifferent_access)
709
+ assert_cast({ foo: '1', bar: '2', qux: '2020-01-13', asd: 1 }, { foo: 1, bar: 2, qux: Date.new(2020, 1, 13), asd: 1 }.with_indifferent_access)
689
710
 
690
711
  assert_json(
691
712
  type: 'object',
@@ -821,6 +842,131 @@ module Schemacop
821
842
  end
822
843
  end
823
844
  end
845
+
846
+ def test_schema_with_string_keys
847
+ schema :hash do
848
+ int! 'foo'
849
+ end
850
+
851
+ assert_validation(nil)
852
+ assert_validation({ 'foo' => 42 })
853
+ assert_validation({ foo: 42 })
854
+
855
+ assert_cast({ 'foo' => 42 }, { 'foo' => 42 })
856
+ assert_cast({ foo: 42 }, { foo: 42 }.with_indifferent_access)
857
+
858
+ assert_validation({}) do
859
+ error '/foo', 'Value must be given.'
860
+ end
861
+
862
+ assert_validation({ :foo => 42, 'foo' => 43 }) do
863
+ error '/', 'Has 1 ambiguous properties: [:foo].'
864
+ end
865
+ end
866
+
867
+ def test_schema_with_string_keys_in_data
868
+ schema :hash do
869
+ int! :foo
870
+ end
871
+
872
+ assert_validation(nil)
873
+ assert_validation({ 'foo' => 42 })
874
+ assert_validation({ foo: 42 })
875
+
876
+ assert_cast({ 'foo' => 42 }, { 'foo' => 42 })
877
+ assert_cast({ foo: 42 }, { foo: 42 }.with_indifferent_access)
878
+
879
+ assert_validation({}) do
880
+ error '/foo', 'Value must be given.'
881
+ end
882
+
883
+ assert_validation({ :foo => 42, 'foo' => 43 }) do
884
+ error '/', 'Has 1 ambiguous properties: [:foo].'
885
+ end
886
+ end
887
+
888
+ def test_invalid_options
889
+ assert_raises_with_message Schemacop::Exceptions::InvalidSchemaError, 'Options [:foo] are not allowed for this node.' do
890
+ schema :hash, foo: 'bar' do
891
+ int! :id
892
+ end
893
+ end
894
+ end
895
+
896
+ def test_casting_optional
897
+ schema :hash do
898
+ str? :foo, format: :integer
899
+ end
900
+
901
+ assert_validation(nil)
902
+ assert_validation({})
903
+
904
+ assert_cast(nil, nil)
905
+ assert_cast({}, {}.with_indifferent_access)
906
+ end
907
+
908
+ def test_as_option
909
+ schema :hash do
910
+ int! :foo, as: :bar
911
+ end
912
+
913
+ assert_validation(nil)
914
+ assert_validation({ foo: 42 })
915
+ assert_validation({ bar: 13 }) do
916
+ error '/', 'Obsolete property "bar".'
917
+ error '/foo', 'Value must be given.'
918
+ end
919
+
920
+ assert_validation({ foo: '13' }) do
921
+ error '/foo', 'Invalid type, expected "integer".'
922
+ end
923
+
924
+ assert_cast(nil, nil)
925
+ assert_cast({ foo: 42 }, { bar: 42 }.with_indifferent_access)
926
+ end
927
+
928
+ def test_as_option_overriding
929
+ schema :hash do
930
+ int? :foo, as: :bar
931
+ int? :bar
932
+ end
933
+
934
+ assert_validation(nil)
935
+ assert_validation({})
936
+ assert_validation({ foo: 42 })
937
+ assert_validation({ foo: 42, bar: 13 })
938
+
939
+ assert_validation({ foo: '13' }) do
940
+ error '/foo', 'Invalid type, expected "integer".'
941
+ end
942
+
943
+ # assert_cast(nil, nil)
944
+ assert_cast({ foo: 42 }, { bar: 42 }.with_indifferent_access)
945
+ assert_cast({ foo: 42, bar: 13 }, { bar: 13 }.with_indifferent_access)
946
+ assert_cast({ bar: 13, foo: 42 }, { bar: 13 }.with_indifferent_access)
947
+
948
+ # Swap order
949
+ schema :hash do
950
+ int? :bar
951
+ int! :foo, as: :bar
952
+ end
953
+
954
+ assert_validation(nil)
955
+ assert_validation({ foo: 42 })
956
+ assert_validation({ foo: 42, bar: 13 })
957
+ assert_validation({ bar: 13 }) do
958
+ error '/foo', 'Value must be given.'
959
+ end
960
+
961
+ assert_validation({ foo: '13' }) do
962
+ error '/foo', 'Invalid type, expected "integer".'
963
+ end
964
+
965
+ assert_cast(nil, nil)
966
+ assert_cast({ foo: 42 }, { bar: 42 }.with_indifferent_access)
967
+ assert_cast({ foo: 42, bar: 13 }, { bar: 42 }.with_indifferent_access)
968
+ assert_cast({ bar: 13, foo: 42 }, { bar: 42 }.with_indifferent_access)
969
+ end
824
970
  end
825
971
  end
826
972
  end