dry-validation 0.7.4 → 0.8.0

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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +9 -6
  4. data/CHANGELOG.md +58 -0
  5. data/Gemfile +3 -3
  6. data/benchmarks/benchmark_form_invalid.rb +64 -0
  7. data/benchmarks/benchmark_form_valid.rb +64 -0
  8. data/benchmarks/profile_schema_call_invalid.rb +20 -0
  9. data/benchmarks/profile_schema_call_valid.rb +20 -0
  10. data/benchmarks/profile_schema_definition.rb +14 -0
  11. data/benchmarks/profile_schema_messages_invalid.rb +20 -0
  12. data/benchmarks/suite.rb +5 -0
  13. data/config/errors.yml +12 -5
  14. data/dry-validation.gemspec +2 -2
  15. data/examples/basic.rb +2 -2
  16. data/examples/form.rb +2 -2
  17. data/examples/json.rb +2 -2
  18. data/examples/nested.rb +6 -6
  19. data/lib/dry/validation.rb +22 -3
  20. data/lib/dry/validation/deprecations.rb +23 -0
  21. data/lib/dry/validation/error_compiler.rb +31 -11
  22. data/lib/dry/validation/error_compiler/input.rb +44 -57
  23. data/lib/dry/validation/hint_compiler.rb +15 -7
  24. data/lib/dry/validation/input_processor_compiler.rb +13 -6
  25. data/lib/dry/validation/input_processor_compiler/form.rb +2 -0
  26. data/lib/dry/validation/input_processor_compiler/sanitizer.rb +1 -1
  27. data/lib/dry/validation/messages/abstract.rb +9 -1
  28. data/lib/dry/validation/predicate_registry.rb +101 -0
  29. data/lib/dry/validation/result.rb +8 -1
  30. data/lib/dry/validation/schema.rb +110 -44
  31. data/lib/dry/validation/schema/check.rb +4 -2
  32. data/lib/dry/validation/schema/deprecated.rb +31 -0
  33. data/lib/dry/validation/schema/dsl.rb +18 -11
  34. data/lib/dry/validation/schema/form.rb +1 -0
  35. data/lib/dry/validation/schema/json.rb +1 -0
  36. data/lib/dry/validation/schema/key.rb +23 -10
  37. data/lib/dry/validation/schema/rule.rb +81 -20
  38. data/lib/dry/validation/schema/value.rb +110 -25
  39. data/lib/dry/validation/version.rb +1 -1
  40. data/spec/fixtures/locales/en.yml +1 -0
  41. data/spec/fixtures/locales/pl.yml +1 -1
  42. data/spec/integration/custom_error_messages_spec.rb +2 -2
  43. data/spec/integration/custom_predicates_spec.rb +98 -15
  44. data/spec/integration/error_compiler_spec.rb +111 -96
  45. data/spec/integration/form/predicates/array_spec.rb +243 -0
  46. data/spec/integration/form/predicates/empty_spec.rb +263 -0
  47. data/spec/integration/form/predicates/eql_spec.rb +327 -0
  48. data/spec/integration/form/predicates/even_spec.rb +455 -0
  49. data/spec/integration/form/predicates/excluded_from_spec.rb +455 -0
  50. data/spec/integration/form/predicates/excludes_spec.rb +391 -0
  51. data/spec/integration/form/predicates/false_spec.rb +455 -0
  52. data/spec/integration/form/predicates/filled_spec.rb +467 -0
  53. data/spec/integration/form/predicates/format_spec.rb +454 -0
  54. data/spec/integration/form/predicates/gt_spec.rb +519 -0
  55. data/spec/integration/form/predicates/gteq_spec.rb +519 -0
  56. data/spec/integration/form/predicates/included_in_spec.rb +455 -0
  57. data/spec/integration/form/predicates/includes_spec.rb +391 -0
  58. data/spec/integration/form/predicates/key_spec.rb +75 -0
  59. data/spec/integration/form/predicates/lt_spec.rb +519 -0
  60. data/spec/integration/form/predicates/lteq_spec.rb +519 -0
  61. data/spec/integration/form/predicates/max_size_spec.rb +391 -0
  62. data/spec/integration/form/predicates/min_size_spec.rb +391 -0
  63. data/spec/integration/form/predicates/none_spec.rb +265 -0
  64. data/spec/integration/form/predicates/not_eql_spec.rb +327 -0
  65. data/spec/integration/form/predicates/odd_spec.rb +455 -0
  66. data/spec/integration/form/predicates/size/fixed_spec.rb +399 -0
  67. data/spec/integration/form/predicates/size/range_spec.rb +398 -0
  68. data/spec/integration/form/predicates/true_spec.rb +455 -0
  69. data/spec/integration/form/predicates/type_spec.rb +391 -0
  70. data/spec/integration/hints_spec.rb +90 -4
  71. data/spec/integration/injecting_rules_spec.rb +2 -2
  72. data/spec/integration/localized_error_messages_spec.rb +2 -2
  73. data/spec/integration/messages/i18n_spec.rb +3 -3
  74. data/spec/integration/optional_keys_spec.rb +3 -3
  75. data/spec/integration/schema/array_schema_spec.rb +49 -13
  76. data/spec/integration/schema/check_rules_spec.rb +6 -6
  77. data/spec/integration/schema/check_with_nested_el_spec.rb +3 -3
  78. data/spec/integration/schema/check_with_nth_el_spec.rb +1 -1
  79. data/spec/integration/schema/each_with_set_spec.rb +3 -3
  80. data/spec/integration/schema/extending_dsl_spec.rb +27 -0
  81. data/spec/integration/schema/form/explicit_types_spec.rb +182 -0
  82. data/spec/integration/schema/form_spec.rb +90 -18
  83. data/spec/integration/schema/hash_schema_spec.rb +47 -0
  84. data/spec/integration/schema/inheriting_schema_spec.rb +4 -4
  85. data/spec/integration/schema/input_processor_spec.rb +8 -8
  86. data/spec/integration/schema/json/explicit_types_spec.rb +157 -0
  87. data/spec/integration/schema/json_spec.rb +18 -18
  88. data/spec/integration/schema/macros/confirmation_spec.rb +1 -1
  89. data/spec/integration/schema/macros/each_spec.rb +177 -43
  90. data/spec/integration/schema/macros/{required_spec.rb → filled_spec.rb} +34 -6
  91. data/spec/integration/schema/macros/input_spec.rb +21 -0
  92. data/spec/integration/schema/macros/maybe_spec.rb +39 -2
  93. data/spec/integration/schema/macros/value_spec.rb +105 -0
  94. data/spec/integration/schema/macros/when_spec.rb +28 -8
  95. data/spec/integration/schema/nested_values_spec.rb +11 -8
  96. data/spec/integration/schema/not_spec.rb +2 -2
  97. data/spec/integration/schema/numbers_spec.rb +1 -1
  98. data/spec/integration/schema/option_with_default_spec.rb +1 -1
  99. data/spec/integration/schema/predicate_verification_spec.rb +9 -0
  100. data/spec/integration/schema/predicates/array_spec.rb +295 -0
  101. data/spec/integration/schema/predicates/custom_spec.rb +103 -0
  102. data/spec/integration/schema/predicates/empty_spec.rb +263 -0
  103. data/spec/integration/schema/predicates/eql_spec.rb +327 -0
  104. data/spec/integration/schema/predicates/even_spec.rb +455 -0
  105. data/spec/integration/schema/predicates/excluded_from_spec.rb +455 -0
  106. data/spec/integration/schema/predicates/excludes_spec.rb +391 -0
  107. data/spec/integration/schema/predicates/filled_spec.rb +467 -0
  108. data/spec/integration/schema/predicates/format_spec.rb +455 -0
  109. data/spec/integration/schema/predicates/gt_spec.rb +519 -0
  110. data/spec/integration/schema/predicates/gteq_spec.rb +519 -0
  111. data/spec/integration/schema/predicates/hash_spec.rb +69 -0
  112. data/spec/integration/schema/predicates/included_in_spec.rb +455 -0
  113. data/spec/integration/schema/predicates/includes_spec.rb +391 -0
  114. data/spec/integration/schema/predicates/key_spec.rb +88 -0
  115. data/spec/integration/schema/predicates/lt_spec.rb +520 -0
  116. data/spec/integration/schema/predicates/lteq_spec.rb +519 -0
  117. data/spec/integration/schema/predicates/max_size_spec.rb +391 -0
  118. data/spec/integration/schema/predicates/min_size_spec.rb +391 -0
  119. data/spec/integration/schema/predicates/none_spec.rb +265 -0
  120. data/spec/integration/schema/predicates/not_eql_spec.rb +391 -0
  121. data/spec/integration/schema/predicates/odd_spec.rb +455 -0
  122. data/spec/integration/schema/predicates/size/fixed_spec.rb +401 -0
  123. data/spec/integration/schema/predicates/size/range_spec.rb +399 -0
  124. data/spec/integration/schema/predicates/type_spec.rb +391 -0
  125. data/spec/integration/schema/reusing_schema_spec.rb +4 -4
  126. data/spec/integration/schema/using_types_spec.rb +24 -6
  127. data/spec/integration/schema/xor_spec.rb +2 -2
  128. data/spec/integration/schema_builders_spec.rb +15 -0
  129. data/spec/integration/schema_spec.rb +37 -12
  130. data/spec/shared/predicate_helper.rb +13 -0
  131. data/spec/spec_helper.rb +10 -0
  132. data/spec/support/matchers.rb +38 -0
  133. data/spec/support/predicates_integration.rb +7 -0
  134. data/spec/unit/hint_compiler_spec.rb +10 -8
  135. data/spec/unit/input_processor_compiler/form_spec.rb +45 -43
  136. data/spec/unit/input_processor_compiler/json_spec.rb +37 -35
  137. data/spec/unit/predicate_registry_spec.rb +34 -0
  138. data/spec/unit/schema/key_spec.rb +12 -14
  139. data/spec/unit/schema/rule_spec.rb +4 -2
  140. data/spec/unit/schema/value_spec.rb +38 -121
  141. metadata +150 -16
  142. data/lib/dry/validation/schema/attr.rb +0 -15
  143. data/spec/integration/attr_spec.rb +0 -122
