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}