Skip to content

Commit

Permalink
switch LanguageTagValidator to operate on DRO::TYPES so that it's inv…
Browse files Browse the repository at this point in the history
…oked automatically when building item models
  • Loading branch information
jmartin-sul committed Nov 8, 2023
1 parent 35ef3bd commit 5ab9875
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 28 deletions.
44 changes: 35 additions & 9 deletions lib/cocina/models/validators/language_tag_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,56 @@ def initialize(clazz, attributes)
def validate
return unless meets_preconditions?

return if valid_language_tag?
return if invalid_files.empty?

raise ValidationError, 'The provided language tag is not valid according to RFC 4646: ' \
"#{attributes[:languageTag]}"
raise ValidationError, 'Some files have invalid language tags according to RFC 4646: ' \
"#{invalid_filenames_with_language_tags.join(', ')}"
end

private

attr_reader :clazz, :attributes

def meets_preconditions?
file? && attributes[:languageTag].present?
dro?
end

def file?
(clazz::TYPES & File::TYPES).any?
def dro?
(clazz::TYPES & DRO::TYPES).any?
rescue NameError
false
end

def valid_language_tag?
parsed_tag = I18n::Locale::Tag::Rfc4646.tag(attributes[:languageTag])
def valid_language_tag?(file)
# I18n::Locale::Tag::Rfc4646.tag will return an instance of I18n::Locale::Tag::Rfc4646 (with fields like language, script,
# region) for strings that can be parsed according to RFC 4646, and nil for strings that do not conform to the spec.
I18n::Locale::Tag::Rfc4646.tag(file[:languageTag]).present?
end

def invalid_files
@invalid_files ||= language_tag_files.reject { |file| valid_language_tag?(file) }
end

def invalid_filenames_with_language_tags
invalid_files.map { |invalid_file| "#{invalid_file[:filename] || invalid_file[:label]} (#{invalid_file[:languageTag]})" }
end

def language_tag_files
files.select { |file| file[:languageTag].present? }
end

def files
[].tap do |files|
next if attributes.dig(:structural, :contains).nil?

attributes[:structural][:contains].each do |fileset|
next if fileset.dig(:structural, :contains).nil?

parsed_tag.present? && parsed_tag.is_a?(I18n::Locale::Tag::Rfc4646)
fileset[:structural][:contains].each do |file|
files << file
end
end
end
end
end
end
Expand Down
58 changes: 39 additions & 19 deletions spec/cocina/models/validators/language_tag_validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,27 @@
require 'spec_helper'

RSpec.describe Cocina::Models::Validators::LanguageTagValidator do
let(:validate) { described_class.validate(clazz, props) }
let(:validate) { described_class.validate(clazz, dro_props) }

let(:dro_props) do
{
type: Cocina::Models::ObjectType.book,
access: { view: 'dark', download: 'none' },
structural: {
contains: [
{
externalIdentifier: 'bc123df4567_1',
label: 'Fileset 1',
type: Cocina::Models::FileSetType.file,
version: 1,
structural: {
contains: [props]
}
}
]
}
}
end

let(:props) { file_props }

Expand All @@ -26,16 +46,16 @@
end

context 'with no value for languageTag specified' do
context 'with a File' do
let(:clazz) { Cocina::Models::File }
context 'with a DRO' do
let(:clazz) { Cocina::Models::DRO }

it 'does not raise' do
expect { validate }.not_to raise_error
end
end

context 'with a RequestFile' do
let(:clazz) { Cocina::Models::RequestFile }
context 'with a RequestDRO' do
let(:clazz) { Cocina::Models::RequestDRO }

it 'does not raise' do
expect { validate }.not_to raise_error
Expand All @@ -53,16 +73,16 @@
context 'with a recognized language, script, and region' do
let(:language_tag) { 'ru-Cyrl-RU' }

context 'with a File' do
let(:clazz) { Cocina::Models::File }
context 'with a DRO' do
let(:clazz) { Cocina::Models::DRO }

it 'does not raise' do
expect { validate }.not_to raise_error
end
end

context 'with a RequestFile' do
let(:clazz) { Cocina::Models::RequestFile }
context 'with a RequestDRO' do
let(:clazz) { Cocina::Models::RequestDRO }

it 'does not raise' do
expect { validate }.not_to raise_error
Expand All @@ -73,16 +93,16 @@
context 'with an unrecognized language, script, and region' do
let(:language_tag) { 'foo-Barr-BZ' } # still conforms to the expected format of BCP 47/RFC 4646, should parse

context 'with a File' do
let(:clazz) { Cocina::Models::File }
context 'with a DRO' do
let(:clazz) { Cocina::Models::DRO }

it 'does not raise' do
expect { validate }.not_to raise_error
end
end

context 'with a RequestFile' do
let(:clazz) { Cocina::Models::RequestFile }
context 'with a RequestDRO' do
let(:clazz) { Cocina::Models::RequestDRO }

it 'does not raise' do
expect { validate }.not_to raise_error
Expand All @@ -98,19 +118,19 @@
end
end

context 'with a File' do
let(:clazz) { Cocina::Models::File }
context 'with a DRO' do
let(:clazz) { Cocina::Models::DRO }

it 'raises a validation error' do
expect { validate }.to raise_error(Cocina::Models::ValidationError, 'The provided language tag is not valid according to RFC 4646: fooooooooooooo')
expect { validate }.to raise_error(Cocina::Models::ValidationError, 'Some files have invalid language tags according to RFC 4646: page1.txt (fooooooooooooo)')
end
end

context 'with a RequestFile' do
let(:clazz) { Cocina::Models::RequestFile }
context 'with a RequestDRO' do
let(:clazz) { Cocina::Models::RequestDRO }

it 'raises a validation error' do
expect { validate }.to raise_error(Cocina::Models::ValidationError, 'The provided language tag is not valid according to RFC 4646: fooooooooooooo')
expect { validate }.to raise_error(Cocina::Models::ValidationError, 'Some files have invalid language tags according to RFC 4646: page1.txt (fooooooooooooo)')
end
end
end
Expand Down

0 comments on commit 5ab9875

Please sign in to comment.