schemacop 3.0.39 → 3.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 +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +87 -0
- data/Gemfile +1 -1
- data/README.md +8 -7
- data/README_V3.md +38 -5
- data/VERSION +1 -1
- data/lib/schemacop/schema3.rb +2 -2
- data/lib/schemacop/v2/node.rb +1 -1
- data/lib/schemacop/v2/validator/string_validator.rb +1 -1
- data/lib/schemacop/v3/any_of_node.rb +13 -0
- data/lib/schemacop/v3/array_node.rb +2 -3
- data/lib/schemacop/v3/global_context.rb +1 -1
- data/lib/schemacop/v3/hash_node.rb +23 -21
- data/lib/schemacop/v3/node.rb +5 -0
- data/lib/schemacop/v3/numeric_node.rb +2 -2
- data/lib/schemacop/v3/object_node.rb +1 -1
- data/lib/schemacop/v3/one_of_node.rb +16 -3
- data/lib/schemacop/v3/result.rb +14 -1
- data/lib/schemacop/v3/string_node.rb +32 -4
- data/lib/schemacop/v3.rb +32 -0
- data/lib/schemacop.rb +12 -9
- data/schemacop.gemspec +3 -3
- data/test/lib/test_helper.rb +7 -0
- data/test/unit/schemacop/v2/casting_test.rb +1 -1
- data/test/unit/schemacop/v2/custom_check_test.rb +2 -2
- data/test/unit/schemacop/v2/custom_if_test.rb +2 -2
- data/test/unit/schemacop/v3/any_of_node_test.rb +24 -0
- data/test/unit/schemacop/v3/array_node_test.rb +60 -1
- data/test/unit/schemacop/v3/binary_node_test.rb +8 -0
- data/test/unit/schemacop/v3/hash_node_test.rb +143 -1
- data/test/unit/schemacop/v3/integer_node_test.rb +15 -1
- data/test/unit/schemacop/v3/is_not_node_test.rb +12 -0
- data/test/unit/schemacop/v3/number_node_test.rb +1 -1
- data/test/unit/schemacop/v3/object_node_test.rb +8 -0
- data/test/unit/schemacop/v3/one_of_node_test.rb +61 -0
- data/test/unit/schemacop/v3/string_node_test.rb +250 -2
- metadata +3 -3
|
@@ -323,6 +323,10 @@ module Schemacop
|
|
|
323
323
|
error '/', 'String does not match format "integer".'
|
|
324
324
|
end
|
|
325
325
|
|
|
326
|
+
assert_validation "32\ntest" do
|
|
327
|
+
error '/', 'String does not match format "integer".'
|
|
328
|
+
end
|
|
329
|
+
|
|
326
330
|
assert_cast(nil, nil)
|
|
327
331
|
assert_cast('2234', 2234)
|
|
328
332
|
assert_cast('-1', -1)
|
|
@@ -516,9 +520,11 @@ module Schemacop
|
|
|
516
520
|
end
|
|
517
521
|
|
|
518
522
|
def test_format_custom
|
|
523
|
+
formatters_was = Schemacop.string_formatters.dup
|
|
524
|
+
|
|
519
525
|
Schemacop.register_string_formatter(
|
|
520
526
|
:integer_tuple_list,
|
|
521
|
-
pattern:
|
|
527
|
+
pattern: /\A(-?[0-9]+):(-?[0-9]+)(,(-?[0-9]+):(-?[0-9]+))*\z/,
|
|
522
528
|
handler: proc do |value|
|
|
523
529
|
value.split(',').map { |t| t.split(':').map(&:to_i) }
|
|
524
530
|
end
|
|
@@ -539,8 +545,55 @@ module Schemacop
|
|
|
539
545
|
error '/', 'String does not match format "integer-tuple-list".'
|
|
540
546
|
end
|
|
541
547
|
|
|
548
|
+
assert_validation "1:5\nsd sfdij soidf" do
|
|
549
|
+
error '/', 'String does not match format "integer-tuple-list".'
|
|
550
|
+
end
|
|
551
|
+
|
|
542
552
|
assert_cast nil, nil
|
|
543
553
|
assert_cast '1:2,3:4,5:-6', [[1, 2], [3, 4], [5, -6]]
|
|
554
|
+
ensure
|
|
555
|
+
Schemacop.string_formatters = formatters_was
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
# A format pattern must be anchored with \A and \z: ^ and $ match the
|
|
559
|
+
# start and the end of any line, so a multi-line string would pass the
|
|
560
|
+
# validation and be handed to the cast handler.
|
|
561
|
+
def test_format_multiline
|
|
562
|
+
values = {
|
|
563
|
+
date: '2020-01-13',
|
|
564
|
+
date_time: '2018-11-13T20:20:39Z',
|
|
565
|
+
time: '20:30:39Z',
|
|
566
|
+
email: 'support@example.com',
|
|
567
|
+
mailbox: '<support@example.com>',
|
|
568
|
+
boolean: 'true',
|
|
569
|
+
integer: '23425',
|
|
570
|
+
number: '2.34',
|
|
571
|
+
integer_list: '1,2,3',
|
|
572
|
+
ipv4: '192.168.0.1',
|
|
573
|
+
ipv4_cidr: '192.168.0.1/24',
|
|
574
|
+
ipv6: '2001:db8::1'
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
assert_equal Schemacop.string_formatters.reject { |_, f| f[:pattern].nil? }.keys.sort,
|
|
578
|
+
values.keys.map { |format| format.to_s.dasherize.to_sym }.sort,
|
|
579
|
+
'Every format with a pattern must be covered here'
|
|
580
|
+
|
|
581
|
+
values.each do |format, value|
|
|
582
|
+
name = format.to_s.dasherize.to_sym
|
|
583
|
+
|
|
584
|
+
schema :string, format: format
|
|
585
|
+
|
|
586
|
+
assert_validation value
|
|
587
|
+
|
|
588
|
+
["#{value}\nfoo", "foo\n#{value}", "#{value}\n"].each do |multiline|
|
|
589
|
+
refute Schemacop.string_formatters[name][:pattern].match?(multiline),
|
|
590
|
+
"Format #{name} matches the multi-line value #{multiline.inspect}"
|
|
591
|
+
|
|
592
|
+
assert_validation multiline do
|
|
593
|
+
error '/', "String does not match format #{name.to_s.inspect}."
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
end
|
|
544
597
|
end
|
|
545
598
|
|
|
546
599
|
def test_enum
|
|
@@ -653,7 +706,7 @@ module Schemacop
|
|
|
653
706
|
end
|
|
654
707
|
|
|
655
708
|
assert_raises_with_message Exceptions::InvalidSchemaError,
|
|
656
|
-
'Option "pattern" can\'t be parsed: end pattern '\
|
|
709
|
+
'Option "pattern" can\'t be parsed: end pattern ' \
|
|
657
710
|
'with unmatched parenthesis: /(abcde/.' do
|
|
658
711
|
schema :string, pattern: '(abcde'
|
|
659
712
|
end
|
|
@@ -750,6 +803,201 @@ module Schemacop
|
|
|
750
803
|
assert_cast("\t", "\t")
|
|
751
804
|
end
|
|
752
805
|
|
|
806
|
+
def test_encoding_single
|
|
807
|
+
schema :string, encoding: 'UTF-8'
|
|
808
|
+
|
|
809
|
+
assert_validation 'Hello World'
|
|
810
|
+
assert_validation ''
|
|
811
|
+
|
|
812
|
+
assert_validation 'Hello World'.encode('ASCII') do
|
|
813
|
+
error '/', 'String has encoding "US-ASCII" but must be "UTF-8".'
|
|
814
|
+
end
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
def test_encoding_multiple
|
|
818
|
+
schema :string, encoding: %w[UTF-8 US-ASCII]
|
|
819
|
+
|
|
820
|
+
assert_validation 'Hello World'
|
|
821
|
+
assert_validation 'Hello World'.encode('ASCII')
|
|
822
|
+
|
|
823
|
+
assert_validation 'Hello World'.encode('ISO-8859-1') do
|
|
824
|
+
error '/', 'String has encoding "ISO-8859-1" but must be "UTF-8" or "US-ASCII".'
|
|
825
|
+
end
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
def test_encoding_with_nil
|
|
829
|
+
schema :string, encoding: 'UTF-8'
|
|
830
|
+
|
|
831
|
+
assert_validation nil
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
def test_encoding_invalid_bytes
|
|
835
|
+
schema :string, encoding: 'UTF-8'
|
|
836
|
+
|
|
837
|
+
assert_validation invalid_string do
|
|
838
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
def test_encoding_invalid_bytes_without_specific_encoding
|
|
843
|
+
schema :string
|
|
844
|
+
|
|
845
|
+
assert_validation invalid_string do
|
|
846
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
847
|
+
end
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
def test_encoding_invalid_bytes_us_ascii
|
|
851
|
+
schema :string
|
|
852
|
+
|
|
853
|
+
assert_validation invalid_string('US-ASCII') do
|
|
854
|
+
error '/', 'String has invalid "US-ASCII" encoding.'
|
|
855
|
+
end
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
def test_encoding_invalid_bytes_and_encoding_mismatch
|
|
859
|
+
schema :string, encoding: 'UTF-8'
|
|
860
|
+
|
|
861
|
+
assert_validation invalid_string('US-ASCII') do
|
|
862
|
+
error '/', 'String has encoding "US-ASCII" but must be "UTF-8".'
|
|
863
|
+
error '/', 'String has invalid "US-ASCII" encoding.'
|
|
864
|
+
end
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
def test_encoding_invalid_bytes_with_format
|
|
868
|
+
schema :string, format: :integer
|
|
869
|
+
|
|
870
|
+
assert_validation invalid_string do
|
|
871
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
def test_encoding_invalid_bytes_with_format_options
|
|
876
|
+
schema :string, format: :integer, format_options: { minimum: 5 }
|
|
877
|
+
|
|
878
|
+
assert_validation invalid_string do
|
|
879
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
880
|
+
end
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
def test_encoding_invalid_bytes_with_format_without_pattern
|
|
884
|
+
schema :string, format: :symbol
|
|
885
|
+
|
|
886
|
+
assert_validation :foo.to_s
|
|
887
|
+
|
|
888
|
+
# The symbol formatter has no pattern to fail on, and its handler calls
|
|
889
|
+
# "to_sym", which raises on an invalid byte sequence.
|
|
890
|
+
assert_validation invalid_string do
|
|
891
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
892
|
+
end
|
|
893
|
+
end
|
|
894
|
+
|
|
895
|
+
def test_encoding_incompatible_with_pattern
|
|
896
|
+
schema :string, pattern: /^ü+$/
|
|
897
|
+
|
|
898
|
+
assert_validation 'üü'
|
|
899
|
+
assert_validation 'üü'.encode('ISO-8859-1') do
|
|
900
|
+
error '/', 'String does not match pattern "^ü+$".'
|
|
901
|
+
end
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
def test_encoding_incompatible_with_format
|
|
905
|
+
schema :string, format: :integer
|
|
906
|
+
|
|
907
|
+
assert_validation '42'
|
|
908
|
+
|
|
909
|
+
# UTF-16 is a dummy encoding and cannot be matched against a pattern in
|
|
910
|
+
# any other encoding, so the string does not match, valid as it looks.
|
|
911
|
+
assert_validation '42'.encode('UTF-16') do
|
|
912
|
+
error '/', 'String does not match format "integer".'
|
|
913
|
+
end
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
def test_encoding_invalid_bytes_with_pattern
|
|
917
|
+
schema :string, pattern: /\Aabc.*\z/
|
|
918
|
+
|
|
919
|
+
assert_validation invalid_string do
|
|
920
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
921
|
+
end
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
def test_encoding_invalid_bytes_with_allow_blank_false
|
|
925
|
+
schema :string, allow_blank: false
|
|
926
|
+
|
|
927
|
+
assert_validation invalid_string do
|
|
928
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
929
|
+
end
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
def test_encoding_incompatible_with_allow_blank_false
|
|
933
|
+
schema :string, allow_blank: false
|
|
934
|
+
|
|
935
|
+
assert_validation '42'.encode('UTF-16')
|
|
936
|
+
assert_validation ''.encode('UTF-16') do
|
|
937
|
+
error '/', 'String is blank but must not be blank!'
|
|
938
|
+
end
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
def test_encoding_binary_has_no_invalid_bytes
|
|
942
|
+
schema :string
|
|
943
|
+
|
|
944
|
+
# Every byte sequence is valid in ASCII-8BIT.
|
|
945
|
+
assert_validation invalid_string('ASCII-8BIT')
|
|
946
|
+
end
|
|
947
|
+
|
|
948
|
+
def test_encoding_invalid_bytes_with_length
|
|
949
|
+
schema :string, min_length: 20, max_length: 30
|
|
950
|
+
|
|
951
|
+
# The length checks do not decode the string, so they are still
|
|
952
|
+
# reported.
|
|
953
|
+
assert_validation invalid_string do
|
|
954
|
+
error '/', 'String is 7 characters long but must be at least 20.'
|
|
955
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
956
|
+
end
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
def test_encoding_incompatible_with_length
|
|
960
|
+
schema :string, max_length: 2
|
|
961
|
+
|
|
962
|
+
assert_validation '42'
|
|
963
|
+
|
|
964
|
+
# A dummy encoding has no characters, so "size" counts bytes.
|
|
965
|
+
assert_validation '42'.encode('UTF-16') do
|
|
966
|
+
error '/', 'String is 6 characters long but must be at most 2.'
|
|
967
|
+
end
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
def test_encoding_invalid_bytes_with_enum
|
|
971
|
+
schema :string, enum: ['foo']
|
|
972
|
+
|
|
973
|
+
assert_validation invalid_string do
|
|
974
|
+
error '/', 'Value not included in enum ["foo"].'
|
|
975
|
+
error '/', 'String has invalid "UTF-8" encoding.'
|
|
976
|
+
end
|
|
977
|
+
end
|
|
978
|
+
|
|
979
|
+
def test_encoding_validate_self
|
|
980
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
|
981
|
+
'Option "encoding" must be a string or an array of strings.' do
|
|
982
|
+
schema :string, encoding: 123
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
|
986
|
+
'Option "encoding" must be a string or an array of strings.' do
|
|
987
|
+
schema :string, encoding: [123]
|
|
988
|
+
end
|
|
989
|
+
|
|
990
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
|
991
|
+
'Option "encoding" contains unknown encoding "UNKNOWN-FOO".' do
|
|
992
|
+
schema :string, encoding: 'UNKNOWN-FOO'
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
assert_raises_with_message Exceptions::InvalidSchemaError,
|
|
996
|
+
'Option "encoding" contains unknown encoding "UNKNOWN-FOO".' do
|
|
997
|
+
schema :string, encoding: %w[UTF-8 UNKNOWN-FOO]
|
|
998
|
+
end
|
|
999
|
+
end
|
|
1000
|
+
|
|
753
1001
|
def test_empty_or_whitespace_string_blank_not_allowed
|
|
754
1002
|
schema :string, allow_blank: false
|
|
755
1003
|
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: schemacop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sitrox
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-09-08 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activesupport
|
|
@@ -164,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
164
164
|
- !ruby/object:Gem::Version
|
|
165
165
|
version: '0'
|
|
166
166
|
requirements: []
|
|
167
|
-
rubygems_version: 4.0.
|
|
167
|
+
rubygems_version: 4.0.8
|
|
168
168
|
specification_version: 4
|
|
169
169
|
summary: Schemacop validates ruby structures consisting of nested hashes and arrays
|
|
170
170
|
against simple schema definitions.
|