ponshu-room-lite/test/models/sake_item_test.dart

241 lines
7.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter_test/flutter_test.dart';
import 'package:ponshu_room_lite/models/sake_item.dart';
void main() {
group('SakeItem - Construction', () {
test('should create SakeItem with required fields', () {
final sake = SakeItem(
id: 'test-001',
displayData: DisplayData(
name: '獺祭 純米大吟醸',
brewery: '旭酒造',
prefecture: '山口県',
imagePaths: ['/path/to/image.jpg'],
),
hiddenSpecs: HiddenSpecs(
description: 'フルーティーで華やかな香りが特徴',
tasteStats: {'aroma': 5, 'sweetness': 3, 'acidity': 2, 'bitterness': 2, 'body': 3},
flavorTags: ['フルーティー', '華やか'],
),
);
expect(sake.id, 'test-001');
expect(sake.displayData.name, '獺祭 純米大吟醸');
expect(sake.displayData.brewery, '旭酒造');
expect(sake.displayData.prefecture, '山口県');
expect(sake.displayData.imagePaths.length, 1);
});
test('should create SakeItem with default values for optional fields', () {
final sake = SakeItem(
id: 'test-002',
displayData: DisplayData(
name: 'テスト銘柄',
brewery: 'テスト蔵元',
prefecture: '東京都',
imagePaths: [],
),
);
expect(sake.hiddenSpecs.tasteStats, isEmpty);
expect(sake.hiddenSpecs.flavorTags, isEmpty);
expect(sake.userData.isFavorite, false);
expect(sake.userData.isUserEdited, false);
});
});
group('SakeItem - DisplayData getters', () {
test('should use primary name when sakenowa data is not set', () {
final sake = SakeItem(
id: 'test-003',
displayData: DisplayData(
name: 'AI解析名',
brewery: 'AI蔵元',
prefecture: 'AI県',
imagePaths: [],
),
);
expect(sake.displayData.displayName, 'AI解析名');
expect(sake.displayData.displayBrewery, 'AI蔵元');
expect(sake.displayData.displayPrefecture, 'AI県');
expect(sake.displayData.hasSakenowaData, false);
});
test('should prioritize sakenowa data over primary data', () {
final sake = SakeItem(
id: 'test-004',
displayData: DisplayData(
name: 'AI解析名',
brewery: 'AI蔵元',
prefecture: 'AI県',
imagePaths: [],
sakenowaName: 'さけのわ統一名',
sakenowaBrewery: 'さけのわ蔵元',
sakenowaPrefecture: 'さけのわ県',
),
);
expect(sake.displayData.displayName, 'さけのわ統一名');
expect(sake.displayData.displayBrewery, 'さけのわ蔵元');
expect(sake.displayData.displayPrefecture, 'さけのわ県');
expect(sake.displayData.hasSakenowaData, true);
});
});
group('SakeItem - copyWith', () {
late SakeItem baseSake;
setUp(() {
baseSake = SakeItem(
id: 'test-005',
displayData: DisplayData(
name: '元の銘柄',
brewery: '元の蔵元',
prefecture: '元の県',
imagePaths: ['/path/original.jpg'],
catchCopy: '元のキャッチコピー',
),
hiddenSpecs: HiddenSpecs(
description: '元の説明',
tasteStats: {'aroma': 3, 'sweetness': 3, 'acidity': 3, 'bitterness': 3, 'body': 3},
flavorTags: ['元のタグ'],
),
);
});
test('should update name while keeping other fields', () {
final updated = baseSake.copyWith(name: '新しい銘柄');
expect(updated.displayData.name, '新しい銘柄');
expect(updated.displayData.brewery, '元の蔵元');
expect(updated.displayData.prefecture, '元の県');
expect(updated.id, 'test-005');
});
test('should update tasteStats while keeping other fields', () {
final newStats = {'aroma': 5, 'sweetness': 1, 'acidity': 4, 'sharpness': 2, 'body': 5};
final updated = baseSake.copyWith(tasteStats: newStats);
expect(updated.hiddenSpecs.tasteStats, newStats);
expect(updated.displayData.name, '元の銘柄');
});
test('should update favorite status', () {
final updated = baseSake.copyWith(isFavorite: true);
expect(updated.userData.isFavorite, true);
expect(updated.displayData.name, '元の銘柄');
});
test('should update imagePaths', () {
final newPaths = ['/path/new1.jpg', '/path/new2.jpg'];
final updated = baseSake.copyWith(imagePaths: newPaths);
expect(updated.displayData.imagePaths, newPaths);
expect(updated.displayData.imagePaths.length, 2);
});
});
group('SakeItem - ensureMigrated', () {
test('レガシーフィールドからdisplayDataを構築する', () {
final sake = SakeItem(
id: 'legacy-001',
legacyName: '出羽桜',
legacyBrand: '出羽桜酒造',
legacyPrefecture: '山形県',
legacyCatchCopy: '花と夢と',
legacyImagePaths: ['/path/legacy.jpg'],
);
// displayData未設定の状態でgetterがlegacyから返す
expect(sake.displayData.name, '出羽桜');
expect(sake.displayData.brewery, '出羽桜酒造');
expect(sake.displayData.prefecture, '山形県');
// ensureMigratedで新構造に昇格
final migrated = sake.ensureMigrated();
expect(migrated, true); // 移行が実行された
// 2回目はfalseを返す既に移行済み
final again = sake.ensureMigrated();
expect(again, false);
});
test('displayDataが既に設定されている場合はfalseを返す', () {
final sake = SakeItem(
id: 'new-001',
displayData: DisplayData(
name: '新政',
brewery: '新政酒造',
prefecture: '秋田県',
imagePaths: [],
),
);
final migrated = sake.ensureMigrated();
expect(migrated, false);
});
test('legacyNameがnullの場合はUnknownにフォールバックする', () {
final sake = SakeItem(id: 'legacy-002');
sake.ensureMigrated();
expect(sake.displayData.name, 'Unknown');
expect(sake.displayData.brewery, 'Unknown');
expect(sake.displayData.prefecture, 'Unknown');
});
});
group('SakeItem - HiddenSpecs / TasteStats', () {
test('should return SakeTasteStats from tasteStats map', () {
final sake = SakeItem(
id: 'test-006',
displayData: DisplayData(
name: 'テスト',
brewery: 'テスト蔵',
prefecture: 'テスト県',
imagePaths: [],
),
hiddenSpecs: HiddenSpecs(
description: '',
tasteStats: {'aroma': 5, 'sweetness': 3, 'acidity': 2, 'bitterness': 4, 'body': 1},
flavorTags: [],
),
);
final stats = sake.hiddenSpecs.sakeTasteStats;
expect(stats.aroma, 5);
expect(stats.sweetness, 3);
expect(stats.acidity, 2);
expect(stats.bitterness, 4);
expect(stats.body, 1);
});
test('should return zero stats for empty tasteStats', () {
final sake = SakeItem(
id: 'test-007',
displayData: DisplayData(
name: 'テスト',
brewery: 'テスト蔵',
prefecture: 'テスト県',
imagePaths: [],
),
hiddenSpecs: HiddenSpecs(
description: '',
tasteStats: {},
flavorTags: [],
),
);
final stats = sake.hiddenSpecs.sakeTasteStats;
expect(stats.aroma, 0);
expect(stats.sweetness, 0);
expect(stats.acidity, 0);
expect(stats.bitterness, 0);
expect(stats.body, 0);
});
});
}