Files
biz_xfj_cloud/test/common/serial_card_protocol_test.dart
T
dzc aa4eb7b86e feat:优化下单速度
feat:处理读卡密码
2026-10-14 13:51:12 +08:00

285 lines
9.4 KiB
Dart

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<int>.filled(16, 0),
]).single;
expect(frame.command, SerialReadCardTool.mifareReadBlockCommand);
expect(frame.payload.first, 1);
expect(frame.payload.sublist(1), List<int>.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 业务卡号保留完整长度并使用 0x20 空格补齐(对齐后台)', () {
final block = SerialReadCardTool.encodeMifareBlockData('12345678901234');
expect(block, hasLength(16));
expect(
SerialReadCardTool.decodeMifareBlockData(block!), '12345678901234');
expect(block.sublist(14), [0x20, 0x20]);
expect(
SerialReadCardTool.encodeMifareBlockData('12345678901234567'),
isNull,
);
expect(SerialReadCardTool.encodeMifareBlockData('中文卡号'), isNull);
expect(
SerialReadCardTool.decodeMifareBlockData(List.filled(16, 0)), isNull);
// 历史 0x00 补齐块仍按截断解析,后台空格补齐块按 trim 解析。
expect(
SerialReadCardTool
.decodeMifareBlockData([...'123456'.codeUnits, ...List.filled(10, 0)]),
'123456',
);
expect(
SerialReadCardTool
.decodeMifareBlockData([...'123456'.codeUnits, ...List.filled(10, 0x20)]),
'123456',
);
});
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<int>.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('固定规范常量与服务端默认密钥', () {
expect(SerialCardConfig.mifareBusinessBlockAddress, 5);
expect(SerialCardConfig.defaultKeyHex, '424324548800');
expect(SerialCardType.mifare.uidLength, 4);
});
test('设置缺失时使用服务端默认密钥并支持 JSON 往返', () {
const config = SerialCardConfig(
keyBHex: 'B0B1B2B3B4B5',
showMifareScanButton: true,
);
final restored = SerialCardConfig.fromJson(config.toJson());
expect(restored.keyBHex, 'B0B1B2B3B4B5');
expect(restored.showMifareScanButton, isTrue);
final defaults = SerialCardConfig.fromJson(const {});
expect(defaults.keyBHex, SerialCardConfig.defaultKeyHex);
expect(defaults.showMifareScanButton, isFalse);
});
test('旧版本 JSON 的多余字段被忽略且非法密钥回退默认值', () {
final compatible = SerialCardConfig.fromJson(const {
'readMode': 'uid_only',
'mifareBlockAddress': 1,
'mifareKeyType': 'key_a',
'keyAHex': 'A0A1A2A3A4A5',
'keyBHex': 'invalid',
'showMifareScanButton': true,
});
expect(compatible.keyBHex, SerialCardConfig.defaultKeyHex);
expect(compatible.showMifareScanButton, isTrue);
});
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,
);
});
});
}