main
1import 'dart:async';
2
3import 'package:blood_pressure_app/features/bluetooth/backend/flutter_blue_plus/fbp_device.dart';
4import 'package:blood_pressure_app/features/bluetooth/backend/flutter_blue_plus/fbp_manager.dart';
5import 'package:blood_pressure_app/features/bluetooth/backend/flutter_blue_plus/flutter_blue_plus_mockable.dart';
6import 'package:blood_pressure_app/features/bluetooth/logic/device_scan_cubit.dart';
7import 'package:blood_pressure_app/model/storage/settings_store.dart';
8import 'package:flutter_blue_plus/flutter_blue_plus.dart';
9import 'package:flutter_test/flutter_test.dart';
10import 'package:mockito/annotations.dart';
11import 'package:mockito/mockito.dart';
12
13@GenerateNiceMocks([
14 MockSpec<BluetoothDevice>(),
15 MockSpec<BluetoothService>(),
16 MockSpec<FlutterBluePlusMockable>(),
17 MockSpec<ScanResult>(),
18])
19import 'device_scan_cubit_test.mocks.dart';
20
21/// Helper util to create a [MockScanResult] & [MockBluetoothDevice]
22(MockScanResult, MockBluetoothDevice) createScanResultMock(String name) {
23 final scanResult = MockScanResult();
24 final btDevice = MockBluetoothDevice();
25 when(btDevice.platformName).thenReturn(name);
26 when(btDevice.remoteId).thenReturn(DeviceIdentifier(name));
27 when(scanResult.device).thenReturn(btDevice);
28 return (scanResult, btDevice);
29}
30
31void main() {
32 test('finds and connects to devices', () async {
33 final StreamController<List<ScanResult>> mockResults = StreamController.broadcast();
34 final settings = Settings();
35
36 final flutterBluePlus = MockFlutterBluePlusMockable();
37 final manager = FlutterBluePlusManager(flutterBluePlus);
38 expect(flutterBluePlus, manager.backend);
39
40 when(flutterBluePlus.startScan(
41 withServices: [Guid('1810')]
42 )).thenAnswer((_) async {
43 when(flutterBluePlus.isScanningNow).thenReturn(true);
44 });
45 when(flutterBluePlus.stopScan()).thenAnswer((_) async {
46 when(flutterBluePlus.isScanningNow).thenReturn(false);
47 });
48 when(flutterBluePlus.scanResults).thenAnswer((_) => mockResults.stream);
49
50 final cubit = DeviceScanCubit(
51 service: '1810',
52 settings: settings,
53 manager: manager
54 );
55 expect(cubit.state, isA<DeviceListLoading>());
56
57 final (wrongRes0, wrongDev0) = createScanResultMock('wrongDev0');
58 final (wrongRes1, wrongDev1) = createScanResultMock('wrongDev1');
59
60 mockResults.sink.add([wrongRes0]);
61 await expectLater(cubit.stream, emits(isA<SingleDeviceAvailable>()));
62
63 mockResults.sink.add([wrongRes0, wrongRes1]);
64 await expectLater(cubit.stream, emits(isA<DeviceListAvailable>()));
65
66 final (res, dev) = createScanResultMock('testDev');
67 mockResults.sink.add([res]);
68 await expectLater(cubit.stream, emits(isA<DeviceListAvailable>()
69 .having((r) => r.devices.last.source, 'device', res)));
70
71 expect(settings.knownBleDev, isEmpty);
72 await cubit.acceptDevice(FlutterBluePlusDevice(manager, res));
73 expect(settings.knownBleDev, contains('testDev'));
74 // state should be set as we await above
75 await expectLater(cubit.state, isA<DeviceSelected>()
76 .having((s) => s.device.source, 'device', res));
77 });
78
79 test('recognizes devices', () async {
80 final StreamController<List<ScanResult>> mockResults = StreamController.broadcast();
81 final settings = Settings(
82 knownBleDev: ['testDev']
83 );
84
85 final flutterBluePlus = MockFlutterBluePlusMockable();
86 final manager = FlutterBluePlusManager(flutterBluePlus);
87 when(flutterBluePlus.startScan(
88 withServices: [Guid('1810')]
89 )).thenAnswer((_) async {
90 when(flutterBluePlus.isScanningNow).thenReturn(true);
91 });
92 when(flutterBluePlus.stopScan()).thenAnswer((_) async {
93 when(flutterBluePlus.isScanningNow).thenReturn(false);
94 });
95 when(flutterBluePlus.scanResults).thenAnswer((_) => mockResults.stream);
96 final cubit = DeviceScanCubit(
97 service: '1810',
98 settings: settings,
99 manager: manager
100 );
101 expect(cubit.state, isA<DeviceListLoading>());
102
103 final (wrongRes0, wrongDev0) = createScanResultMock('wrongDev0');
104 mockResults.sink.add([wrongRes0]);
105
106 await expectLater(cubit.stream, emits(isA<SingleDeviceAvailable>()));
107
108 final (res, dev) = createScanResultMock('testDev');
109 mockResults.sink.add([wrongRes0, res]);
110
111 // No prompt when finding the correct device again
112 await expectLater(cubit.stream, emits(isA<DeviceSelected>()));
113 });
114}