@@ -1,8 +1,8 @@
1
- RSpec.describe 'Macros #required' do
1
+ RSpec.describe 'Macros #filled' do
2
2
  describe 'with no args' do
3
3
  subject(:schema) do
4
4
  Dry::Validation.Schema do
5
- key(:email).required
5
+ required(:email).filled
6
6
  end
7
7
  end
8
8
 
@@ -16,7 +16,7 @@ RSpec.describe 'Macros #required' do
16
16
  describe 'with a type specification' do
17
17
  subject(:schema) do
18
18
  Dry::Validation.Schema do
19
- key(:age).required(:int?)
19
+ required(:age).filled(:int?)
20
20
  end
21
21
  end
22
22
 
@@ -31,7 +31,7 @@ RSpec.describe 'Macros #required' do
31
31
  context 'with a flat arg' do
32
32
  subject(:schema) do
33
33
  Dry::Validation.Schema do
34
- key(:age).required(:int?, gt?: 18)
34
+ required(:age).filled(:int?, gt?: 18)
35
35
  end
36
36
  end
37
37
 
@@ -45,11 +45,39 @@ RSpec.describe 'Macros #required' do
45
45
  context 'with a range arg' do
46
46
  subject(:schema) do
47
47
  Dry::Validation.Schema do
48
- key(:age).required(:int?, size?: 18..24)
48
+ required(:age).filled(:int?, size?: 18..24)
49
49
  end
