dry-rb / dry-rb/dry-validation
Arrays of multiple custom types not validating correctly
- Dominant language
- Ruby
- Stars
- 1.4k
- Forks
- 195
- PR merge metrics
- No merged PRs in 30d
Description
This bug report is being submitted following on from [this forum discussion](https://discourse.hanakai.org/t/dry-schema-validation-array-of-multiple-custom-types-is-it-possible/1504). There's more context there if necessary, but I'll try to keep to the specifics of the actual issue in this report.
Note: I wasn't sure whether to open the report on this repo or on [`dry-schema`]() repo (I guess it's mainly a schema issue but since it occurred in the context of using `dry-validation` I thought I would open it here so that the examples/steps to reproduce make sense).
## Describe the bug
When defining a schema in a `Dry::Validation::Contract` class definition that contains an array of multiple custom types, then invoking `call` on that contract while passing in a data structure which _should_ be invalid against the defined schema, the returned object returns `true` when `valid?` is called on it, and the `errors` hash is empty.
## To Reproduce
Given the following `Dry::Validation::Contract` class definition:
```ruby
require 'dry-validation'
require 'dry-schema'
require 'dry-types'
Types = Dry.Types()
Color = Types::Hash.schema(type: Types::String, name: Types::String, code: Types::Integer)
Book = Types::Hash.schema(type: Types::String, title: Types::String, genre: Types::String)
class ThingsContract < Dry::Validation::Contract
schema do
required(:things).value(array[Color | Book])
end
end
```
Instantiate a new contract object:
```ruby
things_contract = ThingsContract.new
```
Define some data which includes a Hash which doesn't match the structure of either the `Color` or `Book` types, and should therefore be invalid.
```ruby
invalid_things = {
things: [
{ type: 'Color', name: 'red', code: 1 },
{ type: 'Book', title: 'The Great Gatsby', genre: 'Fiction' },
{ type: 'Foo', foo: 'bar' } # This should fail validation since it does not match either `Color` or `Book` types
]
}
```
Pass that data into the `call` invocation:
```ruby
invalid_things_result = person_contract.call(invalid_person)
# invalid_things_result.success? => true
# invalid_things_result.errors.to_h => {}
```
## Expected behavior
The expected behaviour would be that `invalid_things_result.success?` returns `false`, and that `invalid_things_result.errors.to_h` would not return an empty hash.
## My environment
- Ruby version: 3.4
- OS: Mac OS (ventura 13.5)
Contributor guide
Research direction
Start by running the ThingsContract and invalid_things reproduction described in the issue, using Contract#call and checking success? and errors.to_h. Trace how schema handles an array containing the Color | Book union; done means the Foo hash makes validation fail and produces non-empty errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100