Files
biz_xfj_cloud/test/common/serial_card_protocol_test.dart
T
2026-07-28 21:34:12 +08:00

273 lines
9.1 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 业务卡号保留完整长度并使用 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<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('旧设置缺失时使用兼容默认值并支持 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,
);
});
});
}