import 'package:flutter_test/flutter_test.dart'; import 'package:jiu_client/core/utils/label_template.dart'; /// 锁死模板存储读写(走 shop.custom_fields,零后端改动)与 JSON 往返, /// 不触真实库——纯内存对象校验。 void main() { group('LabelTemplate 存储 helpers', () { test('custom_fields 无模板时回退内置默认', () { final list = readLabelTemplates({}); expect(list, hasLength(1)); expect(list.first.id, 'builtin-default'); }); test('activeLabelTemplate 按 id 命中,缺失回退第一项', () { final a = LabelTemplate.builtinDefault(); final b = a.copyWith(id: 'tpl-2', name: '大字号'); final cf = { 'label_templates': [a.toJson(), b.toJson()], 'label_template_active': 'tpl-2', }; expect(activeLabelTemplate(cf).id, 'tpl-2'); cf['label_template_active'] = 'nope'; expect(activeLabelTemplate(cf).id, 'builtin-default'); }); test('toJson → fromJson 往返保真(几何/开关/样式)', () { final src = LabelTemplate.builtinDefault(); src.textStack.subLines[0].fontSize = 16; src.textStack.subLines[0].bold = true; src.qr.size = 120; src.print.direction = 0; final back = LabelTemplate.fromJson(src.toJson()); expect(back.textStack.subLines[0].fontSize, 16); expect(back.textStack.subLines[0].bold, true); expect(back.qr.size, 120); expect(back.print.direction, 0); }); test('存 → 读回列表保持顺序与命名', () { final a = LabelTemplate.builtinDefault(); final b = a.copyWith(id: 'tpl-2', name: '双语抬头'); final cf = { 'label_templates': [a.toJson(), b.toJson()], }; final list = readLabelTemplates(cf); expect(list.map((t) => t.id), ['builtin-default', 'tpl-2']); expect(list[1].name, '双语抬头'); }); test('老店铺旧默认 QR 加载时自动升级为居中坐标', () { final def = LabelTemplate.builtinDefault(); // 构造两个历史默认签名的模板(贴头顶版 + 中间偏上版) final legacyA = def.copyWith(id: 'tpl-legacy-a', name: '旧模板A'); legacyA.qr ..x = 178 ..y = 25 ..size = 134; final legacyB = def.copyWith(id: 'tpl-legacy-b', name: '旧模板B'); legacyB.qr ..x = 190 ..y = 34 ..size = 116; final cf = { 'label_templates': [legacyA.toJson(), legacyB.toJson()], }; final list = readLabelTemplates(cf); for (final t in list) { expect(t.qr.x, def.qr.x, reason: '${t.name} QR.x 应升级到新默认'); expect(t.qr.y, def.qr.y, reason: '${t.name} QR.y 应升级到新默认'); expect(t.qr.size, def.qr.size, reason: '${t.name} QR.size 应升级到新默认'); } }); test('内置默认模板永远回代码基准:存储里被改脏也覆盖回 builtinDefault', () { final def = LabelTemplate.builtinDefault(); // 模拟老库存的 builtin-default:品名被关、QR 乱改、字号乱改 final stale = def.copyWith(); stale.textStack.name.show = false; stale.qr ..x = 10 ..y = 10 ..size = 200; stale.textStack.subLines[0].fontSize = 99; final cf = { 'label_templates': [stale.toJson()], }; final t = readLabelTemplates(cf).firstWhere((x) => x.id == 'builtin-default'); expect(t.textStack.name.show, isTrue, reason: '品名默认必须展示'); expect(t.qr.x, def.qr.x); expect(t.qr.y, def.qr.y); expect(t.qr.size, def.qr.size); expect(t.textStack.subLines[0].fontSize, def.textStack.subLines[0].fontSize); }); test('用户自定义过的 QR 不匹配旧签名,加载时保持不动', () { final custom = LabelTemplate.builtinDefault().copyWith( id: 'tpl-custom', name: '自定义位置', ); custom.qr ..x = 210 ..y = 60 ..size = 80; // 与任一历史默认都不同 final cf = { 'label_templates': [custom.toJson()], }; final t = readLabelTemplates(cf).first; expect(t.qr.x, 210); expect(t.qr.y, 60); expect(t.qr.size, 80); }); }); }