50
50
  end
51
51
 
52
- it 'generates filled? & int? & gt? rule' do
52
+ it 'generates filled? & int? & size? rule' do
53
+ expect(schema.(age: nil).messages).to eql(
54
+ age: ['must be filled', 'size must be within 18 - 24']
55
+ )
56
+ end
57
+ end
58
+
59
+ context 'with a block' do
60
+ subject(:schema) do
61
+ Dry::Validation.Schema do
62
+ required(:age).filled { int? & size?(18..24) }
63
+ end
64
+ end
65
+
66
+ it 'generates filled? & int? & size? rule' do
67
+ expect(schema.(age: nil).messages).to eql(
68
+ age: ['must be filled', 'size must be within 18 - 24']
69
+ )
70
+ end
71
+ end
72
+
73
+ context 'with a predicate and a block' do
74
+ subject(:schema) do
75
+ Dry::Validation.Schema do
76
+ required(:age).filled(:int?) { size?(18..24) }
77
+ end
78
+ end
79
+
80
+ it 'generates filled? & int? & size? rule' do
53
81
  expect(schema.(age: nil).messages).to eql(
54
82
  age: ['must be filled', 'size must be within 18 - 24']
55
83
  )
@@ -0,0 +1,21 @@
1
+ RSpec.describe 'Macros #input' do
2
+ subject(:schema) do
3
+ Dry::Validation.Schema do
4
+ input :hash?
5
+
6
+ required(:foo).filled
7
+ end
8
+ end
9
+
10
+ it 'passes when input is valid' do
11
+ expect(schema.(foo: "bar")).to be_successful
12
+ end
13
+
14
+ it 'prepends a rule for the input' do
15
+ expect(schema.(nil).messages).to eql(["must be a hash"])
16
+ end
17
+
18
+ it 'applies other rules when input has expected type' do
19
+ expect(schema.(foo: '').messages).to eql(foo: ["must be filled"])
20
+ end
21
+ end
@@ -2,7 +2,7 @@ RSpec.describe 'Macros #maybe' do
2
2
  describe 'with no args' do
