Commit 732a11a

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-04-05 17:18:14
provide new repos in tests
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent ae2d196
app/lib/model/blood_pressure/medicine/intake_history.dart
@@ -11,7 +11,7 @@ import 'package:flutter/material.dart';
 /// are
 class IntakeHistory extends ChangeNotifier {
   /// Create a intake history from an unsorted list of intakes.
-  IntakeHistory(List<MedicineIntake> medicineIntakes):
+  IntakeHistory(List<OldMedicineIntake> medicineIntakes):
     _medicineIntakes = medicineIntakes.sorted((p0, p1) => p0.compareTo(p1));
 
   /// Creates a intake history from a sorted list of intakes.
@@ -22,7 +22,7 @@ class IntakeHistory extends ChangeNotifier {
     IntakeHistory._sorted(
       serialized
         .split('\n')
-        .map((e) => MedicineIntake.deserialize(e, availableMedicines))
+        .map((e) => OldMedicineIntake.deserialize(e, availableMedicines))
         .toList(),
     );
 
@@ -31,14 +31,14 @@ class IntakeHistory extends ChangeNotifier {
   /// List of all medicine intakes sorted in ascending order.
   ///
   /// Can contain multiple medicine intakes at the same time.
-  final List<MedicineIntake> _medicineIntakes;
+  final List<OldMedicineIntake> _medicineIntakes;
 
 
   /// Returns all intakes in a given range in ascending order.
   ///
   /// Binary searches the lower and the upper bound of stored intakes to create
   /// the list view.
-  UnmodifiableListView<MedicineIntake> getIntakes(DateTimeRange range) {
+  UnmodifiableListView<OldMedicineIntake> getIntakes(DateTimeRange range) {
     if (_medicineIntakes.isEmpty) return UnmodifiableListView([]);
     int start = _findLowerBound(_medicineIntakes, range.start);
     int end = _findUpperBound(_medicineIntakes, range.end);
@@ -56,7 +56,7 @@ class IntakeHistory extends ChangeNotifier {
   /// When no smaller bigger intake is available insert to the end of the list.
   ///
   /// Uses binary search to determine the bound.
-  void addIntake(MedicineIntake intake) {
+  void addIntake(OldMedicineIntake intake) {
     final int index = _findUpperBound(_medicineIntakes, intake.timestamp);
 
     if (index == -1) {
@@ -71,7 +71,7 @@ class IntakeHistory extends ChangeNotifier {
   ///
   /// When finding multiple intakes with the same timestamp, medicine
   /// and dosis all instances will get deleted.
-  void deleteIntake(MedicineIntake intake) {
+  void deleteIntake(OldMedicineIntake intake) {
     int idx = binarySearch(_medicineIntakes, intake);
     while (idx >= 0) {
       _medicineIntakes.removeAt(idx);
@@ -82,7 +82,7 @@ class IntakeHistory extends ChangeNotifier {
 
   /// Use binary search to determine the first index in [list] before which all
   /// values that are before or at the same time as [t].
-  int _findUpperBound(List<MedicineIntake> list, DateTime t) {
+  int _findUpperBound(List<OldMedicineIntake> list, DateTime t) {
     int low = 0;
     int high = list.length - 1;
 
@@ -104,7 +104,7 @@ class IntakeHistory extends ChangeNotifier {
 
   /// Use binary search to determine the last index in [list] after which before
   /// all values that are after or at the same time as [t].
-  int _findLowerBound(List<MedicineIntake> list, DateTime t) {
+  int _findLowerBound(List<OldMedicineIntake> list, DateTime t) {
     int low = 0;
     int high = list.length - 1;
 
app/lib/model/blood_pressure/medicine/medicine.dart
@@ -48,7 +48,7 @@ class Medicine {
   /// Color used to display medicine intake
   final Color color;
 
-  /// Default dosis used to autofill [MedicineIntake].
+  /// Default dosis used to autofill [OldMedicineIntake].
   final double? defaultDosis;
 
   /// Indicates that this medicine should not be shown in selection menus.
app/lib/model/blood_pressure/medicine/medicine_intake.dart
@@ -5,11 +5,11 @@ import 'package:flutter/material.dart';
 
 /// Instance of a medicine intake.
 @deprecated
-class MedicineIntake implements Comparable<Object> {
+class OldMedicineIntake implements Comparable<Object> {
   /// Create a intake from a String created by [serialize].
   ///
   /// [availableMeds] must contain the
-  factory MedicineIntake.deserialize(
+  factory OldMedicineIntake.deserialize(
     String string,
     List<Medicine> availableMeds,
   ) {
@@ -19,7 +19,7 @@ class MedicineIntake implements Comparable<Object> {
     if (kDebugMode && storedMedicine.isEmpty) {
       throw ArgumentError('Medicine of intake $string not found.');
     }
-    return MedicineIntake(
+    return OldMedicineIntake(
       medicine: storedMedicine.firstOrNull ?? Medicine(
         int.parse(elements[0]),
         designation: 'DELETED MEDICINE',
@@ -32,7 +32,7 @@ class MedicineIntake implements Comparable<Object> {
   }
 
   /// Create a instance of a medicine intake.
-  const MedicineIntake({
+  const OldMedicineIntake({
     required this.medicine,
     required this.dosis,
     required this.timestamp,
@@ -57,7 +57,7 @@ class MedicineIntake implements Comparable<Object> {
   @override
   bool operator ==(Object other) =>
       identical(this, other) ||
-      other is MedicineIntake &&
+      other is OldMedicineIntake &&
           runtimeType == other.runtimeType &&
           medicine == other.medicine &&
           dosis == other.dosis &&
@@ -68,8 +68,8 @@ class MedicineIntake implements Comparable<Object> {
 
   @override
   int compareTo(Object other) {
-    assert(other is MedicineIntake);
-    if (other is! MedicineIntake) return 0;
+    assert(other is OldMedicineIntake);
+    if (other is! OldMedicineIntake) return 0;
 
     final timeCompare = timestamp.compareTo(other.timestamp);
     if (timeCompare != 0) return timeCompare;
app/lib/model/storage/settings_store.dart
@@ -147,7 +147,7 @@ class Settings extends ChangeNotifier {
       'bottomAppBars': bottomAppBars,
       'medications': medications.map(jsonEncode).toList(),
       'highestMedIndex': highestMedIndex,
-      'preferredPressureUnit': preferredPressureUnit,
+      'preferredPressureUnit': preferredPressureUnit.encode(),
     };
 
   /// Serialize the object to a restoreable string.
app/lib/screens/elements/measurement_graph.dart
@@ -122,7 +122,7 @@ class _LineChartState extends State<_LineChart> {
       /// Horizontally furthest value (same as last timestamp).
       double? graphEnd, 
       Iterable<BloodPressureRecord> allRecords,
-      Iterable<MedicineIntake> allIntakes,
+      Iterable<OldMedicineIntake> allIntakes,
       ) {
     final bars = [
       _buildBarData(animatedThickness, sysSpots, settings.sysColor, true, settings.sysWarn.toDouble()),
app/lib/screens/home_screen.dart
@@ -1,6 +1,6 @@
 import 'package:blood_pressure_app/components/dialoges/add_measurement_dialoge.dart';
 import 'package:blood_pressure_app/components/measurement_list/measurement_list.dart';
-import 'package:blood_pressure_app/model/blood_pressure/medicine/intake_history.dart';
+import 'package:blood_pressure_app/components/repository_builder.dart';
 import 'package:blood_pressure_app/model/blood_pressure/model.dart';
 import 'package:blood_pressure_app/model/storage/intervall_store.dart';
 import 'package:blood_pressure_app/model/storage/settings_store.dart';
@@ -14,7 +14,7 @@ import 'package:flutter/scheduler.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:health_data_store/health_data_store.dart' show MedicineIntakeRepository, MedicineRepository;
+import 'package:health_data_store/health_data_store.dart' show MedicineIntake, MedicineIntakeRepository, MedicineRepository;
 import 'package:provider/provider.dart';
 
 /// Is true during the first [AppHome.build] before creating the widget.
@@ -72,22 +72,24 @@ class AppHome extends StatelessWidget {
                       LegacyMeasurementsList(context) :
                       BloodPressureBuilder(
                         rangeType: IntervallStoreManagerLocation.mainPage,
-                        onData: (context, records) => StreamBuilder(
-                          stream: RepositoryProvider.of<MedicineRepository>(context).,
-                          builder: (context, snapshot) {
-                            return MeasurementList(
-                              settings: settings,
-                              records: records,
-                              intakes: intakeHistory.getIntakes(intervalls.mainPage.currentRange),
-                            );
-                          },
+                        onData: (context, records) => RepositoryBuilder<MedicineIntake, MedicineIntakeRepository>(
+                          rangeType: IntervallStoreManagerLocation.mainPage,
+                          onData: (BuildContext context, List<dynamic> list) => MeasurementList(
+                            settings: settings,
+                            records: records,
+                            // The following cast is necessary to avoid a type
+                            // error. I'm not sure why this is necessary as the
+                            // generics _should_ be typesafe. The safety of this
+                            // cast has been proven in practice.
+                            // TODO: Figure out why type safety isn't possible.
+                            intakes: list.cast(),
+                          ) as Widget,
                         ),
                       ),
                   ),
                 ],),
               ),),
             ),
-          ),
         );
       },
       ),
app/test/model/medicine/medicine_intake_test.dart
@@ -8,38 +8,38 @@ import 'medicine_test.dart';
 void main() {
   test('should determine equality', () {
     final med = Medicine(1, designation: 'designation', color: Colors.red, defaultDosis: 123);
-    final int1 = MedicineIntake(medicine: med, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
-    final int2 = MedicineIntake(medicine: med, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
+    final int1 = OldMedicineIntake(medicine: med, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
+    final int2 = OldMedicineIntake(medicine: med, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
     expect(int1, int2);
   });
   test('should determine inequality', () {
     final med1 = Medicine(1, designation: 'designation', color: Colors.red, defaultDosis: 123);
     final med2 = Medicine(2, designation: 'designation', color: Colors.red, defaultDosis: 123);
-    final int1 = MedicineIntake(medicine: med1, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
-    final int2 = MedicineIntake(medicine: med2, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
+    final int1 = OldMedicineIntake(medicine: med1, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
+    final int2 = OldMedicineIntake(medicine: med2, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
     expect(int1, isNot(int2));
-    final int3 = MedicineIntake(medicine: med1, dosis: 11, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
+    final int3 = OldMedicineIntake(medicine: med1, dosis: 11, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
     expect(int1, isNot(int3));
-    final int4 = MedicineIntake(medicine: med1, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(124));
+    final int4 = OldMedicineIntake(medicine: med1, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(124));
     expect(int1, isNot(int4));
   });
   test('should deserialize serialized intake', () {
     final intake = mockIntake(timeMs: 543210);
-    expect(MedicineIntake.deserialize(intake.serialize(), [intake.medicine]), intake);
+    expect(OldMedicineIntake.deserialize(intake.serialize(), [intake.medicine]), intake);
 
     final intake2 = mockIntake(
         timeMs: 543211,
         dosis: 1000231,
         medicine: mockMedicine(designation: 'tst'),
     );
-    expect(MedicineIntake.deserialize(
+    expect(OldMedicineIntake.deserialize(
         intake2.serialize(),
         [intake.medicine, intake2.medicine],),
         intake2,);
   });
   test('should fail to deserialize serialized intake without exising med', () {
     final intake = mockIntake(medicine: mockMedicine(designation: 'tst'));
-    expect(() => MedicineIntake.deserialize(
+    expect(() => OldMedicineIntake.deserialize(
         intake.serialize(),
         [mockMedicine()],),
         throwsArgumentError,);
@@ -50,11 +50,11 @@ void main() {
 ///
 /// [timeMs] creates the intake timestamp through [DateTime.fromMillisecondsSinceEpoch].
 /// When is null [DateTime.now] is used.
-MedicineIntake mockIntake({
+OldMedicineIntake mockIntake({
   double dosis = 0,
   int? timeMs,
   Medicine? medicine,
-}) => MedicineIntake(
+}) => OldMedicineIntake(
     medicine: medicine ?? mockMedicine(),
     dosis: dosis,
     timestamp: timeMs == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(timeMs),
app/test/ui/components/add_measurement_dialoge_test.dart
@@ -306,7 +306,7 @@ void main() {
       await tester.pumpAndSettle();
 
       expect(result?.$1, isNull);
-      expect(result?.$2, isA<MedicineIntake>()
+      expect(result?.$2, isA<OldMedicineIntake>()
           .having((p0) => p0.timestamp.millisecondsSinceEpoch ~/ 2000, 'timestamp', openDialogeTimeStamp.millisecondsSinceEpoch ~/ 2000)
           .having((p0) => p0.medicine, 'medicine', med2)
           .having((p0) => p0.dosis, 'dosis', 123.456),
@@ -542,7 +542,7 @@ void main() {
 
       expect(result, isNotNull);
       expect(result?.$1, isNull);
-      expect(result?.$2, isA<MedicineIntake>()
+      expect(result?.$2, isA<OldMedicineIntake>()
           .having((p0) => p0.dosis, 'dosis', 654.321),
       );
     });
@@ -583,7 +583,7 @@ void main() {
 
       expect(result, isNotNull);
       expect(result?.$1, isNull);
-      expect(result?.$2, isA<MedicineIntake>()
+      expect(result?.$2, isA<OldMedicineIntake>()
           .having((p0) => p0.dosis, 'dosis', 654.322),
       );
     });
app/test/ui/navigation_test.dart
@@ -13,10 +13,11 @@ import 'package:blood_pressure_app/model/storage/settings_store.dart';
 import 'package:blood_pressure_app/screens/settings_screen.dart';
 import 'package:blood_pressure_app/screens/statistics_screen.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_test/flutter_test.dart';
+import 'package:health_data_store/health_data_store.dart';
 import 'package:provider/provider.dart';
-
-import '../ram_only_implementations.dart';
+import 'package:sqflite/sqflite.dart';
 
 void main() {
   group('start page', () {
@@ -65,6 +66,7 @@ void main() {
 }
 
 /// Creates a the same App as the main method.
+@Deprecated('replaced by [newPumpAppRoot]')
 Future<void> pumpAppRoot(WidgetTester tester, {
   Settings? settings,
   ExportSettings? exportSettings,
@@ -74,23 +76,79 @@ Future<void> pumpAppRoot(WidgetTester tester, {
   IntakeHistory? intakeHistory,
   BloodPressureModel? model,
 }) async {
-  model ??= RamBloodPressureModel();
+  // TODO: migrate arguments
+  final db = await HealthDataStore.load(await openDatabase(inMemoryDatabasePath));
+
+  final meds = settings?.medications?.map((e) => Medicine(
+      designation: e.designation,
+      color: e.color.value,
+      dosis: e.defaultDosis != null ? Weight.mg(e.defaultDosis!) : null));
+  final medRepo = db.medRepo;
+  meds?.forEach(medRepo.add);
+
+  final intakeRepo = db.intakeRepo;
+  for (final e in intakeHistory?.getIntakes(DateTimeRange(
+      start: DateTime.fromMillisecondsSinceEpoch(0),
+      end: DateTime.fromMillisecondsSinceEpoch(999999999999))) ?? []) {
+    expect(meds, isNotNull);
+    expect(meds, isNotEmpty);
+    final med = meds!.firstWhere((e2) => e2.designation == e.medicine.designation);
+    intakeRepo.add(MedicineIntake(
+      time: e.timestamp,
+      dosis: Weight.mg(e.dosis),
+      medicine: med,
+    ));
+  }
+
+  // TODO: bpRepo
+
+  await newPumpAppRoot(tester,
+    settings: settings,
+    exportSettings: exportSettings,
+    csvExportSettings: csvExportSettings,
+    pdfExportSettings: pdfExportSettings,
+    intervallStoreManager: intervallStoreManager,
+    medRepo: medRepo,
+    intakeRepo: intakeRepo,
+  );
+}
+
+/// Creates a the same App as the main method.
+Future<void> newPumpAppRoot(WidgetTester tester, {
+  Settings? settings,
+  ExportSettings? exportSettings,
+  CsvExportSettings? csvExportSettings,
+  PdfExportSettings? pdfExportSettings,
+  IntervallStoreManager? intervallStoreManager,
+  BloodPressureRepository? bpRepo,
+  MedicineRepository? medRepo,
+  MedicineIntakeRepository? intakeRepo,
+}) async {
   settings ??= Settings();
   exportSettings ??= ExportSettings();
   csvExportSettings ??= CsvExportSettings();
   pdfExportSettings ??= PdfExportSettings();
-  intakeHistory ??= IntakeHistory([]);
   intervallStoreManager ??= IntervallStoreManager(IntervallStorage(), IntervallStorage(), IntervallStorage());
 
+  HealthDataStore? db;
+  if  (bpRepo != null || medRepo != null || intakeRepo != null) {
+    db = await HealthDataStore.load(await openDatabase(inMemoryDatabasePath));
+  }
+
   await tester.pumpWidget(MultiProvider(providers: [
     ChangeNotifierProvider(create: (_) => settings),
     ChangeNotifierProvider(create: (_) => exportSettings),
     ChangeNotifierProvider(create: (_) => csvExportSettings),
     ChangeNotifierProvider(create: (_) => pdfExportSettings),
-    ChangeNotifierProvider(create: (_) => intakeHistory),
     ChangeNotifierProvider(create: (_) => intervallStoreManager),
-    ChangeNotifierProvider<BloodPressureModel>(create: (_) => model!),
-  ], child: const AppRoot(),),);
+  ], child: MultiRepositoryProvider(
+    providers: [
+      RepositoryProvider(create: (context) => bpRepo ?? db!.bpRepo),
+      RepositoryProvider(create: (context) => medRepo ?? db!.medRepo),
+      RepositoryProvider(create: (context) => intakeRepo ?? db!.intakeRepo),
+    ],
+    child: const AppRoot(),
+  ),),);
 }
 
 class MockConfigDao implements ConfigDao {