このコミットが含まれているのは:
@@ -0,0 +1,110 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Tag group persistence constraints' do
|
||||
include TagGroupRecords
|
||||
|
||||
let!(:user) { create_member_user! }
|
||||
let!(:tag) { group_tag('制約確認') }
|
||||
let!(:group_id) do
|
||||
seed_group(
|
||||
name: '制約確認',
|
||||
members: [{ 'tag_id' => tag.id, 'version_no' => tag.version_no }])
|
||||
end
|
||||
|
||||
def placement attributes
|
||||
insert_group_row('tag_group_placements', {
|
||||
tag_group_id: group_id, position: 1,
|
||||
created_at: Time.current, updated_at: Time.current }.merge(attributes))
|
||||
end
|
||||
|
||||
def reject_statement
|
||||
before_state = group_state
|
||||
expect { yield }.to raise_error(ActiveRecord::StatementInvalid)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
|
||||
it 'allows membership without placement' do
|
||||
expect(group_rows('tag_group_tags', tag_group_id: group_id).size).to eq(1)
|
||||
expect(group_rows('tag_group_placements', tag_group_id: group_id)).to be_empty
|
||||
end
|
||||
|
||||
it 'allows repeated Tag placements with unique membership' do
|
||||
placement(tag_id: tag.id)
|
||||
placement(tag_id: tag.id, position: 2)
|
||||
expect(group_rows('tag_group_tags', tag_group_id: group_id).size).to eq(1)
|
||||
expect(group_rows('tag_group_placements', tag_group_id: group_id).size).to eq(2)
|
||||
end
|
||||
|
||||
it 'rejects duplicate Tag membership' do
|
||||
reject_statement do
|
||||
insert_group_row('tag_group_tags', {
|
||||
tag_group_id: group_id, tag_id: tag.id, created_at: Time.current })
|
||||
end
|
||||
end
|
||||
|
||||
it 'rejects duplicate child membership' do
|
||||
child_id = seed_group(name: '子')
|
||||
attributes = { tag_group_id: group_id, child_tag_group_id: child_id,
|
||||
created_at: Time.current }
|
||||
insert_group_row('tag_group_groups', attributes)
|
||||
reject_statement { insert_group_row('tag_group_groups', attributes) }
|
||||
end
|
||||
|
||||
it 'rejects direct self membership' do
|
||||
reject_statement do
|
||||
insert_group_row('tag_group_groups', {
|
||||
tag_group_id: group_id, child_tag_group_id: group_id, created_at: Time.current })
|
||||
end
|
||||
end
|
||||
|
||||
it 'rejects a placement without a kind' do
|
||||
reject_statement { placement({ }) }
|
||||
end
|
||||
|
||||
it 'rejects simultaneous Section and Tag kinds' do
|
||||
reject_statement { placement(section_name: '区分', tag_id: tag.id) }
|
||||
end
|
||||
|
||||
it 'rejects a description attached to a Tag placement' do
|
||||
reject_statement { placement(tag_id: tag.id, description: '不正') }
|
||||
end
|
||||
|
||||
it 'allows an optional description on a Section' do
|
||||
placement(section_name: '区分', description: '説明')
|
||||
expect(group_rows('tag_group_placements', tag_group_id: group_id).sole)
|
||||
.to include('section_name' => '区分', 'description' => '説明')
|
||||
end
|
||||
|
||||
it 'rejects a Tag placement absent from membership' do
|
||||
other = group_tag('非メンバー')
|
||||
reject_statement { placement(tag_id: other.id) }
|
||||
end
|
||||
|
||||
it 'rejects a missing parent placement' do
|
||||
reject_statement { placement(section_name: '子', parent_position: 9) }
|
||||
end
|
||||
|
||||
it 'rejects a child ordered before its parent' do
|
||||
placement(section_name: '親', position: 2)
|
||||
reject_statement { placement(section_name: '子', position: 1, parent_position: 2) }
|
||||
end
|
||||
|
||||
it 'rejects duplicate group names' do
|
||||
reject_statement { seed_group(name: '制約確認') }
|
||||
end
|
||||
|
||||
it 'rejects a missing mandatory group name' do
|
||||
reject_statement { seed_group(name: nil) }
|
||||
end
|
||||
|
||||
it 'rejects a six-level snapshot' do
|
||||
nodes = []
|
||||
6.times { nodes = [{ 'tag_id' => tag.id, 'children' => nodes }] }
|
||||
reject_statement do
|
||||
insert_group_row('tag_group_versions', {
|
||||
tag_group_id: group_id, version_no: 2, event_type: 'update', name: '制約確認',
|
||||
members: [{ 'tag_id' => tag.id, 'version_no' => tag.version_no }].to_json,
|
||||
placements: nodes.to_json, created_at: Time.current })
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,119 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Tag group migration identity and structure' do
|
||||
include TagGroupRecords
|
||||
|
||||
let!(:user) { create_member_user! }
|
||||
|
||||
before { I18n.locale = :ja }
|
||||
|
||||
it 'preserves page and revision IDs, timestamps and repeated historical structures' do
|
||||
tag = group_tag('洗澡鹿')
|
||||
body = "説明文\n\n- 洗澡鹿\n- 洗澡鹿"
|
||||
page = legacy_group('伊地知ニジカ亜種', body)
|
||||
revisions = [page.current_revision]
|
||||
[body, '# 空の区分', body].each do |text|
|
||||
revisions << Wiki::Commit.legacy_content!(page:, body: text, created_user: user)
|
||||
end
|
||||
before_state = group_state.except(*TagGroupRecords::GROUP_TABLES)
|
||||
|
||||
migrate_groups
|
||||
|
||||
versions = group_rows('tag_group_versions', tag_group_id: page.id)
|
||||
.sort_by { _1.fetch('version_no') }
|
||||
expect(versions.map { _1.fetch('id') }).to eq(revisions.map(&:id))
|
||||
expect(versions.map { _1.fetch('version_no') }).to eq([1, 2, 3, 4])
|
||||
expect(versions.map { _1.fetch('created_at') }).to eq(revisions.map(&:created_at))
|
||||
expect(versions.map { _1.fetch('created_by_user_id') }).to eq([user.id] * 4)
|
||||
expect(versions.map { _1.fetch('event_type') }).to eq(['create', 'update', 'update', 'update'])
|
||||
expect(group_version(page.id, 1).fetch('placements')).to eq(
|
||||
group_version(page.id, 2).fetch('placements'))
|
||||
expect(group_version(page.id, 3).fetch('placements')).to eq([
|
||||
{ 'section_name' => '空の区分', 'description' => nil, 'children' => [] }])
|
||||
expect_group_snapshot(
|
||||
page.id, number: 4, description: '説明文',
|
||||
members: [{ 'tag_id' => tag.id, 'version_no' => tag.version_no }],
|
||||
placements: [{ 'tag_id' => tag.id, 'children' => [] }] * 2)
|
||||
expect(group_rows('tag_groups', id: page.id).sole).to include(
|
||||
'created_at' => page.created_at, 'updated_at' => page.reload.updated_at)
|
||||
expect(group_state.except(*TagGroupRecords::GROUP_TABLES)).to eq(before_state)
|
||||
end
|
||||
|
||||
it 'migrates nested list Sections and child groups as different placement kinds' do
|
||||
series = group_tag('ぼざろクリーチャーシリーズ')
|
||||
deer = group_tag('洗澡鹿')
|
||||
nijika = group_tag('伊地知ニジカ')
|
||||
child = legacy_group('伊地知ニジカ亜種', <<~MARKDOWN)
|
||||
- ぼざろクリーチャーシリーズ
|
||||
- 伊地知ニジカ亜種:
|
||||
- 洗澡鹿
|
||||
MARKDOWN
|
||||
parent = legacy_group('ぼざろクリーチャーシリーズのキャラクター', <<~MARKDOWN)
|
||||
- ぼざろクリーチャーシリーズ
|
||||
- 伊地知ニジカ
|
||||
- タググループ:伊地知ニジカ亜種
|
||||
MARKDOWN
|
||||
|
||||
migrate_groups
|
||||
|
||||
expect_group_snapshot(
|
||||
child.id, number: 1,
|
||||
members: [series, deer].map { { 'tag_id' => _1.id, 'version_no' => _1.version_no } },
|
||||
placements: [{ 'tag_id' => series.id, 'children' => [
|
||||
{ 'section_name' => '伊地知ニジカ亜種', 'description' => nil,
|
||||
'children' => [{ 'tag_id' => deer.id, 'children' => [] }] }] }])
|
||||
expect_group_snapshot(
|
||||
parent.id, number: 1,
|
||||
members: [
|
||||
{ 'tag_id' => series.id, 'version_no' => series.version_no },
|
||||
{ 'tag_id' => nijika.id, 'version_no' => nijika.version_no },
|
||||
{ 'tag_group_id' => child.id, 'version_no' => 1 }],
|
||||
placements: [{ 'tag_id' => series.id, 'children' => [
|
||||
{ 'tag_id' => nijika.id, 'children' => [
|
||||
{ 'tag_group_id' => child.id, 'children' => [] }] }] }])
|
||||
end
|
||||
|
||||
it 'preserves heading order, group paragraphs and Section descriptions' do
|
||||
names = ['タグ希望', 'キャラクター名希望', '楽曲情報希望', 'bot操作', 'ニジラー情報不詳']
|
||||
tags = names.map { group_tag(_1) }
|
||||
markdown = <<~MARKDOWN
|
||||
全体の説明
|
||||
|
||||
# 要求
|
||||
要求の説明
|
||||
|
||||
- タグ希望
|
||||
- キャラクター名希望
|
||||
- 楽曲情報希望
|
||||
|
||||
# 情報
|
||||
- bot操作
|
||||
- ニジラー情報不詳
|
||||
MARKDOWN
|
||||
page = legacy_group('メタタグ', markdown)
|
||||
expect(page.current_revision.body).to eq(markdown.chomp)
|
||||
|
||||
migrate_groups
|
||||
|
||||
leaves = tags.map { { 'tag_id' => _1.id, 'children' => [] } }
|
||||
leaves.first['children'] = leaves[1..2]
|
||||
expect_group_snapshot(
|
||||
page.id, number: 1, description: '全体の説明',
|
||||
members: tags.map { { 'tag_id' => _1.id, 'version_no' => _1.version_no } },
|
||||
placements: [
|
||||
{ 'section_name' => '要求', 'description' => '要求の説明',
|
||||
'children' => [leaves.first] },
|
||||
{ 'section_name' => '情報', 'description' => nil,
|
||||
'children' => leaves[3..4] }])
|
||||
end
|
||||
|
||||
it 'leaves Help in the legacy domain' do
|
||||
page = Wiki::Commit.create_legacy_content!(
|
||||
tag_name: create(:tag_name, name: 'Help:移行対象外'),
|
||||
body: 'Help 本文', created_by_user: user)
|
||||
before_state = group_state
|
||||
migrate_groups
|
||||
expect(group_state).to eq(before_state)
|
||||
expect(page.reload.body).to eq('Help 本文')
|
||||
end
|
||||
end
|
||||
新しいイシューから参照
ユーザーをブロックする