3
3
  subject(:schema) do
4
4
  Dry::Validation.Schema do
5
- key(:email).maybe
5
+ required(:email).maybe
6
6
  end
7
7
  end
8
8
 
@@ -15,7 +15,7 @@ RSpec.describe 'Macros #maybe' do
15
15
  describe 'with a predicate with args' do
16
16
  subject(:schema) do
17
17
  Dry::Validation.Schema do
18
- key(:name).maybe(min_size?: 3)
18
+ required(:name).maybe(min_size?: 3)
19
19
  end
20
20
  end
21
21
 
@@ -29,4 +29,41 @@ RSpec.describe 'Macros #maybe' do
29
29
  )
30
30
  end
31
31
  end
32
+
33
+ describe 'with a block' do
34
+ subject(:schema) do
35
+ Dry::Validation.Schema do
36
+ required(:name).maybe { str? & min_size?(3) }
37
+ end
38
+ end
39
+
40
+ it 'generates none? | (str? & min_size?) rule' do
41
+ expect(schema.(name: nil).messages).to be_empty
42
+
43
+ expect(schema.(name: 'jane').messages).to be_empty
44
+
45
+ expect(schema.(name: 'xy').messages).to eql(
46
+ name: ['size cannot be less than 3']
47
+ )
48
+ end
49
+ end
50
+
51
+ describe 'with a predicate and a block' do
52
+ subject(:schema) do
53
+ Dry::Validation.Schema do
54
+ required(:name).maybe(:str?) { min_size?(3) }
55
+ end
56
+ end
57
+
58
+ it 'generates none? | (str? & min_size?) rule' do
59
+ expect(schema.(name: nil).messages).to be_empty
60
+
61
+ expect(schema.(name: 'jane').messages).to be_empty
62
+
63
+ expect(schema.(name: 'xy').messages).to eql(
64
+ name: ['size cannot be less than 3']
65
+ )
66
+ end
67
+ end
32
68
  end
