// JournalElement 模型单元测试 // // 覆盖:工厂方法、便利工厂、copyWith 不可变性、序列化往返、默认值 import 'dart:math'; import 'package:flutter_test/flutter_test.dart'; import 'package:nuanji_app/data/models/journal_element.dart'; void main() { group('JournalElement', () { // ===== create 工厂 ===== test('create 工厂生成正确的默认值', () { final element = JournalElement.create( journalId: 'journal-1', elementType: ElementType.text, positionX: 10, positionY: 20, content: {'text': 'Hello'}, ); expect(element.journalId, 'journal-1'); expect(element.elementType, ElementType.text); expect(element.positionX, 10.0); expect(element.positionY, 20.0); expect(element.width, 100.0); expect(element.height, 100.0); expect(element.rotation, 0.0); expect(element.zIndex, 0); expect(element.version, 1); expect(element.id, isNotEmpty); expect(element.createdAt, isNotNull); expect(element.updatedAt, isNotNull); }); // ===== createText ===== test('createText 便利工厂', () { final element = JournalElement.createText( journalId: 'j-1', text: '你好', position: const Offset(50, 100), fontSize: 24.0, fontColor: '#E07A5F', ); expect(element.elementType, ElementType.text); expect(element.content['text'], '你好'); expect(element.content['fontSize'], 24.0); expect(element.content['fontColor'], '#E07A5F'); expect(element.positionX, 50.0); expect(element.positionY, 100.0); }); test('createText 使用默认字号和颜色', () { final element = JournalElement.createText( journalId: 'j-1', text: '默认', position: Offset.zero, ); expect(element.content['fontSize'], 18.0); expect(element.content['fontColor'], '#2D2420'); }); // ===== createImage ===== test('createImage 便利工厂', () { final element = JournalElement.createImage( journalId: 'j-1', filePath: '/path/to/image.jpg', position: Offset.zero, thumbnailPath: '/path/to/thumb.jpg', ); expect(element.elementType, ElementType.image); expect(element.content['filePath'], '/path/to/image.jpg'); expect(element.content['thumbnailPath'], '/path/to/thumb.jpg'); }); test('createImage 无 thumbnailPath 时不包含该字段', () { final element = JournalElement.createImage( journalId: 'j-1', filePath: '/path/to/img.jpg', position: Offset.zero, ); expect(element.content.containsKey('thumbnailPath'), isFalse); expect(element.content['filePath'], '/path/to/img.jpg'); }); // ===== createSticker ===== test('createSticker 便利工厂', () { final element = JournalElement.createSticker( journalId: 'j-1', emoji: '🐱', position: const Offset(50, 50), stickerPackId: 'pack-1', stickerId: 's-1', ); expect(element.elementType, ElementType.sticker); expect(element.content['emoji'], '🐱'); expect(element.content['stickerPackId'], 'pack-1'); expect(element.content['stickerId'], 's-1'); }); test('createSticker 无可选字段时不包含', () { final element = JournalElement.createSticker( journalId: 'j-1', emoji: '🌸', position: Offset.zero, ); expect(element.content.containsKey('stickerPackId'), isFalse); expect(element.content.containsKey('stickerId'), isFalse); expect(element.content['emoji'], '🌸'); }); // ===== copyWith 不可变性 ===== test('copyWith 返回新实例且不修改原始', () { final original = JournalElement.createText( journalId: 'j-1', text: '原始', position: Offset.zero, ); final modified = original.copyWith( positionX: 100.0, positionY: 200.0, ); expect(identical(original, modified), isFalse); expect(original.positionX, 0.0); expect(original.positionY, 0.0); expect(modified.positionX, 100.0); expect(modified.positionY, 200.0); expect(modified.journalId, original.journalId); expect(modified.id, original.id); }); // ===== 序列化 ===== test('toJson / fromJson 往返一致', () { final original = JournalElement.createText( journalId: 'j-1', text: '序列化测试', position: const Offset(42, 84), fontSize: 20.0, ); final json = original.toJson(); final restored = JournalElement.fromJson(json); expect(restored.id, original.id); expect(restored.journalId, original.journalId); expect(restored.elementType, original.elementType); expect(restored.positionX, original.positionX); expect(restored.positionY, original.positionY); expect(restored.content['text'], original.content['text']); expect(restored.version, original.version); }); test('fromJson 处理空 content', () { final json = { 'id': 'test-id', 'journal_id': 'j-1', 'element_type': 'text', 'position_x': 0.0, 'position_y': 0.0, 'width': 100.0, 'height': 100.0, 'rotation': 0.0, 'z_index': 0, 'content': {}, 'version': 1, 'created_at': DateTime.now().toIso8601String(), 'updated_at': DateTime.now().toIso8601String(), }; final element = JournalElement.fromJson(json); expect(element.content, isA()); expect(element.content, isEmpty); }); // ===== ElementType 枚举 ===== test('ElementType 枚举值完整', () { expect(ElementType.values.length, 5); expect(ElementType.values, containsAll([ ElementType.text, ElementType.image, ElementType.sticker, ElementType.handwritingRef, ElementType.tape, ])); }); }); }