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/models/path_selection_test.dart

120 lines
3.6 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/contact.dart';
import 'package:meshcore_open/models/path_selection.dart';
Contact _contact({
required int pathLength,
required int pathHashWidth,
List<int> path = const [],
int? pathOverride,
List<int>? pathOverrideBytes,
}) {
return Contact(
publicKey: Uint8List(32),
name: 'R',
type: advTypeRepeater,
pathLength: pathLength,
pathHashWidth: pathHashWidth,
path: Uint8List.fromList(path),
pathOverride: pathOverride,
pathOverrideBytes: pathOverrideBytes == null
? null
: Uint8List.fromList(pathOverrideBytes),
lastSeen: DateTime.utc(2026),
);
}
void main() {
const pathLenOffset = 35; // 1 cmd + 32 pubKey + 1 type + 1 flags
group('resolvePathSelection width (#279)', () {
test('device path reports true hops + the captured width', () {
// Bandit 2026-08-01: a 6-hop 2-byte route (12 path bytes). It must NOT be
// reported as 12 hops nor sent at width 1.
final bytes = [
0xC6, 0x5C, 0x64, 0x7A, 0x75, 0xC9, //
0x73, 0x60, 0xF6, 0x9F, 0xFB, 0x97,
];
final r = resolvePathSelection(
_contact(pathLength: 6, pathHashWidth: 2, path: bytes),
);
expect(r.useFlood, isFalse);
expect(r.hopCount, 6);
expect(r.hashWidth, 2);
expect(r.pathBytes.length, 12);
});
test('end to end: the device path encodes as 0x46, not 0x06', () {
final bytes = [
0xC6, 0x5C, 0x64, 0x7A, 0x75, 0xC9, //
0x73, 0x60, 0xF6, 0x9F, 0xFB, 0x97,
];
final r = resolvePathSelection(
_contact(pathLength: 6, pathHashWidth: 2, path: bytes),
);
final frame = buildUpdateContactPathFrame(
Uint8List(32),
Uint8List.fromList(r.pathBytes),
r.hopCount,
hashWidth: r.hashWidth,
);
expect(frame[pathLenOffset], 0x46);
expect(pathHopCount(frame[pathLenOffset]), 6);
expect(pathHashSizeBytes(frame[pathLenOffset]), 2);
});
test('override: one 2-byte hop is 1 hop at width 2, not 2 hops', () {
// The dialog stores pathOverride as a BYTE count (2); the selection must
// still resolve to a single 2-byte hop.
final r = resolvePathSelection(
_contact(
pathLength: 1,
pathHashWidth: 2,
pathOverride: 2,
pathOverrideBytes: [0xC6, 0x5C],
),
);
expect(r.hopCount, 1);
expect(r.hashWidth, 2);
});
test('legacy 1-byte net is unchanged', () {
final r = resolvePathSelection(
_contact(pathLength: 3, pathHashWidth: 1, path: [0xAA, 0xBB, 0xCC]),
);
expect(r.hopCount, 3);
expect(r.hashWidth, 1);
});
test('flood override passes through as flood', () {
final r = resolvePathSelection(
_contact(pathLength: 0, pathHashWidth: 2, pathOverride: -1),
);
expect(r.useFlood, isTrue);
expect(r.hopCount, -1);
});
test('path-history retry derives width from the contact', () {
final retry = const PathSelection(
pathBytes: [0xC6, 0x5C, 0xA1, 0xB2],
hopCount: 99, // stale/ambiguous; must be recomputed
useFlood: false,
);
final r = resolvePathSelection(
_contact(
pathLength: 2,
pathHashWidth: 2,
path: [0x00, 0x00, 0x00, 0x00],
),
selection: retry,
);
expect(r.pathBytes.length, 4);
expect(r.hopCount, 2);
expect(r.hashWidth, 2);
});
});
}

Powered by TurnKey Linux.