69
+
@@ -0,0 +1,105 @@
1
+ RSpec.describe 'Macros #value' do
2
+ describe 'with no args' do
3
+ it 'raises an exception' do
4
+ expect { Dry::Validation.Schema { required(:email).value } }.to raise_error(
5
+ ArgumentError, "wrong number of arguments (given 0, expected at least 1)"
6
+ )
7
+ end
8
+ end
9
+
10
+ describe 'with a type specification' do
11
+ subject(:schema) do
12
+ Dry::Validation.Schema do
13
+ required(:age).value(:int?)
14
+ end
15
+ end
16
+
17
+ it 'generates int? rule' do
18
+ expect(schema.(age: nil).messages).to eql(
19
+ age: ['must be an integer']
20
+ )
21
+ end
22
+ end
23
+
24
+ describe 'with a predicate with args' do
25
+ context 'with a flat arg' do
26
+ subject(:schema) do
27
+ Dry::Validation.Schema do
28
+ required(:age).value(:int?, gt?: 18)
29
+ end
30
+ end
31
+
32
+ it 'generates int? & gt? rule' do
33
+ expect(schema.(age: nil).messages).to eql(
34
+ age: ['must be an integer', 'must be greater than 18']
35
+ )
36
+ end
37
+ end
38
+
39
+ context 'with a range arg' do
40
+ subject(:schema) do
41
+ Dry::Validation.Schema do
42
+ required(:age).value(:int?, size?: 18..24)
43
+ end
44
+ end
45
+
46
+ it 'generates int? & gt? rule' do
47
+ expect(schema.(age: nil).messages).to eql(
48
+ age: ['must be an integer', 'size must be within 18 - 24']
49
+ )
50
+ end
51
+ end
52
+
53
+ context 'with a block' do
54
+ subject(:schema) do
55
+ Dry::Validation.Schema do
56
+ required(:age).value { int? & size?(18..24) }
57
+ end
58
+ end
59
+
60
+ it 'generates int? & gt? rule' do
61
+ expect(schema.(age: nil).messages).to eql(
62
+ age: ['must be an integer', 'size must be within 18 - 24']
63
+ )
64
+ end
65
+ end
66
+
67
+ context 'with a predicate and a block' do
68
+ subject(:schema) do
69
+ Dry::Validation.Schema do
70
+ required(:age).value(:int?) { size?(18..24) }
71
+ end
72
+ end
73
+
74
+ it 'generates int? & gt? rule' do
75
+ expect(schema.(age: nil).messages).to eql(
76
+ age: ['must be an integer', 'size must be within 18 - 24']
77
+ )
78
+ end
79
+ end
80
+
81
+ context 'with a schema' do
82
+ subject(:schema) do
83
+ Dry::Validation.Schema do
84
+ required(:data).value(DataSchema)
85
+ end
86
+ end
87
+
88
+ before do
89
+ DataSchema = Dry::Validation.Schema do
90
+ required(:foo).filled(size?: 2..10)
91
+ end
92
+ end
93
+
94
+ after do
95
+ Object.send(:remove_const, :DataSchema)
96
+ end
97
+
98
+ it 'uses the schema' do
99
+ expect(schema.(data: { foo: '' }).messages).to eql(
100
+ data: { foo: ['must be filled', 'size must be within 2 - 10'] }
101
+ )
102
+ end
103
+ end
104
+ end
105
+ end
@@ -2,9 +2,9 @@ RSpec.describe 'Macros #when' do
2
2
  context 'with a result rule returned from the block' do
3
3
  subject(:schema) do
4
4
  Dry::Validation.Schema do
5
- key(:email).maybe
5
+ required(:email).maybe
6
6
 
7
- key(:login).required.when(:true?) do
7
+ required(:login).filled.when(:true?) do
8
8
  value(:email).filled?
9
9
  end
10
10
  end
@@ -22,10 +22,10 @@ RSpec.describe 'Macros #when' do
22
22
  describe 'with a result rule depending on another result' do
23
23
  subject(:schema) do
24
24
  Dry::Validation.Schema do
25
- key(:left).maybe(:int?)
26
- key(:right).maybe(:int?)
25
+ required(:left).maybe(:int?)
26
+ required(:right).maybe(:int?)
27
27
 
28
- key(:compare).maybe(:bool?).when(:true?) do
28
+ required(:compare).maybe(:bool?).when(:true?) do
29
29
  value(:left).gt?(value(:right))
30
30
  end
31
31
  end
@@ -43,10 +43,10 @@ RSpec.describe 'Macros #when' do
43
43
  describe 'with multiple result rules' do
44
44
  subject(:schema) do
45
45
  Dry::Validation.Schema do
