1
1
import 'dart:async' ;
2
+ import 'package:flutter/material.dart' ;
2
3
import 'package:flutter_test/flutter_test.dart' ;
3
4
import 'package:mockito/mockito.dart' ;
4
5
import 'package:hydrated_cubit/hydrated_cubit.dart' ;
@@ -7,11 +8,6 @@ import 'package:uuid/uuid.dart';
7
8
8
9
class MockStorage extends Mock implements Storage {}
9
10
10
- class MockCubit extends Mock implements HydratedCubit <dynamic > {
11
- @override
12
- String get storageToken => '${runtimeType .toString ()}$id ' ;
13
- }
14
-
15
11
class MyUuidHydratedCubit extends HydratedCubit <String > {
16
12
MyUuidHydratedCubit () : super (Uuid ().v4 ());
17
13
@@ -22,6 +18,23 @@ class MyUuidHydratedCubit extends HydratedCubit<String> {
22
18
String fromJson (dynamic json) => json['value' ] as String ;
23
19
}
24
20
21
+ class MyCallbackHydratedCubit extends HydratedCubit <int > {
22
+ MyCallbackHydratedCubit ({this .onFromJsonCalled}) : super (0 );
23
+
24
+ final ValueSetter <dynamic > onFromJsonCalled;
25
+
26
+ void increment () => emit (state + 1 );
27
+
28
+ @override
29
+ Map <String , int > toJson (int state) => {'value' : state};
30
+
31
+ @override
32
+ int fromJson (dynamic json) {
33
+ onFromJsonCalled? .call (json);
34
+ return json['value' ] as int ;
35
+ }
36
+ }
37
+
25
38
class MyHydratedCubit extends HydratedCubit <int > {
26
39
MyHydratedCubit ([this ._id]) : super (0 );
27
40
@@ -64,13 +77,89 @@ void main() {
64
77
HydratedCubit .storage = storage;
65
78
});
66
79
67
- group ('SingleHydratedCubit' , () {
68
- MyHydratedCubit cubit;
80
+ test ('reads from storage once upon initialization' , () {
81
+ MyCallbackHydratedCubit ();
82
+ verify <dynamic >(storage.read ('MyCallbackHydratedCubit' )).called (1 );
83
+ });
69
84
70
- setUp (() {
71
- cubit = MyHydratedCubit ();
72
- });
85
+ test (
86
+ 'does not read from storage on subsequent state changes '
87
+ 'when cache value exists' , () {
88
+ when < dynamic > (storage.read ('MyCallbackHydratedCubit' )).thenReturn (
89
+ {'value' : 42 },
90
+ );
91
+ final cubit = MyCallbackHydratedCubit ();
92
+ expect (cubit.state, 42 );
93
+ cubit.increment ();
94
+ expect (cubit.state, 43 );
95
+ verify <dynamic >(storage.read ('MyCallbackHydratedCubit' )).called (1 );
96
+ });
73
97
98
+ test (
99
+ 'does not deserialize state on subsequent state changes '
100
+ 'when cache value exists' , () {
101
+ final fromJsonCalls = < dynamic > [];
102
+ when < dynamic > (storage.read ('MyCallbackHydratedCubit' )).thenReturn (
103
+ {'value' : 42 },
104
+ );
105
+ final cubit = MyCallbackHydratedCubit (
106
+ onFromJsonCalled: fromJsonCalls.add,
107
+ );
108
+ expect (cubit.state, 42 );
109
+ cubit.increment ();
110
+ expect (cubit.state, 43 );
111
+ expect (fromJsonCalls, [
112
+ {'value' : 42 }
113
+ ]);
114
+ });
115
+
116
+ test (
117
+ 'does not read from storage on subsequent state changes '
118
+ 'when cache is empty' , () {
119
+ when < dynamic > (storage.read ('MyCallbackHydratedCubit' )).thenReturn (null );
120
+ final cubit = MyCallbackHydratedCubit ();
121
+ expect (cubit.state, 0 );
122
+ cubit.increment ();
123
+ expect (cubit.state, 1 );
124
+ verify <dynamic >(storage.read ('MyCallbackHydratedCubit' )).called (1 );
125
+ });
126
+
127
+ test ('does not deserialize state when cache is empty' , () {
128
+ final fromJsonCalls = < dynamic > [];
129
+ when < dynamic > (storage.read ('MyCallbackHydratedCubit' )).thenReturn (null );
130
+ final cubit = MyCallbackHydratedCubit (
131
+ onFromJsonCalled: fromJsonCalls.add,
132
+ );
133
+ expect (cubit.state, 0 );
134
+ cubit.increment ();
135
+ expect (cubit.state, 1 );
136
+ expect (fromJsonCalls, isEmpty);
137
+ });
138
+
139
+ test (
140
+ 'does not read from storage on subsequent state changes '
141
+ 'when cache is malformed' , () {
142
+ when < dynamic > (storage.read ('MyCallbackHydratedCubit' )).thenReturn ('{' );
143
+ final cubit = MyCallbackHydratedCubit ();
144
+ expect (cubit.state, 0 );
145
+ cubit.increment ();
146
+ expect (cubit.state, 1 );
147
+ verify <dynamic >(storage.read ('MyCallbackHydratedCubit' )).called (1 );
148
+ });
149
+
150
+ test ('does not deserialize state when cache is malformed' , () {
151
+ final fromJsonCalls = < dynamic > [];
152
+ when < dynamic > (storage.read ('MyCallbackHydratedCubit' )).thenReturn ('{' );
153
+ final cubit = MyCallbackHydratedCubit (
154
+ onFromJsonCalled: fromJsonCalls.add,
155
+ );
156
+ expect (cubit.state, 0 );
157
+ cubit.increment ();
158
+ expect (cubit.state, 1 );
159
+ expect (fromJsonCalls, isEmpty);
160
+ });
161
+
162
+ group ('SingleHydratedCubit' , () {
74
163
test ('should throw HydratedStorageNotFound when storage is null' , () {
75
164
HydratedCubit .storage = null ;
76
165
expect (
@@ -93,7 +182,7 @@ void main() {
93
182
test ('should call storage.write when onTransition is called' , () {
94
183
final transition = const Transition (currentState: 0 , nextState: 0 );
95
184
final expected = < String , int > {'value' : 0 };
96
- cubit .onTransition (transition);
185
+ MyHydratedCubit () .onTransition (transition);
97
186
verify (storage.write ('MyHydratedCubit' , expected)).called (2 );
98
187
});
99
188
@@ -112,82 +201,76 @@ void main() {
112
201
final expectedError = Exception ('oops' );
113
202
final transition = const Transition (currentState: 0 , nextState: 0 );
114
203
when (storage.write (any, any)).thenThrow (expectedError);
115
- cubit .onTransition (transition);
204
+ MyHydratedCubit () .onTransition (transition);
116
205
}, onError: (dynamic _) => fail ('should not throw' ));
117
206
});
118
207
119
208
test ('stores initial state when instantiated' , () {
209
+ MyHydratedCubit ();
120
210
verify <dynamic >(
121
211
storage.write ('MyHydratedCubit' , {'value' : 0 }),
122
212
).called (1 );
123
213
});
124
214
125
215
test ('initial state should return 0 when fromJson returns null' , () {
126
216
when < dynamic > (storage.read ('MyHydratedCubit' )).thenReturn (null );
127
- expect (cubit .state, 0 );
128
- verify <dynamic >(storage.read ('MyHydratedCubit' )).called (2 );
217
+ expect (MyHydratedCubit () .state, 0 );
218
+ verify <dynamic >(storage.read ('MyHydratedCubit' )).called (1 );
129
219
});
130
220
131
221
test ('initial state should return 0 when deserialization fails' , () {
132
222
when < dynamic > (storage.read ('MyHydratedCubit' ))
133
223
.thenThrow (Exception ('oops' ));
134
- expect (cubit .state, 0 );
224
+ expect (MyHydratedCubit () .state, 0 );
135
225
});
136
226
137
227
test ('initial state should return 101 when fromJson returns 101' , () {
138
228
when < dynamic > (storage.read ('MyHydratedCubit' ))
139
229
.thenReturn ({'value' : 101 });
140
- expect (cubit.state, 101 );
141
- verify <dynamic >(storage.read ('MyHydratedCubit' )).called (2 );
230
+
231
+ expect (MyHydratedCubit ().state, 101 );
232
+ verify <dynamic >(storage.read ('MyHydratedCubit' )).called (1 );
142
233
});
143
234
144
235
group ('clear' , () {
145
236
test ('calls delete on storage' , () async {
146
- await cubit .clear ();
237
+ await MyHydratedCubit () .clear ();
147
238
verify (storage.delete ('MyHydratedCubit' )).called (1 );
148
239
});
149
240
});
150
241
});
151
242
152
243
group ('MultiHydratedCubit' , () {
153
- MyMultiHydratedCubit multiCubitA;
154
- MyMultiHydratedCubit multiCubitB;
155
-
156
- setUp (() {
157
- multiCubitA = MyMultiHydratedCubit ('A' );
158
- multiCubitB = MyMultiHydratedCubit ('B' );
159
- });
160
-
161
244
test ('initial state should return 0 when fromJson returns null' , () {
162
245
when < dynamic > (storage.read ('MyMultiHydratedCubitA' )).thenReturn (null );
163
- expect (multiCubitA .state, 0 );
164
- verify <dynamic >(storage.read ('MyMultiHydratedCubitA' )).called (2 );
246
+ expect (MyMultiHydratedCubit ( 'A' ) .state, 0 );
247
+ verify <dynamic >(storage.read ('MyMultiHydratedCubitA' )).called (1 );
165
248
166
249
when < dynamic > (storage.read ('MyMultiHydratedCubitB' )).thenReturn (null );
167
- expect (multiCubitB .state, 0 );
168
- verify <dynamic >(storage.read ('MyMultiHydratedCubitB' )).called (2 );
250
+ expect (MyMultiHydratedCubit ( 'B' ) .state, 0 );
251
+ verify <dynamic >(storage.read ('MyMultiHydratedCubitB' )).called (1 );
169
252
});
170
253
171
254
test ('initial state should return 101/102 when fromJson returns 101/102' ,
172
255
() {
173
256
when < dynamic > (storage.read ('MyMultiHydratedCubitA' ))
174
257
.thenReturn ({'value' : 101 });
175
- expect (multiCubitA .state, 101 );
176
- verify <dynamic >(storage.read ('MyMultiHydratedCubitA' )).called (2 );
258
+ expect (MyMultiHydratedCubit ( 'A' ) .state, 101 );
259
+ verify <dynamic >(storage.read ('MyMultiHydratedCubitA' )).called (1 );
177
260
178
261
when < dynamic > (storage.read ('MyMultiHydratedCubitB' ))
179
262
.thenReturn ({'value' : 102 });
180
- expect (multiCubitB .state, 102 );
181
- verify <dynamic >(storage.read ('MyMultiHydratedCubitB' )).called (2 );
263
+ expect (MyMultiHydratedCubit ( 'B' ) .state, 102 );
264
+ verify <dynamic >(storage.read ('MyMultiHydratedCubitB' )).called (1 );
182
265
});
183
266
184
267
group ('clear' , () {
185
268
test ('calls delete on storage' , () async {
186
- await multiCubitA .clear ();
269
+ await MyMultiHydratedCubit ( 'A' ) .clear ();
187
270
verify (storage.delete ('MyMultiHydratedCubitA' )).called (1 );
188
271
verifyNever (storage.delete ('MyMultiHydratedCubitB' ));
189
272
190
- await multiCubitB .clear ();
273
+ await MyMultiHydratedCubit ( 'B' ) .clear ();
191
274
verify (storage.delete ('MyMultiHydratedCubitB' )).called (1 );
192
275
});
193
276
});
0 commit comments