Files
knx_stack_tpuart/test/knx_tpuart_client_test.dart

167 lines
4.1 KiB
Dart

import 'dart:async';
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:knx_stack/knx_stack.dart';
import 'package:knx_stack_tpuart/knx_stack_tpuart.dart';
void main() {
group('KnxTpUartClient', () {
test('completes the reset and state handshake', () async {
final transport = _FakeKnxTransport();
final client = KnxTpUartClient(transport: transport);
final connectFuture = client.connect();
await _flushMicrotasks();
expect(transport.sentFrames, hasLength(1));
expect(transport.sentFrames.single, [0x01]);
transport.emit(const [0x03]);
await _flushMicrotasks();
expect(transport.sentFrames, hasLength(2));
expect(transport.sentFrames.last, [0x02]);
transport.emit(const [0x07]);
await connectFuture;
expect(client.isConnected, isTrue);
});
test('encodes cEMI writes into TP-UART service bytes', () async {
final transport = _FakeKnxTransport();
final client = KnxTpUartClient(transport: transport);
await _connectClient(client, transport);
final sendFuture = client.send(_sampleCemiWrite().toBytes());
await _flushMicrotasks();
expect(transport.sentFrames.last, [
0x80,
0xbc,
0x81,
0x11,
0x82,
0x01,
0x83,
0x00,
0x84,
0x01,
0x85,
0xe2,
0x86,
0x00,
0x87,
0x80,
0x88,
0x64,
0x49,
0x54,
]);
transport.emit(const [0x8b]);
await sendFuture;
});
test('decodes inbound TP telegrams into cEMI indications', () async {
final transport = _FakeKnxTransport();
final client = KnxTpUartClient(transport: transport);
await _connectClient(client, transport);
final frameFuture = client.inboundFrames.first;
final messageFuture = client.inboundMessages.first;
transport.emit(const [0xbc, 0x11, 0x01, 0x00, 0x01, 0xe2, 0x00, 0x80, 0x64, 0x54]);
expect(await frameFuture, [
0x29,
0x00,
0xbc,
0xe0,
0x11,
0x01,
0x00,
0x01,
0x02,
0x00,
0x80,
0x64,
]);
expect((await messageFuture).destinationAddress.canonical, '0/0/1');
});
});
}
Future<void> _connectClient(KnxTpUartClient client, _FakeKnxTransport transport) async {
final connectFuture = client.connect();
await _flushMicrotasks();
transport.emit(const [0x03]);
await _flushMicrotasks();
transport.emit(const [0x07]);
await connectFuture;
}
Future<void> _flushMicrotasks() async {
await Future<void>.delayed(Duration.zero);
}
CemiLDataReq _sampleCemiWrite() {
final controlField2 = ExtendedControlField()
..addressType = AddressType.group
..hopCount = 6
..eff = ExtendedFrameFormat.pointToPointOrStandardGroupAddressedLDataExtendedFrame;
return CemiLDataReq(
controlField1: ControlField(0xbc),
controlField2: controlField2,
sourceAddress: KnxIndividualAddress.parse('1.1.1'),
destinationAddress: KnxGroupAddress.parse('0/0/1'),
tpdu: TPDU(data: Uint8List.fromList([0x64])),
);
}
final class _FakeKnxTransport implements KnxTransport {
final StreamController<Uint8List> _frames = StreamController<Uint8List>.broadcast();
final List<Uint8List> sentFrames = <Uint8List>[];
bool _isConnected = false;
@override
String get transportId => 'fake_tpuart';
@override
KnxFeature get feature => KnxFeature.tpuartTransport;
@override
KnxFeatureSupport get support => const KnxFeatureSupport.supported(
feature: KnxFeature.tpuartTransport,
platform: KnxPlatform.macos,
);
@override
bool get isConnected => _isConnected;
@override
Stream<Uint8List> get inboundFrames => _frames.stream;
@override
Future<void> connect() async {
_isConnected = true;
}
@override
Future<void> disconnect() async {
_isConnected = false;
}
@override
Future<void> send(Uint8List frame) async {
sentFrames.add(Uint8List.fromList(frame));
}
void emit(List<int> frame) {
_frames.add(Uint8List.fromList(frame));
}
}