@@ -13,6 +13,7 @@ import 'package:borneo_app/features/devices/view_models/device_discovery_view_mo
1313import 'package:borneo_app/core/services/devices/device_manager.dart' ;
1414import 'package:borneo_app/core/services/devices/ble_provisioner.dart' ;
1515import 'package:borneo_app/core/services/devices/device_module_registry.dart' ;
16+ import 'package:borneo_app/core/services/platform_service.dart' ;
1617import 'package:borneo_app/features/devices/models/device_entity.dart' ;
1718import 'package:borneo_app/features/devices/models/device_module_metadata.dart' ;
1819import 'package:lw_wot/wot.dart' ;
@@ -23,6 +24,43 @@ import '../mocks/mocks.dart';
2324
2425// Minimal implementations / fakes for the interfaces used by the view model.
2526
27+ // A tiny fake that lets tests pretend they are running on a particular
28+ // platform without depending on the real `dart:io` APIs.
29+ class FakePlatformService implements PlatformService {
30+ @override
31+ bool isWeb;
32+
33+ @override
34+ bool isAndroid;
35+
36+ @override
37+ bool isIOS;
38+
39+ @override
40+ bool isWindows;
41+
42+ @override
43+ bool isMacOS;
44+
45+ @override
46+ bool isLinux;
47+
48+ FakePlatformService ({
49+ this .isWeb = false ,
50+ this .isAndroid = false ,
51+ this .isIOS = false ,
52+ this .isWindows = false ,
53+ this .isMacOS = false ,
54+ this .isLinux = false ,
55+ });
56+
57+ @override
58+ bool get isMobile => isAndroid || isIOS;
59+
60+ @override
61+ bool get isDesktop => isWindows || isMacOS || isLinux;
62+ }
63+
2664class FakeDeviceManager implements IDeviceManager {
2765 // ignore: unused_field
2866 final EventBus _bus = EventBus ();
@@ -168,66 +206,59 @@ void main() {
168206 late DeviceDiscoveryViewModel vm;
169207 late FakeBleProvisioner bleProv;
170208
171- setUp (() {
172- bleProv = FakeBleProvisioner ();
173- vm = DeviceDiscoveryViewModel (
209+ // helper to construct a VM configured for mobile/desktop and an optional
210+ // permission stub.
211+ DeviceDiscoveryViewModel makeVm ({
212+ required bool mobile,
213+ Future <bool > Function ()? permissions,
214+ FakeBleProvisioner ? ble,
215+ }) {
216+ bleProv = ble ?? FakeBleProvisioner ();
217+ return DeviceDiscoveryViewModel (
174218 Logger (),
175219 FakeDeviceManager (),
176220 bleProv,
177221 FakeDeviceModuleRegistry (),
222+ FakePlatformService (isAndroid: mobile, isIOS: false , isWindows: ! mobile),
178223 globalEventBus: EventBus (),
179224 gt: FakeGettext (),
180225 logger: Logger (),
181- requestBlePermissions: () async => false ,
226+ requestBlePermissions: permissions ?? () async => false ,
182227 );
183- });
228+ }
184229
185230 test ('startDiscovery does not call BLE scan when permissions denied' , () async {
231+ vm = makeVm (mobile: true , permissions: () async => false );
186232 expect (bleProv.scanCalled, isFalse);
187233 await vm.startDiscovery ();
188234 expect (bleProv.scanCalled, isFalse);
189235 expect (vm.scanError.value, 'Bluetooth permissions are required to discover devices.' );
190236 });
191237
192238 test ('startDiscovery calls BLE scan when permissions granted' , () async {
193- // create new vm with permission true
194- vm = DeviceDiscoveryViewModel (
195- Logger (),
196- FakeDeviceManager (),
197- bleProv,
198- FakeDeviceModuleRegistry (),
199- globalEventBus: EventBus (),
200- gt: FakeGettext (),
201- logger: Logger (),
202- requestBlePermissions: () async => true ,
203- );
204-
239+ vm = makeVm (mobile: true , permissions: () async => true );
205240 await vm.startDiscovery ();
206- // allow _startBleScan unawaited future to run
241+ // scanning happens asynchronously; give it a chance
207242 await Future .delayed (Duration .zero);
208243 expect (bleProv.scanCalled, isTrue);
209244 });
210245
211246 test ('startDiscovery handles platform exception permission denial' , () async {
212247 final errorProv = FakeBleProvisioner ();
213- // override to throw
214248 errorProv.scanImpl = (String prefix, {CancellationToken ? cancelToken}) async {
215249 throw PlatformException (code: 'PERMISSION_DENIED' , message: 'nope' );
216250 };
217- vm = DeviceDiscoveryViewModel (
218- Logger (),
219- FakeDeviceManager (),
220- errorProv,
221- FakeDeviceModuleRegistry (),
222- globalEventBus: EventBus (),
223- gt: FakeGettext (),
224- logger: Logger (),
225- requestBlePermissions: () async => true ,
226- );
227-
251+ vm = makeVm (mobile: true , permissions: () async => true , ble: errorProv);
228252 await vm.startDiscovery ();
229253 await Future .delayed (Duration .zero);
230254 expect (vm.scanError.value, 'Bluetooth permissions are required to discover devices.' );
231255 });
256+
257+ test ('non‑mobile platforms skip BLE scan entirely' , () async {
258+ vm = makeVm (mobile: false , permissions: () async => true );
259+ await vm.startDiscovery ();
260+ expect (bleProv.scanCalled, isFalse);
261+ expect (vm.scanError.value, isNull);
262+ });
232263 });
233264}
0 commit comments