Commit bfdf6ac

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-06-22 18:16:31
implement FakeFlutterBluePlus for manual testing
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 6903053
app/lib/bluetooth/mock/fake_characteristic.dart
@@ -0,0 +1,84 @@
+import 'dart:async';
+
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+class FakeBleBpCharacteristic implements BluetoothCharacteristic {
+  final StreamController<List<int>> _valueReceivedController = StreamController.broadcast();
+
+  @override
+  Guid get characteristicUuid => Guid('2A35');
+  @override
+  Guid get uuid => characteristicUuid;
+
+  @override
+  Stream<List<int>> get onValueReceived => _valueReceivedController.stream;
+
+  @override
+  Future<bool> setNotifyValue(bool notify, {int timeout = 15, bool forceIndications = false}) async{
+    if (notify) {
+      _valueReceivedController.add([22, 124, 0, 86, 0, 97, 0, 232, 7, 6, 15, 17, 17, 27, 51, 0, 0, 0]);
+    }
+    return true;
+  }
+
+  @override
+  // TODO: implement descriptors
+  List<BluetoothDescriptor> get descriptors => throw UnimplementedError();
+
+  @override
+  // TODO: implement device
+  BluetoothDevice get device => throw UnimplementedError();
+
+  @override
+  // TODO: implement deviceId
+  DeviceIdentifier get deviceId => throw UnimplementedError();
+
+  @override
+  // TODO: implement isNotifying
+  bool get isNotifying => throw UnimplementedError();
+
+  @override
+  // TODO: implement lastValue
+  List<int> get lastValue => throw UnimplementedError();
+
+  @override
+  // TODO: implement lastValueStream
+  Stream<List<int>> get lastValueStream => throw UnimplementedError();
+
+  @override
+  // TODO: implement onValueChangedStream
+  Stream<List<int>> get onValueChangedStream => throw UnimplementedError();
+
+  @override
+  // TODO: implement properties
+  CharacteristicProperties get properties => throw UnimplementedError();
+
+  @override
+  Future<List<int>> read({int timeout = 15}) {
+    // TODO: implement read
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement remoteId
+  DeviceIdentifier get remoteId => throw UnimplementedError();
+
+  @override
+  // TODO: implement secondaryServiceUuid
+  Guid? get secondaryServiceUuid => throw UnimplementedError();
+
+  @override
+  // TODO: implement serviceUuid
+  Guid get serviceUuid => throw UnimplementedError();
+
+  @override
+  // TODO: implement value
+  Stream<List<int>> get value => throw UnimplementedError();
+
+  @override
+  Future<void> write(List<int> value, {bool withoutResponse = false, bool allowLongWrite = false, int timeout = 15}) {
+    // TODO: implement write
+    throw UnimplementedError();
+  }
+
+}
\ No newline at end of file
app/lib/bluetooth/mock/fake_device.dart
@@ -0,0 +1,187 @@
+import 'dart:async';
+
+import 'package:blood_pressure_app/bluetooth/mock/fake_service.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+class FakeDevice implements BluetoothDevice {
+  FakeDevice() {
+    Timer.periodic(Duration(seconds: 2), (timer) {
+      _connectedController.add(_connected ? BluetoothConnectionState.connected : BluetoothConnectionState.disconnected);
+    });
+  }
+
+  bool _connected = false;
+  StreamController<BluetoothConnectionState> _connectedController = StreamController.broadcast();
+
+
+  List<BluetoothService> _services = [
+    FakeBleBPService(),
+  ];
+
+  String _platformName = 'test device 1234';
+
+  AdvertisementData createFakeData() => AdvertisementData(
+    advName: advName,
+    txPowerLevel: null,
+      appearance: null,
+      connectable: true,
+      manufacturerData: {},
+      serviceData: {},
+      serviceUuids: [],
+  );
+
+  @override
+  String get advName => platformName;
+
+  @override
+  // TODO: implement bondState
+  Stream<BluetoothBondState> get bondState => throw UnimplementedError();
+
+  @override
+  void cancelWhenDisconnected(StreamSubscription subscription, {bool next = false, bool delayed = false}) {
+    // TODO: implement cancelWhenDisconnected
+  }
+
+  @override
+  Future<void> clearGattCache() {
+    // TODO: implement clearGattCache
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> connect({Duration timeout = const Duration(seconds: 35), int? mtu = 512, bool autoConnect = false}) async {
+    print('CALLED CONNECT');
+    _connected = true;
+    final state = _connected
+        ? BluetoothConnectionState.connected
+        : BluetoothConnectionState.disconnected;
+    _connectedController.add(state);
+  }
+
+  @override
+  Stream<BluetoothConnectionState> get connectionState => _connectedController.stream;
+
+  @override
+  Future<void> createBond({int timeout = 90}) {
+    // TODO: implement createBond
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> disconnect({int timeout = 35, bool queue = true}) async {
+    print('CALLED DISCONNECT:');
+    debugPrintStack();
+    _connected = false;
+    final state = _connected
+        ? BluetoothConnectionState.connected
+        : BluetoothConnectionState.disconnected;
+    _connectedController.add(state);
+  }
+
+  @override
+  DisconnectReason? get disconnectReason => null;
+
+  @override
+  Future<List<BluetoothService>> discoverServices({bool subscribeToServicesChanged = true, int timeout = 15}) async {
+    assert(_connected);
+    return _services;
+  }
+
+  @override
+  // TODO: implement id
+  DeviceIdentifier get id => throw UnimplementedError();
+
+  @override
+  bool get isAutoConnectEnabled => false;
+
+  @override
+  bool get isConnected => _connected;
+
+  @override
+  bool get isDisconnected => !_connected;
+
+  @override
+  // TODO: implement isDiscoveringServices
+  Stream<bool> get isDiscoveringServices => throw UnimplementedError();
+
+  @override
+  // TODO: implement localName
+  String get localName => throw UnimplementedError();
+
+  @override
+  // TODO: implement mtu
+  Stream<int> get mtu => throw UnimplementedError();
+
+  @override
+  // TODO: implement mtuNow
+  int get mtuNow => throw UnimplementedError();
+
+  @override
+  // TODO: implement name
+  String get name => throw UnimplementedError();
+
+  @override
+  // TODO: implement onServicesReset
+  Stream<void> get onServicesReset => throw UnimplementedError();
+
+  @override
+  Future<void> pair() {
+    // TODO: implement pair
+    throw UnimplementedError();
+  }
+
+  @override
+  String get platformName => _platformName;
+
+  @override
+  // TODO: implement prevBondState
+  BluetoothBondState? get prevBondState => throw UnimplementedError();
+
+  @override
+  Future<int> readRssi({int timeout = 15}) {
+    // TODO: implement readRssi
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement remoteId
+  DeviceIdentifier get remoteId => throw UnimplementedError();
+
+  @override
+  Future<void> removeBond({int timeout = 30}) {
+    // TODO: implement removeBond
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> requestConnectionPriority({required ConnectionPriority connectionPriorityRequest}) {
+    // TODO: implement requestConnectionPriority
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<int> requestMtu(int desiredMtu, {double predelay = 0.35, int timeout = 15}) {
+    // TODO: implement requestMtu
+    throw UnimplementedError();
+  }
+
+  @override
+  Stream<List<BluetoothService>> get services => Stream.value(_services);
+
+  @override
+  List<BluetoothService> get servicesList => _services;
+
+  @override
+  Stream<List<BluetoothService>> get servicesStream => Stream.value(_services);
+
+  @override
+  Future<void> setPreferredPhy({required int txPhy, required int rxPhy, required PhyCoding option}) {
+    // TODO: implement setPreferredPhy
+    throw UnimplementedError();
+  }
+
+  @override
+  Stream<BluetoothConnectionState> get state => connectionState;
+
+}
app/lib/bluetooth/mock/fake_flutter_blue_plus.dart
@@ -0,0 +1,105 @@
+import 'dart:async';
+
+import 'package:blood_pressure_app/bluetooth/flutter_blue_plus_mockable.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+import 'fake_device.dart';
+
+/// Wrapper for FlutterBluePlus in order to easily mock it
+/// Wraps all calls for testing purposes
+class FakeFlutterBluePlus extends FlutterBluePlusMockable {
+  FakeFlutterBluePlus(): assert(kDebugMode);
+
+  final BluetoothAdapterState _kFakeAdapterState = BluetoothAdapterState.on;
+  final List<ScanResult> _kFakeScanResults = [
+    ScanResult(
+      device: FakeDevice(),
+      advertisementData: FakeDevice().createFakeData(),
+      rssi: 123,
+      timeStamp: DateTime.now()
+    )
+  ];
+
+  StreamController<List<ScanResult>> _fakeScanResultsEmiter = StreamController.broadcast();
+  Timer? _fakeScanResultsEmitTimer;
+
+  @override
+  BluetoothAdapterState get adapterStateNow => BluetoothAdapterState.on;
+
+  StreamController<bool> _isScanning = StreamController.broadcast();
+  bool _scanningNow = false;
+
+  @override
+  Stream<bool> get isScanning => _isScanning.stream;
+
+  @override
+  bool get isScanningNow => _scanningNow;
+
+  @override
+  List<ScanResult> get lastScanResults => _kFakeScanResults;
+
+  @override
+  Stream<List<ScanResult>> get scanResults => _fakeScanResultsEmiter.stream;
+
+  @override
+  Stream<List<ScanResult>> get onScanResults => _fakeScanResultsEmiter.stream;
+
+  @override
+  BluetoothEvents get events => throw UnimplementedError();
+
+  @override
+  Stream<BluetoothAdapterState> get adapterState => Stream.value(_kFakeAdapterState);
+
+  @override
+  List<BluetoothDevice> get connectedDevices => throw UnimplementedError();
+
+  @override
+  Future<List<BluetoothDevice>> get systemDevices => throw UnimplementedError();
+
+  @override
+  Future<List<BluetoothDevice>> get bondedDevices => throw UnimplementedError();
+
+  @override
+  Future<void> setOptions({bool showPowerAlert = true,}) => throw UnimplementedError();
+
+  @override
+  Future<void> turnOn({int timeout = 60}) async => null;
+
+  @override
+  Future<void> startScan({
+    List<Guid> withServices = const [],
+    List<String> withRemoteIds = const [],
+    List<String> withNames = const [],
+    List<String> withKeywords = const [],
+    List<MsdFilter> withMsd = const [],
+    List<ServiceDataFilter> withServiceData = const [],
+    Duration? timeout,
+    Duration? removeIfGone,
+    bool continuousUpdates = false,
+    int continuousDivisor = 1,
+    bool oneByOne = false,
+    AndroidScanMode androidScanMode = AndroidScanMode.lowLatency,
+    bool androidUsesFineLocation = false,
+  }) async {
+    assert(_fakeScanResultsEmitTimer == null);
+    _scanningNow = true;
+    _fakeScanResultsEmitTimer = Timer.periodic(Duration(seconds: 1), (timer) {
+      _fakeScanResultsEmiter.add(_kFakeScanResults);
+    });
+  }
+
+  @override
+  Future<void> stopScan() async {
+    _scanningNow = false;
+    _fakeScanResultsEmitTimer!.cancel();
+  }
+
+  @override
+  void cancelWhenScanComplete(StreamSubscription subscription) =>
+      FlutterBluePlus.cancelWhenScanComplete(subscription); // TODO: figure out if useful
+
+
+  @override
+  Future<PhySupport> getPhySupport() => throw UnimplementedError();
+}
\ No newline at end of file
app/lib/bluetooth/mock/fake_service.dart
@@ -0,0 +1,29 @@
+import 'package:blood_pressure_app/bluetooth/mock/fake_characteristic.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+class FakeBleBPService implements BluetoothService {
+  @override
+  List<BluetoothCharacteristic> get characteristics => [FakeBleBpCharacteristic()];
+
+  @override
+  // TODO: implement deviceId
+  DeviceIdentifier get deviceId => throw UnimplementedError();
+
+  @override
+  List<BluetoothService> get includedServices => [];
+
+  @override
+  // TODO: implement isPrimary
+  bool get isPrimary => throw UnimplementedError();
+
+  @override
+  // TODO: implement remoteId
+  DeviceIdentifier get remoteId => throw UnimplementedError();
+
+  @override
+  Guid get serviceUuid => Guid('1810');
+
+  @override
+  Guid get uuid => Guid('1810');
+
+}
app/lib/bluetooth/mock/mock_ble_read_cubit.dart
@@ -0,0 +1,35 @@
+import 'package:blood_pressure_app/bluetooth/ble_read_cubit.dart';
+import 'package:blood_pressure_app/bluetooth/characteristics/ble_measurement_data.dart';
+import 'package:blood_pressure_app/bluetooth/characteristics/ble_measurement_status.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+class MockBleReadCubit extends Cubit<BleReadState> implements BleReadCubit {
+  MockBleReadCubit(): super(BleReadSuccess(
+    BleMeasurementData(
+      systolic: 123,
+      diastolic: 456,
+      pulse: 67,
+      meanArterialPressure: 123456,
+      isMMHG: true,
+      userID: 3,
+      status: BleMeasurementStatus(
+        bodyMovementDetected: true,
+        cuffTooLose: true,
+        irregularPulseDetected: true,
+        pulseRateInRange: true,
+        pulseRateExceedsUpperLimit: true,
+        pulseRateIsLessThenLowerLimit: true,
+        improperMeasurementPosition: true,
+      ),
+      timestamp: DateTime.now(),
+    ),
+  ));
+
+  @override
+  Guid get characteristicUUID => throw UnimplementedError();
+
+  @override
+  Guid get serviceUUID => throw UnimplementedError();
+
+}
app/lib/components/dialoges/add_measurement_dialoge.dart
@@ -285,6 +285,7 @@ class _AddEntryDialogeState extends State<AddEntryDialoge> {
             if (widget.settings.bleInput)
               BluetoothInput(
                 settings: widget.settings,
+                /* flutterBluePlus: FakeFlutterBluePlus(), */
                 onMeasurement: (record) => setState(() => _loadFields(record)),
               ),
             if (widget.settings.allowManualTimeInput)