dry-validation icon indicating copy to clipboard operation
dry-validation copied to clipboard

Validation passes when array type is invalid

Open guilherme-andrade opened this issue 1 year ago • 1 comments

Describe the bug

When creating a custom type and using with the array rule, it appears that the validations applied by the type are not applied always by the rule. See the example below, and note that the last test is failing when it shouldn't:

To Reproduce

require 'dry/validation'
require 'dry/types'

module Types
  include Dry.Types(default: :nominal)

  StringOrHash = Types::Strict::String.enum('foo') | Types::Strict::Hash.schema(bar: Types::Strict::String.enum('baz'))
end


class TestContract < Dry::Validation::Contract
  params do
    required(:test).array(Types::StringOrHash)
  end
end

These tests all pass as expected:

RSpec.describe Types::StringOrHash do
  it 'works with a valid hash input' do
    expect { described_class[{ bar: 'baz' }] }.not_to raise_error
  end

  it 'works with a valid string input' do
    expect { described_class['foo'] }.not_to raise_error
  end

  it 'fails with an invalid string input' do
    expect { described_class['bar'] }.to raise_error
  end

  it 'fails with a hash with invalid values' do
    expect { described_class[{ bar: 'quz' }] }.to raise_error
  end

  it 'fails with a hash with invalid keys' do
    expect { described_class[{ quz: 'baz' }] }.to raise_error
  end
end

The first test passes, the second fails:

RSpec.describe TestContract do
  subject { described_class.new.call(params) }

  context 'when passing a valid array' do
    let(:params) { { test: ['foo', { bar: 'baz' }] } }

    it { is_expected.to be_success }
  end

  # THIS TEST FAILS
  context 'when passing an invalid array' do
    let(:params) { { test: ['foo', { bar: 'qux' }] } }

    it { is_expected.to be_failure }
  end
end

Expected behavior

It is expected that the validation fails when the input value is not of the described value.

My environment

  • Affects my production application: YES
  • Ruby version: 2.7.5
  • OS: MacOS Monterrey 12.0.1 (Apple chip)

guilherme-andrade avatar Sep 09 '22 11:09 guilherme-andrade

Thanks for reporting this. Looks like the right-side hash type is not expanded fully to a schema rule:

dry-validation> TestContract.schema
=> #<Dry::Schema::Params keys=["test"] rules={:test=>"key?(:test) AND key[test](array? AND each(str? AND included_in?([\"foo\"]) OR hash?))"}>

solnic avatar Sep 12 '22 08:09 solnic