From 4a09caf56323c9a1c9032ef92411b46eeafd077b Mon Sep 17 00:00:00 2001 From: bardram Date: Wed, 23 Jul 2025 17:02:45 +0200 Subject: [PATCH 1/2] Fix of #506 --- carp_core/CHANGELOG.md | 5 ++ carp_core/lib/carp_core.json.dart | 1 + carp_core/pubspec.yaml | 2 +- carp_core/test/carp_core_dart_test.dart | 84 +++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) diff --git a/carp_core/CHANGELOG.md b/carp_core/CHANGELOG.md index 06bf97c4..bf31b30b 100644 --- a/carp_core/CHANGELOG.md +++ b/carp_core/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.9.4 + +* fix of issue [#506](https://github.com/cph-cachet/carp.sensing-flutter/issues/506) +* added unit tests for input data types + ## 1.9.3 * fix of issue [#491](https://github.com/cph-cachet/carp.sensing-flutter/issues/491) diff --git a/carp_core/lib/carp_core.json.dart b/carp_core/lib/carp_core.json.dart index 6bc7b1fc..82a6aa6d 100644 --- a/carp_core/lib/carp_core.json.dart +++ b/carp_core/lib/carp_core.json.dart @@ -154,6 +154,7 @@ void _registerFromJsonFunctions() { SexInput(value: Sex.Female), FullNameInput(), AddressInput(), + PhoneNumberInput(countryCode: '', number: ''), SocialSecurityNumberInput(socialSecurityNumber: '', country: ''), InformedConsentInput(name: '', userId: '', consent: '', signatureImage: ''), DiagnosisInput(icd11Code: ''), diff --git a/carp_core/pubspec.yaml b/carp_core/pubspec.yaml index 841d0f7a..049cf042 100644 --- a/carp_core/pubspec.yaml +++ b/carp_core/pubspec.yaml @@ -1,6 +1,6 @@ name: carp_core description: The core domain model for the Copenhagen Research Platform (CARP) in Dart. -version: 1.9.3 +version: 1.9.4 homepage: https://github.com/cph-cachet/carp.sensing-flutter environment: diff --git a/carp_core/test/carp_core_dart_test.dart b/carp_core/test/carp_core_dart_test.dart index 5e091039..87832263 100644 --- a/carp_core/test/carp_core_dart_test.dart +++ b/carp_core/test/carp_core_dart_test.dart @@ -300,4 +300,88 @@ void main() { expect(task.getUrl('12345-1234', 'ecec573e-442b-4563-8e2c-62b7693011df', 1), 'https://cans.cachet.dk/portal/playground/studies/ecec573e-442b-4563-8e2c-62b7693011df/settings?participant=12345-1234&trigger_id=1'); }); + + group('InputData - deep assert', () { + test('- CustomInput', () async { + final dataJson = toJsonString(CustomInput(value: {'key': 'value'})); + + final dataFromJson = + CustomInput.fromJson(json.decode(dataJson) as Map); + print(toJsonString(dataFromJson)); + expect(toJsonString(dataFromJson), equals(dataJson)); + }); + + test('- SexInput', () async { + final dataJson = toJsonString(SexInput(value: Sex.Male)); + + final dataFromJson = + SexInput.fromJson(json.decode(dataJson) as Map); + print(toJsonString(dataFromJson)); + expect(toJsonString(dataFromJson), equals(dataJson)); + }); + + test('- PhoneNumberInput', () async { + final dataJson = toJsonString( + PhoneNumberInput(countryCode: '+45', number: '12345678')); + + final dataFromJson = PhoneNumberInput.fromJson( + json.decode(dataJson) as Map); + print(toJsonString(dataFromJson)); + expect(toJsonString(dataFromJson), equals(dataJson)); + }); + + test('- SocialSecurityNumberInput', () async { + final dataJson = toJsonString(SocialSecurityNumberInput( + country: '45', socialSecurityNumber: '123456-7890')); + + final dataFromJson = SocialSecurityNumberInput.fromJson( + json.decode(dataJson) as Map); + print(toJsonString(dataFromJson)); + expect(toJsonString(dataFromJson), equals(dataJson)); + }); + + test('- FullNameInput', () async { + final dataJson = toJsonString( + FullNameInput(firstName: 'John', middleName: 'A.', lastName: 'Doe')); + + final dataFromJson = + FullNameInput.fromJson(json.decode(dataJson) as Map); + print(toJsonString(dataFromJson)); + expect(toJsonString(dataFromJson), equals(dataJson)); + }); + + test('- AddressInput', () async { + final dataJson = + toJsonString(AddressInput(street: 'Main St', city: 'Anytown')); + + final dataFromJson = + AddressInput.fromJson(json.decode(dataJson) as Map); + print(toJsonString(dataFromJson)); + expect(toJsonString(dataFromJson), equals(dataJson)); + }); + + test('- DiagnosisInput', () async { + final dataJson = + toJsonString(DiagnosisInput(diagnosis: 'Flu', icd11Code: '123456')); + + final dataFromJson = DiagnosisInput.fromJson( + json.decode(dataJson) as Map); + print(toJsonString(dataFromJson)); + expect(toJsonString(dataFromJson), equals(dataJson)); + }); + + test('- InformedConsentInput', () async { + final dataJson = toJsonString(InformedConsentInput( + userId: '12345', + name: 'John Doe', + consent: 'true', + signatureImage: 'blob', + )); + + final dataFromJson = InformedConsentInput.fromJson( + json.decode(dataJson) as Map); + print(toJsonString(dataFromJson)); + expect(toJsonString(dataFromJson), equals(dataJson)); + }); + }); } From 9b2f56187cc4c316dd0b633e787a81156054a970 Mon Sep 17 00:00:00 2001 From: Yarno Van de Weyer Date: Fri, 1 Aug 2025 10:49:33 +0200 Subject: [PATCH 2/2] updated the stream probe --- .../lib/connectivity_probes.dart | 72 +++++++++---------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/packages/carp_connectivity_package/lib/connectivity_probes.dart b/packages/carp_connectivity_package/lib/connectivity_probes.dart index a4c28630..871a9976 100644 --- a/packages/carp_connectivity_package/lib/connectivity_probes.dart +++ b/packages/carp_connectivity_package/lib/connectivity_probes.dart @@ -13,18 +13,16 @@ class ConnectivityProbe extends StreamProbe { @override Future onStart() async { // collect the current connectivity status on sampling start - var connectivityStatus = - await connectivity.Connectivity().checkConnectivity(); - addMeasurement(Measurement.fromData( - Connectivity.fromConnectivityResult(connectivityStatus))); + var connectivityStatus = await connectivity.Connectivity().checkConnectivity(); + addMeasurement(Measurement.fromData(Connectivity.fromConnectivityResult(connectivityStatus))); return super.onStart(); } @override - Stream get stream => - connectivity.Connectivity().onConnectivityChanged.map((event) => - Measurement.fromData(Connectivity.fromConnectivityResult(event))); + Stream get stream => connectivity.Connectivity() + .onConnectivityChanged + .map((event) => Measurement.fromData(Connectivity.fromConnectivityResult(event))); } // This probe requests access to location permissions (both on Android and iOS). @@ -69,24 +67,17 @@ class BluetoothProbe extends BufferingPeriodicStreamProbe { Stream get bufferingStream => FlutterBluePlus.scanResults; @override - Future getMeasurement() async => - _data != null ? Measurement.fromData(_data!) : null; + Future getMeasurement() async => _data != null ? Measurement.fromData(_data!) : null; // if a BT-specific sampling configuration is used, we need to // extract the services and remoteIds from it so FlutterBluePlus can // perform filtered scanning - List get services => (samplingConfiguration - is BluetoothScanPeriodicSamplingConfiguration) - ? (samplingConfiguration as BluetoothScanPeriodicSamplingConfiguration) - .withServices - .map((e) => Guid(e)) - .toList() + List get services => (samplingConfiguration is BluetoothScanPeriodicSamplingConfiguration) + ? (samplingConfiguration as BluetoothScanPeriodicSamplingConfiguration).withServices.map((e) => Guid(e)).toList() : []; - List get remoteIds => (samplingConfiguration - is BluetoothScanPeriodicSamplingConfiguration) - ? (samplingConfiguration as BluetoothScanPeriodicSamplingConfiguration) - .withRemoteIds + List get remoteIds => (samplingConfiguration is BluetoothScanPeriodicSamplingConfiguration) + ? (samplingConfiguration as BluetoothScanPeriodicSamplingConfiguration).withRemoteIds : []; @override @@ -97,8 +88,7 @@ class BluetoothProbe extends BufferingPeriodicStreamProbe { FlutterBluePlus.startScan( withServices: services, withRemoteIds: remoteIds, - timeout: samplingConfiguration?.duration ?? - const Duration(milliseconds: DEFAULT_TIMEOUT), + timeout: samplingConfiguration?.duration ?? const Duration(milliseconds: DEFAULT_TIMEOUT), ); } catch (error) { FlutterBluePlus.stopScan(); @@ -132,10 +122,7 @@ class BeaconProbe extends StreamProbe { super.samplingConfiguration as BeaconRangingPeriodicSamplingConfiguration; List get beaconRegions => - samplingConfiguration?.beaconRegions - .map((region) => region.toRegion()) - .toList() ?? - []; + samplingConfiguration?.beaconRegions.map((region) => region.toRegion()).toList() ?? []; int get beaconDistance => samplingConfiguration?.beaconDistance ?? 2; @@ -143,8 +130,7 @@ class BeaconProbe extends StreamProbe { bool onInitialize() { super.onInitialize(); if (beaconRegions.isEmpty) { - warning( - '$runtimeType - No beacon regions specified for monitoring. Will not start monitoring.'); + warning('$runtimeType - No beacon regions specified for monitoring. Will not start monitoring.'); return false; } @@ -165,15 +151,17 @@ class BeaconProbe extends StreamProbe { } @override - Stream get stream => flutterBeacon.ranging(beaconRegions).map( - (RangingResult result) { - final closeBeacons = result.beacons - .where((beacon) => beacon.accuracy <= beaconDistance); - - // If no beacons are close, still return an measurement with an empty - // list of iBeacons for this region. - return Measurement.fromData( - BeaconData(region: result.region.identifier) + Stream get stream async* { + await for (final monitoringResult in flutterBeacon.monitoring(beaconRegions)) { + if (monitoringResult.monitoringState == MonitoringState.inside) { + info('$runtimeType - Entered region: ${monitoringResult.region.identifier}'); + + yield* flutterBeacon.ranging(beaconRegions).map( + (rangingResult) { + final closeBeacons = rangingResult.beacons.where((beacon) => beacon.accuracy <= beaconDistance); + + return Measurement.fromData( + BeaconData(region: rangingResult.region.identifier) ..scanResult = closeBeacons .map((beacon) => BeaconDevice( uuid: beacon.proximityUUID, @@ -183,7 +171,13 @@ class BeaconProbe extends StreamProbe { accuracy: beacon.accuracy, proximity: beacon.proximity, )) - .toList()); - }, - ); + .toList(), + ); + }, + ); + } else if (monitoringResult.monitoringState == MonitoringState.outside) { + info('$runtimeType - Exited region: ${monitoringResult.region.identifier}'); + } + } + } }