You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
meshcore-client/test/channel_path_len_test.dart

125 lines
4.2 KiB

import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:meshcore_open/connector/meshcore_protocol.dart';
import 'package:meshcore_open/models/channel_message.dart';
// #985: a 13-hop message with 3-byte path hashes (packed path-len 0x8D)
// rendered as "39 hops". Three defects: the V3 path_len field was read
// signed (0x8D became -115, swallowed as the flood sentinel), the log-RX
// ingress stored the width-stripped hop count, and the repeat merge
// substituted the path BYTE length into the packed field.
Uint8List _v3Frame({required int pathLen, String text = 'Dee3: hi'}) {
final textBytes = text.codeUnits;
return Uint8List.fromList([
respCodeChannelMsgRecvV3,
0, // SNR
0, // reserved1 (bit0 = outgoing)
0, // reserved2
2, // channel_idx
pathLen,
txtTypePlain,
0x40, 0xE2, 0x01, 0x00, // timestamp LE
...textBytes,
]);
}
Uint8List _legacyFrame({required int pathLen, String text = 'Dee3: hi'}) {
final textBytes = text.codeUnits;
return Uint8List.fromList([
respCodeChannelMsgRecv,
2, // channel_idx
pathLen,
txtTypePlain,
0x40, 0xE2, 0x01, 0x00, // timestamp LE
...textBytes,
]);
}
void main() {
group('ChannelMessage.fromFrame path-len decode (#985)', () {
test(
'3-byte-width packed byte stays unsigned: 0x8D = 13 hops, width 3',
() {
final m = ChannelMessage.fromFrame(_v3Frame(pathLen: 0x8D))!;
expect(m.pathLength, 0x8D);
expect(m.hopCount, 13);
expect(m.pathHashSize, 3);
},
);
test('2-byte-width packed byte: 0x53 = 19 hops, width 2', () {
final m = ChannelMessage.fromFrame(_v3Frame(pathLen: 0x53))!;
expect(m.hopCount, 19);
expect(m.pathHashSize, 2);
});
test('0xFF stays the direct-route sentinel (-1)', () {
final m = ChannelMessage.fromFrame(_v3Frame(pathLen: 0xFF))!;
expect(m.pathLength, -1);
expect(m.hopCount, -1);
});
test('legacy (non-V3) frame decodes the same way', () {
final m = ChannelMessage.fromFrame(_legacyFrame(pathLen: 0x8D))!;
expect(m.pathLength, 0x8D);
expect(m.hopCount, 13);
expect(m.pathHashSize, 3);
});
});
group('effectivePathHashWidth (#985)', () {
ChannelMessage msg(int? pathLength) => ChannelMessage(
senderName: 'Dee3',
text: 'hi',
timestamp: DateTime.fromMillisecondsSinceEpoch(0),
isOutgoing: false,
status: ChannelMessageStatus.sent,
pathLength: pathLength,
);
test('uses the packet\'s own width when a path-len byte is stored', () {
expect(msg(0x8D).effectivePathHashWidth(2), 3);
expect(msg(0x53).effectivePathHashWidth(1), 2);
expect(msg(13).effectivePathHashWidth(2), 1);
});
test('falls back to the device width for legacy/sentinel records', () {
expect(msg(null).effectivePathHashWidth(2), 2);
expect(msg(-1).effectivePathHashWidth(3), 3);
expect(msg(null).effectivePathHashWidth(0), 1);
});
});
group('mergePathLenRaw (#985)', () {
test('null and sentinel yield to the real packed byte', () {
expect(mergePathLenRaw(null, 0x8D), 0x8D);
expect(mergePathLenRaw(0x8D, null), 0x8D);
expect(mergePathLenRaw(-1, 0x8D), 0x8D);
expect(mergePathLenRaw(0x8D, -1), 0x8D);
expect(mergePathLenRaw(null, null), isNull);
});
test('higher decoded hop count wins, compared in hops not raw bytes', () {
// 0x8E = 14 hops at width 3; 0x8D = 13 hops at width 3.
expect(mergePathLenRaw(0x8D, 0x8E), 0x8E);
// 19 hops at width 2 (0x53) beats 13 hops at width 2 (0x4D).
expect(mergePathLenRaw(0x4D, 0x53), 0x53);
// A width-1 count is NOT outranked by a packed byte's raw magnitude:
// 20 hops at width 1 beats 13 hops at width 3 (raw 0x8D = 141).
expect(mergePathLenRaw(0x8D, 20), 20);
});
test('regression: the Dee3 scenario decodes to 13 hops, never 39', () {
// Two repeats of the same packet, both carrying packed 0x8D. The old
// merge substituted the 39-byte path length, which decoded as
// "39 hops at width 1".
final merged = mergePathLenRaw(0x8D, 0x8D)!;
expect(pathHopCount(merged), 13);
expect(pathHashSizeBytes(merged), 3);
expect(pathByteLength(merged), 39);
});
});
}

Powered by TurnKey Linux.