import 'package:flutter_test/flutter_test.dart'; import 'package:pj_supermarket_cloud/common/models/plugs/serial_card_models.dart'; import 'package:pj_supermarket_cloud/common/utils/manage/tool/serial_read_card_tool.dart'; import 'package:pj_supermarket_cloud/common/utils/manage/tool/serial_tool.dart'; void main() { group('DK25-ST 帧解码', () { test('按长度字段合并分包', () { final decoder = SerialCardFrameDecoder(); expect(decoder.add([0xAA, 0x05, 0x01]), isEmpty); final frames = decoder.add([0x16, 0xAB, 0xE1, 0xC5]); expect(frames, hasLength(1)); expect(frames.single.command, SerialReadCardTool.getUidCommand); expect(frames.single.payload, [0x16, 0xAB, 0xE1, 0xC5]); }); test('一次提取粘连的多个帧并忽略帧前噪声', () { final decoder = SerialCardFrameDecoder(); final frames = decoder.add([ 0x00, 0x55, 0xAA, 0x02, 0x02, 0x01, 0xAA, 0x01, 0xFE, ]); expect(frames, hasLength(2)); expect(frames.first.command, SerialReadCardTool.getCardTypeCommand); expect(frames.first.payload, [SerialCardType.mifare.code]); expect(frames.last.isAck, isTrue); final malformedAck = decoder.add([0xAA, 0x02, 0xFE, 0x00]).single; expect(malformedAck.isAck, isFalse); }); test('AA1204 空块响应按协议拆出块地址和 16 字节数据', () { final decoder = SerialCardFrameDecoder(); final frame = decoder.add([ 0xAA, 0x12, 0x04, 0x01, ...List.filled(16, 0), ]).single; expect(frame.command, SerialReadCardTool.mifareReadBlockCommand); expect(frame.payload.first, 1); expect(frame.payload.sublist(1), List.filled(16, 0)); expect( SerialReadCardTool.decodeMifareBlockData(frame.payload.sublist(1)), isNull, ); }); }); group('DK25-ST 命令组装', () { test('通用、M1 密钥与块读写命令符合手册长度定义', () { expect(SerialReadCardTool.getUidRequest(), [0xAA, 0x01, 0x01]); expect(SerialReadCardTool.getCardTypeRequest(), [0xAA, 0x01, 0x02]); expect( SerialReadCardTool.saveMifareKeyRequest( keyType: SerialMifareKeyType.keyA, keyBytes: List.filled(6, 0xFF), ), [0xAA, 0x07, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], ); expect( SerialReadCardTool.setMifareKeyTypeRequest( SerialMifareKeyType.keyB, ), [0xAA, 0x02, 0x0C, 0x0B], ); expect( SerialReadCardTool.readMifareBlockRequest(1), [0xAA, 0x02, 0x04, 0x01], ); expect( SerialReadCardTool.canSafelyRepeatRequest( SerialReadCardTool.getCardTypeRequest(), ), isTrue, ); expect( SerialReadCardTool.canSafelyRepeatRequest( SerialReadCardTool.saveMifareKeyRequest( keyType: SerialMifareKeyType.keyA, keyBytes: List.filled(6, 0xFF), ), ), isFalse, ); expect( SerialReadCardTool.canSafelyRepeatRequest( SerialReadCardTool.writeMifareBlockRequest( blockAddress: 1, blockData: List.filled(16, 0), ), ), isFalse, ); }); test('M1 业务卡号保留完整长度并使用 0x00 补齐', () { final block = SerialReadCardTool.encodeMifareBlockData('12345678901234'); expect(block, hasLength(16)); expect( SerialReadCardTool.decodeMifareBlockData(block!), '12345678901234'); expect(block.sublist(14), [0, 0]); expect( SerialReadCardTool.encodeMifareBlockData('12345678901234567'), isNull, ); expect(SerialReadCardTool.encodeMifareBlockData('中文卡号'), isNull); expect( SerialReadCardTool.decodeMifareBlockData(List.filled(16, 0)), isNull); }); test('显式 UID 与自动寻卡带类型 UID 均保留完整位数', () { const uid = [0x16, 0xAB, 0xE1, 0xC5]; expect( SerialReadCardTool.extractUidPayload( cardType: SerialCardType.mifare, payload: uid, ), uid, ); expect( SerialReadCardTool.extractUidPayload( cardType: SerialCardType.mifare, payload: [SerialCardType.mifare.code, ...uid], ), uid, ); expect(SerialReadCardTool.uidToCardNumber(uid), '16ABE1C5'); expect( SerialReadCardTool.extractUidPayload( cardType: SerialCardType.undefined, payload: [SerialCardType.undefined.code, ...List.filled(7, 0x11)], ), List.filled(7, 0x11), ); }); test('忽略复用 0x01 指令码但长度不符合卡型的自动寻卡扩展数据', () { expect( SerialReadCardTool.extractUidPayload( cardType: SerialCardType.iso14443ACpu, payload: [ SerialCardType.iso14443ACpu.code, ...List.filled(20, 0x31), ], ), isNull, ); }); test('禁止把 M1 扇区密钥块当作业务数据块', () { expect(SerialReadCardTool.isMifareTrailerBlock(3), isTrue); expect(SerialReadCardTool.isMifareTrailerBlock(127), isTrue); expect(SerialReadCardTool.isMifareTrailerBlock(143), isTrue); expect(SerialReadCardTool.isMifareTrailerBlock(159), isTrue); expect(SerialReadCardTool.isMifareTrailerBlock(1), isFalse); expect(SerialReadCardTool.isMifareTrailerBlock(142), isFalse); expect(SerialReadCardTool.isMifareBusinessDataBlock(0), isFalse); expect(SerialReadCardTool.isMifareBusinessDataBlock(1), isTrue); expect(SerialReadCardTool.isMifareBusinessDataBlock(3), isFalse); }); test('M1 扫描地址只包含 S50/S70 的安全数据块', () { final addresses = SerialReadCardTool.mifareSafeDataBlockAddresses(); expect(addresses, hasLength(215)); expect(addresses.where((address) => address <= 63), hasLength(47)); expect(addresses.first, 1); expect(addresses.last, 254); expect(addresses, isNot(contains(0))); expect(addresses, isNot(contains(3))); expect(addresses, isNot(contains(127))); expect(addresses, isNot(contains(143))); expect(addresses, isNot(contains(255))); }); test('扫描忽略全零和全 FF 块并识别不限 12 位的卡号候选文本', () { expect( SerialReadCardTool.isBlankMifareBlockData(List.filled(16, 0x00)), isTrue, ); expect( SerialReadCardTool.isBlankMifareBlockData(List.filled(16, 0xFF)), isTrue, ); final block = SerialReadCardTool.encodeMifareBlockData('123456789012')!; expect(SerialReadCardTool.isBlankMifareBlockData(block), isFalse); expect( SerialMifareBlockScanItem( blockAddress: 4, hex: SerialTool.bytesToString(block), text: SerialReadCardTool.decodeMifareBlockData(block), ).isCardNumberCandidate, isTrue, ); expect( const SerialMifareBlockScanItem( blockAddress: 5, hex: '4131', text: 'A1', ).isCardNumberCandidate, isTrue, ); }); }); group('读写卡配置', () { test('旧设置缺失时使用兼容默认值并支持 JSON 往返', () { const config = SerialCardConfig( readMode: SerialCardReadMode.uidOnly, mifareBlockAddress: 4, mifareKeyType: SerialMifareKeyType.keyB, keyAHex: 'A0A1A2A3A4A5', keyBHex: 'B0B1B2B3B4B5', showMifareScanButton: true, ); final restored = SerialCardConfig.fromJson(config.toJson()); expect(restored.readMode, SerialCardReadMode.uidOnly); expect(restored.mifareBlockAddress, 4); expect(restored.mifareKeyType, SerialMifareKeyType.keyB); expect(restored.selectedKeyHex, 'B0B1B2B3B4B5'); expect(restored.showMifareScanButton, isTrue); final defaults = SerialCardConfig.fromJson(const {}); expect(defaults.readMode, SerialCardReadMode.smart); expect(defaults.mifareBlockAddress, 1); expect(defaults.keyAHex, SerialCardConfig.defaultKeyHex); expect(defaults.showMifareScanButton, isFalse); final compatible = SerialCardConfig.fromJson(const { 'readMode': 'future_mode', 'mifareKeyType': 'future_key', 'keyAHex': 'invalid', }); expect(compatible.readMode, SerialCardReadMode.smart); expect(compatible.mifareKeyType, SerialMifareKeyType.keyA); expect(compatible.keyAHex, SerialCardConfig.defaultKeyHex); }); test('不同卡型保留手册定义的 UID 长度', () { expect(SerialCardType.mifare.uidLength, 4); expect(SerialCardType.ultralight.uidLength, 7); expect(SerialCardType.iso14443B.uidLength, 8); expect(SerialCardType.iso14443ACpu.uidLength, 4); expect(SerialCardType.iso15693.uidLength, 8); expect( SerialReadCardTool.isValidUidLength(SerialCardType.undefined, 7), isTrue, ); expect( SerialReadCardTool.isValidUidLength(SerialCardType.undefined, 3), isFalse, ); }); }); }