import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:dmc_app/transport/loopback/loopback_transport.dart'; import 'package:dmc_app/transport/msp/msp_client.dart'; import 'package:dmc_app/transport/msp/msp_commands.dart'; import 'package:dmc_app/transport/msp/msp_frame.dart'; import 'package:dmc_app/transport/msp/msp_frame_decoder.dart'; MspFrame _decodeSingle(Uint8List bytes) => MspFrameDecoder().addBytes(bytes).single; void main() { late LoopbackTransport transport; setUp(() async { transport = LoopbackTransport(); await transport.connect(); }); tearDown(() { transport.dispose(); }); test('request() sendet einen MSPv2-Rahmen und liefert den Antwort-Payload', () async { final client = MspClient(transport); final future = client.request(MspCommands.altitude); await Future.delayed(Duration.zero); expect(transport.sentData, hasLength(1)); final sentFrame = _decodeSingle(transport.sentData.single); expect(sentFrame.direction, MspDirection.request); expect(sentFrame.function, MspCommands.altitude); final payload = Uint8List.fromList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); transport.feed( encodeMspV2Frame(MspDirection.response, MspCommands.altitude, payload), ); expect(await future, payload); client.dispose(); }); test('wirft nach Timeout + Wiederholungen MspRequestException und sendet ' 'jedes Mal erneut', () async { final client = MspClient( transport, requestTimeout: const Duration(milliseconds: 30), maxRetries: 2, ); await expectLater( client.request(MspCommands.altitude), throwsA(isA()), ); // Erstversuch + 2 Wiederholungen = 3 gesendete Anfragen. expect(transport.sentData, hasLength(3)); for (final sent in transport.sentData) { expect(_decodeSingle(sent).function, MspCommands.altitude); } client.dispose(); }); test('Fehlerantwort (dir = \'!\') wirft sofort ohne weiteren Versuch', () async { final client = MspClient( transport, requestTimeout: const Duration(seconds: 5), maxRetries: 2, ); final future = client.request(MspCommands.altitude); await Future.delayed(Duration.zero); transport.feed( encodeMspV2Frame(MspDirection.error, MspCommands.altitude, Uint8List(0)), ); await expectLater(future, throwsA(isA())); expect(transport.sentData, hasLength(1)); client.dispose(); }); test('serialisiert ueberlappende Anfragen - immer nur eine offen', () async { final client = MspClient(transport); final future1 = client.request(MspCommands.rawGps); final future2 = client.request(MspCommands.altitude); await Future.delayed(Duration.zero); expect(transport.sentData, hasLength(1)); expect(_decodeSingle(transport.sentData.single).function, MspCommands.rawGps); transport.feed(encodeMspV2Frame( MspDirection.response, MspCommands.rawGps, Uint8List(18), )); await future1; await Future.delayed(Duration.zero); expect(transport.sentData, hasLength(2)); expect(_decodeSingle(transport.sentData[1]).function, MspCommands.altitude); transport.feed(encodeMspV2Frame( MspDirection.response, MspCommands.altitude, Uint8List(10), )); await future2; client.dispose(); }); }