main
1import 'package:blood_pressure_app/model/export_import/column.dart';
2import 'package:blood_pressure_app/model/export_import/import_field_type.dart';
3import 'package:blood_pressure_app/model/export_import/record_formatter.dart';
4import 'package:flutter/material.dart';
5import 'package:flutter_test/flutter_test.dart';
6import 'package:health_data_store/health_data_store.dart';
7
8import '../../features/measurement_list/measurement_list_entry_test.dart';
9import '../../util.dart';
10import 'record_formatter_test.dart';
11
12void main() {
13 group('NativeColumn', () {
14 test('should contain fields in allColumns', () {
15 expect(NativeColumn.allColumns, containsAll([
16 NativeColumn.timestampUnixMs,
17 NativeColumn.systolic,
18 NativeColumn.diastolic,
19 NativeColumn.pulse,
20 NativeColumn.notes,
21 NativeColumn.color,
22 NativeColumn.needlePin,
23 ]),);
24 });
25 test('should have internalIdentifier prefixed with "native."', () {
26 for (final c in NativeColumn.allColumns) {
27 expect(c.internalIdentifier, startsWith('native.'));
28 }
29 });
30 test('should encode into non-empty string', () {
31 // Use BuildInColumn for utility columns
32 for (final c in NativeColumn.allColumns) {
33 final r = _filledRecord(true);
34 expect(c.encode(r.$1, r.$2, r.$3, Weight.kg(123)), isNotEmpty, reason: '${c.internalIdentifier} is NativeColumn');
35 }
36 });
37 test('should only contain restoreable types', () {
38 // Use BuildInColumn for utility columns
39 for (final c in NativeColumn.allColumns) {
40 expect(c.restoreAbleType, isNotNull);
41 }
42 });
43 test('should decode correctly', () {
44 final r = _filledRecord(true);
45 for (final c in NativeColumn.allColumns) {
46 final txt = c.encode(r.$1, r.$2, r.$3, Weight.kg(123));
47 final decoded = c.decode(txt);
48 expect(decoded, isNotNull, reason: 'a real value was encoded: ${c.internalIdentifier}: ${r.debugToString()} > $txt');
49 switch (decoded!.$1) {
50 case RowDataFieldType.timestamp:
51 expect(decoded.$2, isA<DateTime>().having(
52 (p0) => p0.millisecondsSinceEpoch, 'milliseconds', r.$1.time.millisecondsSinceEpoch,),);
53 break;
54 case RowDataFieldType.sys:
55 expect(decoded.$2, isA<int>()
56 .having((p0) => p0, 'systolic', r.$1.sys?.mmHg));
57 case RowDataFieldType.dia:
58 expect(decoded.$2, isA<int>()
59 .having((p0) => p0, 'diastolic', r.$1.dia?.mmHg));
60 case RowDataFieldType.pul:
61 expect(decoded.$2, isA<int>()
62 .having((p0) => p0, 'pulse', r.$1.pul));
63 case RowDataFieldType.notes:
64 expect(decoded.$2, isA<String>()
65 .having((p0) => p0, 'note', r.$2.note));
66 case RowDataFieldType.color:
67 expect(decoded.$2, isA<int>()
68 .having((p0) => p0, 'pin', r.$2.color));
69 case RowDataFieldType.intakes:
70 expect(decoded.$2, isA<List>()
71 .having((p0) => p0.length, 'length', 1,)
72 .having((p0) => p0[0].$1, 'designation', 'mockMed',)
73 .having((p0) => p0[0].$2, 'dosis', 123.4,));
74 case RowDataFieldType.weightKg:
75 expect(decoded.$2, isA<double>()
76 .having((p0) => p0, 'weight', 123.0));
77 }
78 }
79 });
80 });
81
82 group('BuildInColumn', () {
83 test('should contain fields in allColumns', () {
84 expect(BuildInColumn.allColumns, containsAll([
85 BuildInColumn.pulsePressure,
86 BuildInColumn.mhDate,
87 BuildInColumn.mhSys,
88 BuildInColumn.mhDia,
89 BuildInColumn.mhPul,
90 BuildInColumn.mhDesc,
91 BuildInColumn.mhTags,
92 BuildInColumn.mhWeight,
93 BuildInColumn.mhOxygen,
94 ]),);
95 });
96 test('should have internalIdentifier prefixed with "buildin."', () {
97 for (final c in BuildInColumn.allColumns) {
98 expect(c.internalIdentifier, startsWith('buildin.'));
99 }
100 });
101 test('should encode without problems', () {
102 for (final c in BuildInColumn.allColumns) {
103 final r = _filledRecord();
104 expect(c.encode(r.$1, r.$2, r.$3, null), isNotNull);
105 }
106 });
107 test('should decode correctly', () {
108 final r = _filledRecord(true);
109 for (final c in BuildInColumn.allColumns) {
110 final txt = c.encode(r.$1, r.$2, r.$3, Weight.kg(123.45));
111 final decoded = c.decode(txt);
112 switch (decoded?.$1) {
113 case RowDataFieldType.timestamp:
114 if (c is TimeColumn) {
115 // This ensures no columns with useless conversions get introduced.
116 expect(decoded?.$2, isA<DateTime>().having(
117 (p0) => p0.difference(r.$1.time).inDays,
118 'inaccuracy',
119 lessThan(1),),);
120 } else {
121 expect(decoded?.$2, isA<DateTime>().having(
122 (p0) => p0.millisecondsSinceEpoch, 'milliseconds', r.$1.time.millisecondsSinceEpoch,),);
123 }
124 case RowDataFieldType.sys:
125 expect(decoded?.$2, isA<int>()
126 .having((p0) => p0, 'systolic', r.$1.sys?.mmHg));
127 case RowDataFieldType.dia:
128 expect(decoded?.$2, isA<int>()
129 .having((p0) => p0, 'diastolic', r.$1.dia?.mmHg));
130 case RowDataFieldType.pul:
131 expect(decoded?.$2, isA<int>()
132 .having((p0) => p0, 'pulse', r.$1.pul));
133 case RowDataFieldType.notes:
134 expect(decoded?.$2, isA<String>()
135 .having((p0) => p0, 'note', r.$2.note));
136 case RowDataFieldType.color:
137 expect(decoded?.$2, isA<int>()
138 .having((p0) => p0, 'pin', r.$2.color));
139 case RowDataFieldType.intakes:
140 expect(decoded?.$2, isA<List<(String, double)>>()
141 .having((p0) => p0.length, 'length', 1,)
142 .having((p0) => p0[0].$1, 'designation', 'mockMed',)
143 .having((p0) => p0[0].$2, 'dosis', 123.4,));
144 case RowDataFieldType.weightKg:
145 expect(decoded?.$2, isA<double>()
146 .having((p0) => p0, 'weight', 123.45));
147 case null:
148 // no-op
149 }
150 }
151 });
152 });
153
154 group('UserColumn', () {
155 test('should have internalIdentifier prefixed with "userColumn."', () {
156 final column = UserColumn('test', 'csvTitle', 'pattern');
157 expect(column.internalIdentifier, startsWith('userColumn.'));
158 });
159 test('should encode like ScriptedFormatter', () {
160 final r = _filledRecord();
161 expect(
162 UserColumn('','', 'TEST').encode(r.$1, r.$2, r.$3, null),
163 ScriptedFormatter('TEST').encode(r.$1, r.$2, r.$3, null),
164 );
165 expect(
166 UserColumn('','', r'$SYS').encode(r.$1, r.$2, r.$3, null),
167 ScriptedFormatter(r'$SYS').encode(r.$1, r.$2, r.$3, null),
168 );
169 expect(
170 UserColumn('','', r'$SYS-$DIA').encode(r.$1, r.$2, r.$3, null),
171 ScriptedFormatter(r'$SYS-$DIA').encode(r.$1, r.$2, r.$3, null),
172 );
173 expect(
174 UserColumn('','', r'$TIMESTAMP').encode(r.$1, r.$2, r.$3, null),
175 ScriptedFormatter(r'$TIMESTAMP').encode(r.$1, r.$2, r.$3, null),
176 );
177 expect(
178 UserColumn('','', '').encode(r.$1, r.$2, r.$3, null),
179 ScriptedFormatter('').encode(r.$1, r.$2, r.$3, null),
180 );
181 });
182 test('should decode like ScriptedFormatter', () {
183 final r = _filledRecord();
184 final testPatterns = ['TEST', r'$SYS', r'{{$SYS-$DIA}}', r'$TIMESTAMP', ''];
185
186 for (final pattern in testPatterns) {
187 final column = UserColumn('','', pattern);
188 final formatter = ScriptedFormatter(pattern);
189 expect(
190 column.decode(column.encode(r.$1, r.$2, r.$3, null)),
191 formatter.decode(formatter.encode(r.$1, r.$2, r.$3, null)),
192 );
193 }
194 });
195 });
196
197 group('TimeColumn', () {
198 test('should have internalIdentifier prefixed with "timeFormatter."', () {
199 final column = TimeColumn('csvTitle', 'formatPattern');
200 expect(column.internalIdentifier, startsWith('timeFormatter.'));
201 });
202 });
203}
204
205FullEntry _filledRecord([bool addIntakes = false]) => mockEntry(
206 sys: 123,
207 dia: 456,
208 pul: 789,
209 note: 'test',
210 pin: Colors.pink,
211 intake: addIntakes
212 ? mockIntake(mockMedicine(designation: 'mockMed'), dosis: 123.4,)
213 : null,
214);