46
- key(:email).maybe
47
- key(:password).maybe
46
+ required(:email).maybe
47
+ required(:password).maybe
48
48
 
49
- key(:login).maybe(:bool?).when(:true?) do
49
+ required(:login).maybe(:bool?).when(:true?) do
50
50
  value(:email).filled?
51
51
  value(:password).filled?
52
52
  end
@@ -62,4 +62,24 @@ RSpec.describe 'Macros #when' do
62
62
  )
63
63
  end
64
64
  end
65
+
66
+ context "predicate with options" do
67
+ subject(:schema) do
68
+ Dry::Validation.Schema do
69
+ required(:bar).maybe
70
+
71
+ required(:foo).filled.when(size?: 3) do
72
+ value(:bar).filled?
73
+ end
74
+ end
75
+ end
76
+
77
+ it 'generates check rule' do
78
+ expect(schema.(foo: [1,2,3], bar: nil).messages).to eql(
79
+ bar: ['must be filled']
80
+ )
81
+
82
+ expect(schema.(foo: [1,2], bar: nil).messages).to be_empty
83
+ end
84
+ end
65
85
  end
@@ -1,16 +1,19 @@
1
1
  RSpec.describe Schema, 'using nested values' do
2
2
  let(:schema) do
3
3
  Dry::Validation.Schema do
4
- key(:email).maybe
4
+ required(:email).maybe
5
5
 
6
- key(:settings) do
7
- optional(:offers).required(:bool?).when(:true?) do
8
- value([:settings, :newsletter]).false?
9
- end
6
+ required(:settings).schema do
7
+ optional(:offers).filled(:bool?)
8
+ required(:newsletter).filled(:bool?)
9
+ end
10
+
11
+ rule(newsletter: [[:settings, :newsletter], [:settings, :offers]]) do |newsletter, offers|
12
+ offers.true?.then(newsletter.false?)
13
+ end
10
14
 
11
- key(:newsletter).required(:bool?).when(:true?) do
12
- value(:email).filled?
13
- end
15
+ rule(email: [[:settings, :newsletter], :email]) do |newsletter, email|
16
+ newsletter.true?.then(email.filled?)
14
17
  end
15
18
  end
16
19
  end
@@ -9,8 +9,8 @@ RSpec.describe 'Schema with negated rules' do
9
9
  end
10
10
  end
11
11
 
12
- optional(:eat_cake).required
13
- optional(:have_cake).required
12
+ optional(:eat_cake).filled
13
+ optional(:have_cake).filled
14
14
 
15
15
  rule(:be_reasonable) do
16
16
  value(:eat_cake).eql?('yes!') & value(:have_cake).eql?('yes!').not
@@ -1,7 +1,7 @@
1
1
  RSpec.describe Dry::Validation::Schema do
2
2
  subject(:schema) do
3
3
  Dry::Validation.Schema do
4
- key(:age).required(:number?, :int?)
4
+ required(:age).filled(:number?, :int?)
5
5
  end
6
6
  end
7
7
 
@@ -9,7 +9,7 @@ RSpec.describe Dry::Validation::Schema, 'defining an option with default value'
9
9
  end
10
10
  end
11
11
 
12
- key(:email) { filled? & unique?(:email) }
12
+ required(:email) { filled? & unique?(:email) }
13
13
  end
14
14
  end
15
15
 
