test(tcp): harden cancel-race handling and add coverage

- tighten late TCP connect error suppression to manual-cancel disconnecting/disconnected windows
- keep TCP handshake failures surfaced outside explicit cancel flow
- allow TcpScreen connect action when connector is scanning
- add connector-level tests for late-error suppression classifier
- add TcpScreen test covering connect from scanning state
This commit is contained in:
just-stuff-tm
2026-03-10 20:06:05 -04:00
parent 1913a5aa11
commit 9db79e9d40
4 changed files with 113 additions and 5 deletions
@@ -0,0 +1,64 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:meshcore_open/connector/meshcore_connector.dart';
void main() {
group('shouldIgnoreLateTcpConnectError', () {
test('returns true for manual cancel during disconnecting state', () {
final result = MeshCoreConnector.shouldIgnoreLateTcpConnectError(
manualDisconnect: true,
state: MeshCoreConnectionState.disconnecting,
activeTransport: MeshCoreTransportType.bluetooth,
tcpManagerConnected: false,
);
expect(result, isTrue);
});
test(
'returns true for manual cancel after reaching disconnected state',
() {
final result = MeshCoreConnector.shouldIgnoreLateTcpConnectError(
manualDisconnect: true,
state: MeshCoreConnectionState.disconnected,
activeTransport: MeshCoreTransportType.bluetooth,
tcpManagerConnected: false,
);
expect(result, isTrue);
},
);
test('returns false when not a manual disconnect', () {
final result = MeshCoreConnector.shouldIgnoreLateTcpConnectError(
manualDisconnect: false,
state: MeshCoreConnectionState.disconnecting,
activeTransport: MeshCoreTransportType.bluetooth,
tcpManagerConnected: false,
);
expect(result, isFalse);
});
test('returns false for connected state handshake failures', () {
final result = MeshCoreConnector.shouldIgnoreLateTcpConnectError(
manualDisconnect: true,
state: MeshCoreConnectionState.connected,
activeTransport: MeshCoreTransportType.tcp,
tcpManagerConnected: true,
);
expect(result, isFalse);
});
test('returns false when TCP is still active while disconnecting', () {
final result = MeshCoreConnector.shouldIgnoreLateTcpConnectError(
manualDisconnect: true,
state: MeshCoreConnectionState.disconnecting,
activeTransport: MeshCoreTransportType.tcp,
tcpManagerConnected: true,
);
expect(result, isFalse);
});
});
}
+23
View File
@@ -135,6 +135,29 @@ void main() {
await tester.pump(const Duration(milliseconds: 60));
});
testWidgets('TcpScreen allows connect while connector is scanning', (
tester,
) async {
final connector = _FakeMeshCoreConnector()
..initialState = MeshCoreConnectionState.scanning;
await tester.pumpWidget(
_buildTestApp(
connector: connector,
child: const TcpScreen(),
locale: const Locale('en'),
),
);
await tester.pumpAndSettle();
await tester.tap(find.widgetWithText(FilledButton, 'Connect'));
await tester.pumpAndSettle();
expect(connector.connectTcpCalls, 1);
expect(connector.lastHost, '192.168.40.10');
expect(connector.lastPort, 5000);
});
testWidgets('TcpScreen narrow width long status text does not overflow', (
tester,
) async {