From 34861b0373fad95f84e1c720d2e11b8c79e5d4cb Mon Sep 17 00:00:00 2001 From: David Mora Date: Fri, 20 Jan 2023 15:22:10 +0000 Subject: [PATCH] Keep all errors for all union types and attach the schema name ..So not only the errors from the first failed union type are kept --- lang/ruby/lib/avro/schema_validator.rb | 20 +++++++++++++++----- lang/ruby/test/test_schema_validator.rb | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lang/ruby/lib/avro/schema_validator.rb b/lang/ruby/lib/avro/schema_validator.rb index 8e463941a8b..97b60a77478 100644 --- a/lang/ruby/lib/avro/schema_validator.rb +++ b/lang/ruby/lib/avro/schema_validator.rb @@ -196,9 +196,14 @@ def validate_union(expected_schema, datum, path, result, options) compatible_type = first_compatible_type(datum, expected_schema, path, failures, options) return unless compatible_type.nil? - complex_type_failed = failures.detect { |r| COMPLEX_TYPES.include?(r[:type]) } - if complex_type_failed - complex_type_failed[:result].errors.each { |error| result << error } + complex_type_failed = failures.select { |r| COMPLEX_TYPES.include?(r[:type]) } + if complex_type_failed.any? + complex_type_failed.each do |type_failures| + type_failures[:result].errors.each do |error| + error_msg = type_failures[:schema] ? "#{type_failures[:schema]} #{error}" : error + result << error_msg + end + end else types = expected_schema.schemas.map { |s| "'#{s.type_sym}'" }.join(', ') result.add_error(path, "expected union of [#{types}], got #{actual_value_message(datum)}") @@ -208,11 +213,16 @@ def validate_union(expected_schema, datum, path, result, options) def first_compatible_type(datum, expected_schema, path, failures, options = {}) expected_schema.schemas.find do |schema| # Avoid expensive validation if we're just validating a nil - next datum.nil? if schema.type_sym == :null + if schema.type_sym == :null + next datum.nil? + end result = Result.new validate_recursive(schema, datum, path, result, options) - failures << { type: schema.type_sym, result: result } if result.failure? + + failure = { type: schema.type_sym, result: result } + failure[:schema] = schema.name if schema.is_a?(Avro::Schema::RecordSchema) + failures << failure if result.failure? !result.failure? end end diff --git a/lang/ruby/test/test_schema_validator.rb b/lang/ruby/test/test_schema_validator.rb index 8b120927929..6e10d9b7074 100644 --- a/lang/ruby/test/test_schema_validator.rb +++ b/lang/ruby/test/test_schema_validator.rb @@ -556,7 +556,7 @@ def test_validate_union_extra_fields validate!(schema, { 'name' => 'apple', 'color' => 'green' }, fail_on_extra_fields: true) end assert_equal(1, exception.result.errors.size) - assert_equal("at . extra field 'color' - not in schema", exception.to_s) + assert_equal("fruit at . extra field 'color' - not in schema", exception.to_s) end def test_validate_bytes_decimal