ファイル
btrc-hub/backend/spec/models/locale_spec.rb
T
2026-10-20 20:29:18 +09:00

186 行
8.3 KiB
Ruby

require 'rails_helper'
RSpec.describe Locale, type: :model do
include_context 'Ainu locale'
def create_ainu_locale!
prepare_ainu_reference!
described_class.create!(code: 'ain-Kana', language_code: 'ain',
script_code: 'Kana', region_code: 392,
variants: '', name: 'Ainu')
end
it 'keeps the active Nipponese locale consistent with its identity tuple' do
expect(described_class.where(deprecated_at: nil).pluck(:code)).to eq(['ja'])
expect(described_class.nipponese).to have_attributes(
code: 'ja', language_code: 'ja', script_code: 'Jpan',
region_code: 392, variants: '')
end
it 'rejects a duplicate locale identity tuple at the database boundary' do
expect {
described_class.insert_all!([{ code: 'ja-duplicate', language_code: 'ja',
script_code: 'Jpan', region_code: 392,
variants: '', name: '日本語',
created_at: Time.current }])
}.to raise_error(ActiveRecord::RecordNotUnique)
end
it 'generates a primary name for every existing tag using the name generator' do
first = create(:tag, primary_name: 'first_existing_tag')
second = create(:tag, primary_name: 'second_existing_tag')
allow(TagName).to receive(:generate_name).and_call_original
allow(TagName).to receive(:generate_name)
.with(kind_of(described_class), first, primary_tag_name_for(first, 'ja'))
.and_return('name_from_generator')
locale = create_ainu_locale!
expect(TagName).to have_received(:generate_name)
.with(locale, first, primary_tag_name_for(first, 'ja'))
expect(TagName).to have_received(:generate_name)
.with(locale, second, primary_tag_name_for(second, 'ja'))
expect(first.tag_names.find_by!(language_code: 'ain', primary_flg: true))
.to have_attributes(name: 'name_from_generator', tag_id: first.id,
language_code: 'ain', script_code: 'Kana',
primary_flg: true, auto_generated: true)
expect(second.tag_names.find_by!(language_code: 'ain', primary_flg: true))
.to have_attributes(tag_id: second.id, language_code: 'ain',
script_code: 'Kana', primary_flg: true,
auto_generated: true)
expect(TagName.where(language_code: 'ain', primary_flg: true,
tag_id: [first.id, second.id]).count).to eq(2)
end
it 'does not duplicate an existing primary name in the new language' do
prepare_ainu_reference!
tag = create(:tag, primary_name: 'already_named')
existing = create(:tag_name, name: 'existing_ainu', tag:,
language_code: 'ain', script_code: 'Kana')
versions_before = tag.tag_versions.order(:version_no).map(&:attributes)
create_ainu_locale!
expect(TagName.where(tag_id: tag.id, language_code: 'ain', primary_flg: true))
.to contain_exactly(existing)
expect(existing.reload).to have_attributes(
tag_id: tag.id, language_code: 'ain', script_code: 'Kana',
primary_flg: true, auto_generated: false)
expect(tag.tag_versions.order(:version_no).map(&:attributes)).to eq(versions_before)
end
it 'adds the new language primary while preserving existing names and aliases' do
tag = create(:tag, primary_name: 'named_tag')
create(:tag_name, :alias, name: 'existing_alias', tag:,
language_code: 'ja', script_code: 'Jpan')
original_names = tag.tag_names.order(:id).map(&:attributes)
create_ainu_locale!
expect(tag.tag_names.where(language_code: 'ja').order(:id).map(&:attributes))
.to eq(original_names)
generated = TagName.find_by!(tag_id: tag.id, language_code: 'ain', primary_flg: true)
expect(generated).to have_attributes(name: 'named_tag', tag_id: tag.id, language_code: 'ain',
script_code: 'Kana', primary_flg: true,
auto_generated: true)
expect(TagName.where(tag_id: tag.id, language_code: 'ain', primary_flg: true).count).to eq(1)
end
it 'rolls back the locale and all generated names when backfill fails' do
prepare_ainu_reference!
first = create(:tag, primary_name: 'atomic_first')
second = create(:tag, primary_name: 'atomic_second')
versions_before = TagVersion.order(:id).map(&:attributes)
allow(TagName).to receive(:generate_name).and_call_original
allow(TagName).to receive(:generate_name)
.with(kind_of(described_class), second, primary_tag_name_for(second, 'ja'))
.and_raise('backfill failed')
expect { create_ainu_locale! }.to raise_error('backfill failed')
expect(described_class.exists?(code: 'ain-Kana')).to be(false)
expect(TagName.where(language_code: 'ain', tag_id: [first.id, second.id])).to be_empty
expect(TagVersion.order(:id).map(&:attributes)).to eq(versions_before)
end
it 'records a separate automatic update for each tag without changing its authored create' do
author = create(:user, :admin)
tags = ['locale_history_first', 'locale_history_second'].map do |name|
Tag.find_or_create_by_tag_name!(Locale.nipponese, name, category: :general,
created_by_user: author)
end
originals = tags.map { |tag| tag.tag_versions.sole.attributes }
expect { create_ainu_locale! }.to change(TagVersion, :count).by(2)
tags.zip(originals).each do |tag, original|
versions = tag.tag_versions.order(:version_no).to_a
expect(versions.map(&:event_type)).to eq(['create', 'update'])
expect(versions.first.attributes).to eq(original)
expect(versions.first.created_by_user_id).to eq(author.id)
expect(versions.last).to have_attributes(version_no: 2, created_by_user_id: nil)
expect(versions.last.names.fetch('ain')).to eq(
'name' => tag.name('ja'), 'script_code' => 'Kana',
'auto_generated' => true, 'aliases' => [])
expect(versions.first.names.keys).to eq(['ja'])
expect(tag.reload.version_no).to eq(2)
end
expect { TagNameCompletion.for_locale!(Locale.find('ain-Kana')) }
.not_to change(TagVersion, :count)
end
it 'records automatic before and after snapshots for a tag without any history' do
tag = create(:tag, primary_name: 'legacy_before_locale')
expect(tag.tag_versions).to be_empty
create_ainu_locale!
versions = tag.tag_versions.order(:version_no).to_a
expect(versions.map(&:event_type)).to eq(['create', 'update'])
expect(versions.map(&:created_by_user_id)).to eq([nil, nil])
expect(versions.first.names.keys).to eq(['ja'])
expect(versions.last.names.keys).to match_array(['ja', 'ain'])
expect(versions.last.names.fetch('ja')).to eq(versions.first.names.fetch('ja'))
end
it 'rolls back earlier tag names and histories when a later history fails' do
first = create(:tag, primary_name: 'history_atomic_first')
second = create(:tag, primary_name: 'history_atomic_second')
names_before = TagName.order(:id).map(&:attributes)
versions_before = TagVersion.order(:id).map(&:attributes)
allow(TagVersioning).to receive(:record!).and_wrap_original do |original, tag, **options|
if tag.id == second.id && options[:event_type] == :update
raise ActiveRecord::RecordNotSaved, 'history failed'
end
original.call(tag, **options)
end
expect { create_ainu_locale! }
.to raise_error(ActiveRecord::RecordNotSaved, 'history failed')
expect(described_class.exists?(code: 'ain-Kana')).to be(false)
expect(TagName.order(:id).map(&:attributes)).to eq(names_before)
expect(TagVersion.order(:id).map(&:attributes)).to eq(versions_before)
expect([first.reload.version_no, second.reload.version_no]).to eq([1, 1])
end
it 'rejects a private locale code outside the supported locale set' do
prepare_ainu_reference!
expect {
described_class.create!(
code: 'ain-Kana-x-rspec', language_code: 'ain',
script_code: 'Kana', region_code: 392,
variants: 'x-rspec', name: 'Ainu')
}.to raise_error(ArgumentError)
end
it 'registers the supported Ainu locale tuple' do
expect(locale).to have_attributes(code: 'ain-Kana', language_code: 'ain',
script_code: 'Kana', region_code: 392,
variants: '')
end
end