@@ -0,0 +1,9 @@
1
+ RSpec.describe 'Verifying predicates in the DSL' do
2
+ it 'raises error when invalid predicate name is used' do
3
+ expect { Dry::Validation.Schema { required(:age).value(filled?: 312) } }
4
+ .to raise_error(ArgumentError, "filled? predicate arity is invalid")
5
+
6
+ expect { Dry::Validation.Schema { required(:age) { none? | filled?(312) } } }
7
+ .to raise_error(ArgumentError, "filled? predicate arity is invalid")
8
+ end
9
+ end
@@ -0,0 +1,295 @@
1
+ RSpec.describe 'Predicates: Array' do
2
+ context 'with required' do
3
+ subject(:schema) do
4
+ Dry::Validation.Schema do
5
+ required(:foo) { array? { each { int? } } }
6
+ end
7
+ end
8
+
9
+ context 'with valid input' do
10
+ let(:input) { { foo: [3] } }
11
+
12
+ it 'is successful' do
13
+ expect(result).to be_successful
14
+ end
15
+ end
16
+
17
+ context 'with missing input' do
18
+ let(:input) { {} }
19
+
20
+ it 'is not successful' do
21
+ expect(result).to be_failing ['is missing']
22
+ end
23
+ end
24
+
25
+ context 'with nil input' do
26
+ let(:input) { { foo: nil } }
27
+
28
+ it 'is not successful' do
29
+ expect(result).to be_failing ['must be an array']
30
+ end
31
+ end
32
+
33
+ context 'with blank input' do
34
+ let(:input) { { foo: '' } }
35
+
36
+ it 'is not successful' do
37
+ expect(result).to be_failing ['must be an array']
38
+ end
39
+ end
40
+
41
+ context 'with invalid type' do
42
+ let(:input) { { foo: { a: 1 } } }
43
+
44
+ it 'is not successful' do
45
+ expect(result).to be_failing ['must be an array']
46
+ end
47
+ end
48
+
49
+ context 'with invalid input (integer)' do
50
+ let(:input) { { foo: 4 } }
51
+
52
+ it 'is not successful' do
53
+ expect(result).to be_failing ['must be an array']
54
+ end
55
+ end
56
+
57
+ context 'with invalid input (array with non-integers)' do
58
+ let(:input) { { foo: [:foo, :bar] } }
59
+
60
+ it 'is not successful' do
61
+ expect(result).to be_failing 0 => ['must be an integer'], 1 => ['must be an integer']
62
+ end
63
+ end
64
+
65
+ context 'with invalid input (miexed array)' do
66
+ let(:input) { { foo: [1, '2', :bar] } }
67
+
68
+ it 'is not successful' do
69
+ expect(result).to be_failing 1 => ['must be an integer'], 2 => ['must be an integer']
70
+ end
71
+ end
72
+ end
73
+
74
+ context 'with optional' do
75
+ subject(:schema) do
76
+ Dry::Validation.Schema do
77
+ optional(:foo) { array? { each { int? } } }
78
+ end
79
+ end
80
+
81
+ context 'with valid input' do
82
+ let(:input) { { foo: [3] } }
83
+
84
+ it 'is successful' do
85
+ expect(result).to be_successful
86
+ end
87
+ end
88
+
89
+ context 'with missing input' do
90
+ let(:input) { {} }
91
+
92
+ it 'is successful' do
93
+ expect(result).to be_successful
94
+ end
95
+ end
96
+
97
+ context 'with nil input' do
98
+ let(:input) { { foo: nil } }
99
+
100
+ it 'is not successful' do
101
+ expect(result).to be_failing ['must be an array']
102
+ end
103
+ end
104
+
105
+ context 'with blank input' do
106
+ let(:input) { { foo: '' } }
107
+
108
+ it 'is not successful' do
109
+ expect(result).to be_failing ['must be an array']
110
+ end
111
+ end
112
+
113
+ context 'with invalid type' do
114
+ let(:input) { { foo: { a: 1 } } }
115
+
116
+ it 'is not successful' do
117
+ expect(result).to be_failing ['must be an array']
118
+ end
119
+ end
120
+
121
+ context 'with invalid input (integer)' do
122
+ let(:input) { { foo: 4 } }
123
+
124
+ it 'is not successful' do
125
+ expect(result).to be_failing ['must be an array']
126
+ end
127
+ end
128
+
129
+ context 'with invalid input (array with non-integers)' do
130
+ let(:input) { { foo: [:foo, :bar] } }
131
+
132
+ it 'is not successful' do
133
+ expect(result).to be_failing 0 => ['must be an integer'], 1 => ['must be an integer']
134
+ end
135
+ end
136
+
137
+ context 'with invalid input (miexed array)' do
138
+ let(:input) { { foo: [1, '2', :bar] } }
139
+
140
+ it 'is not successful' do
141
+ expect(result).to be_failing 1 => ['must be an integer'], 2 => ['must be an integer']
142
+ end
143
+ end
144
+ end
145
+
146
+ context 'as macro' do
147
+ context 'with required' do
148
+ subject(:schema) do
149
+ Dry::Validation.Schema do
150
+ required(:foo).each(:int?)
151
+ end
152
+ end
153
+
154
+ context 'with missing input' do
155
+ let(:input) { {} }
156
+
157
+ it 'is not successful' do
158
+ expect(result).to be_failing ['is missing']
159
+ end
160
+ end
161
+
162
+ context 'with nil input' do
163
+ let(:input) { { foo: nil } }
164
+
165
+ it 'is not successful' do
166
+ expect(result).to be_failing ['must be an array']
167
+ end
168
+ end
169
+
170
+ context 'with blank input' do
171
+ let(:input) { { foo: '' } }
172
+
173
+ it 'is not successful' do
174
+ expect(result).to be_failing ['must be an array']
175
+ end
176
+ end
177
+
178
+ context 'with valid input' do
179
+ let(:input) { { foo: [3] } }
180
+
181
+ it 'is successful' do
182
+ expect(result).to be_successful
183
+ end
184
+ end
185
+
186
+ context 'with invalid input' do
187
+ let(:input) { { foo: [:bar] } }
188
+
189
+ it 'is not successful' do
190
+ expect(result).to be_failing 0 => ['must be an integer']
191
+ end
192
+ end
193
+
194
+ context "when using an input_processor" do
195
+ subject(:schema) do
196
+ Dry::Validation.Schema do
197
+ configure do
198
+ config.input_processor = :sanitizer
199
+ end
200
+
201
+ required(:foo).each(:int?)
202
+ end
203
+ end
204
+
205
+ context 'with missing input' do
206
+ let(:input) { {} }
207
+
208
+ it 'is not successful' do
209
+ expect(result).to be_failing ['is missing']
210
+ end
211
+ end
212
+
213
+ context 'with nil input' do
214
+ let(:input) { { foo: nil } }
215
+
216
+ it 'is not successful' do
217
+ expect(result).to be_failing ['must be an array']
218
+ end
219
+ end
220
+
221
+ context 'with blank input' do
222
+ let(:input) { { foo: '' } }
223
+
224
+ it 'is not successful' do
225
+ expect(result).to be_failing ['must be an array']
226
+ end
227
+ end
228
+
229
+ context 'with valid input' do
230
+ let(:input) { { foo: [3] } }
231
+
232
+ it 'is successful' do
233
+ expect(result).to be_successful
234
+ end
235
+ end
236
+
237
+ context 'with invalid input' do
238
+ let(:input) { { foo: [:bar] } }
239
+
240
+ it 'is not successful' do
241
+ expect(result).to be_failing 0 => ['must be an integer']
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ context 'with optional' do
248
+ subject(:schema) do
249
+ Dry::Validation.Schema do
250
+ optional(:foo).each(:int?)
251
+ end
252
+ end
253
+
254
+ context 'with missing input' do
255
+ let(:input) { {} }
256
+
257
+ it 'is successful' do
258
+ expect(result).to be_successful
259
+ end
260
+ end
261
+
262
+ context 'with nil input' do
263
+ let(:input) { { foo: nil } }
264
+
265
+ it 'is not successful' do
266
+ expect(result).to be_failing ['must be an array']
267
+ end
268
+ end
269
+
270
+ context 'with blank input' do
271
+ let(:input) { { foo: '' } }
272
+
273
+ it 'is not successful' do
274
+ expect(result).to be_failing ['must be an array']
275
+ end
276
+ end
277
+
278
+ context 'with valid input' do
279
+ let(:input) { { foo: [3] } }
280
+
281
+ it 'is successful' do
282
+ expect(result).to be_successful
283
+ end
284
+ end
285
+
286
+ context 'with invalid input' do
287
+ let(:input) { { foo: [:bar] } }
288
+
289
+ it 'is not successful' do
290
+ expect(result).to be_failing 0 => ['must be an integer']
291
+ end
292
+ end
293
+ end
294
+ end
295
+ end