Skip to content

Commit 1d79d4a

Browse files
test: add unit tests for platform interface
1 parent e99932a commit 1d79d4a

File tree

2 files changed

+214
-14
lines changed

2 files changed

+214
-14
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import 'package:flutter_secure_storage_platform_interface/flutter_secure_storage_platform_interface.dart';
2+
import 'package:mocktail/mocktail.dart';
3+
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
4+
5+
class MockFlutterSecureStoragePlatform extends Mock
6+
with MockPlatformInterfaceMixin
7+
implements FlutterSecureStoragePlatform {}
8+
9+
class ImplementsFlutterSecureStoragePlatform extends Mock
10+
implements FlutterSecureStoragePlatform {}
11+
12+
class ExtendsFlutterSecureStoragePlatform extends FlutterSecureStoragePlatform {
13+
@override
14+
Future<bool> containsKey({
15+
required String key,
16+
required Map<String, String> options,
17+
}) =>
18+
Future.value(true);
19+
20+
@override
21+
Future<void> delete({
22+
required String key,
23+
required Map<String, String> options,
24+
}) =>
25+
Future<void>.value();
26+
27+
@override
28+
Future<void> deleteAll({required Map<String, String> options}) =>
29+
Future<void>.value();
30+
31+
@override
32+
Future<String?> read({
33+
required String key,
34+
required Map<String, String> options,
35+
}) =>
36+
Future<String?>.value();
37+
38+
@override
39+
Future<Map<String, String>> readAll({required Map<String, String> options}) =>
40+
Future.value(<String, String>{});
41+
42+
@override
43+
Future<void> write({
44+
required String key,
45+
required String value,
46+
required Map<String, String> options,
47+
}) =>
48+
Future<void>.value();
49+
50+
// @override
51+
// Future<bool> isCupertinoProtectedDataAvailable() => Future.value(true);
52+
//
53+
// @override
54+
// Stream<bool> get onCupertinoProtectedDataAvailabilityChanged =>
55+
// Stream.value(true);
56+
}

flutter_secure_storage/test/flutter_secure_storage_test.dart

Lines changed: 158 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,169 @@
1+
import 'package:flutter/services.dart';
12
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
23
import 'package:flutter_secure_storage_platform_interface/flutter_secure_storage_platform_interface.dart';
34
import 'package:flutter_test/flutter_test.dart';
45
import 'package:mocktail/mocktail.dart';
5-
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
66

7-
// ✅ Correct Mock Class Implementation
8-
class MockFlutterSecureStoragePlatform extends Mock
9-
with MockPlatformInterfaceMixin
10-
implements FlutterSecureStoragePlatform {}
7+
import 'flutter_secure_storage_mock.dart';
118

129
void main() {
10+
TestWidgetsFlutterBinding.ensureInitialized();
11+
1312
late FlutterSecureStorage storage;
1413
late MockFlutterSecureStoragePlatform mockPlatform;
1514

15+
const channel = MethodChannel('plugins.it_nomads.com/flutter_secure_storage');
16+
final methodStorage = MethodChannelFlutterSecureStorage();
17+
final log = <MethodCall>[];
18+
19+
Future<bool?>? handler(MethodCall methodCall) async {
20+
log.add(methodCall);
21+
if (methodCall.method == 'containsKey') {
22+
return true;
23+
} else if (methodCall.method == 'isProtectedDataAvailable') {
24+
return true;
25+
}
26+
return null;
27+
}
28+
1629
setUp(() {
1730
mockPlatform = MockFlutterSecureStoragePlatform();
1831
FlutterSecureStoragePlatform.instance = mockPlatform;
1932
storage = const FlutterSecureStorage();
33+
34+
// Ensure method channel mock is set up for the tests
35+
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
36+
.setMockMethodCallHandler(channel, handler);
37+
38+
log.clear(); // Clear logs before each test
39+
});
40+
41+
tearDown(() {
42+
log.clear(); // Clear logs after each test
43+
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
44+
.setMockMethodCallHandler(channel, null); // Remove the mock handler
45+
});
46+
47+
group('Method Channel Interaction Tests for FlutterSecureStorage', () {
48+
test('read', () async {
49+
const key = 'test_key';
50+
const options = <String, String>{};
51+
await methodStorage.read(key: key, options: options);
52+
53+
expect(
54+
log,
55+
<Matcher>[
56+
isMethodCall(
57+
'read',
58+
arguments: <String, Object>{
59+
'key': key,
60+
'options': options,
61+
},
62+
),
63+
],
64+
);
65+
});
66+
67+
test('write', () async {
68+
const key = 'test_key';
69+
const options = <String, String>{};
70+
await methodStorage.write(key: key, value: 'test', options: options);
71+
72+
expect(
73+
log,
74+
<Matcher>[
75+
isMethodCall(
76+
'write',
77+
arguments: <String, Object>{
78+
'key': key,
79+
'value': 'test',
80+
'options': options,
81+
},
82+
),
83+
],
84+
);
85+
});
86+
87+
test('containsKey', () async {
88+
const key = 'test_key';
89+
const options = <String, String>{};
90+
await methodStorage.write(key: key, value: 'test', options: options);
91+
92+
final result =
93+
await methodStorage.containsKey(key: key, options: options);
94+
95+
expect(result, true);
96+
});
97+
98+
test('delete', () async {
99+
const key = 'test_key';
100+
const options = <String, String>{};
101+
await methodStorage.write(key: key, value: 'test', options: options);
102+
await methodStorage.delete(key: key, options: options);
103+
104+
expect(
105+
log,
106+
<Matcher>[
107+
isMethodCall(
108+
'write',
109+
arguments: <String, Object>{
110+
'key': key,
111+
'value': 'test',
112+
'options': options,
113+
},
114+
),
115+
isMethodCall(
116+
'delete',
117+
arguments: <String, Object>{
118+
'key': key,
119+
'options': options,
120+
},
121+
),
122+
],
123+
);
124+
});
125+
126+
test('deleteAll', () async {
127+
const options = <String, String>{};
128+
await methodStorage.deleteAll(options: options);
129+
130+
expect(
131+
log,
132+
<Matcher>[
133+
isMethodCall(
134+
'deleteAll',
135+
arguments: <String, Object>{
136+
'options': options,
137+
},
138+
),
139+
],
140+
);
141+
});
142+
});
143+
144+
group('Platform-Specific Interface Tests', () {
145+
test('Cannot be implemented with `implements`', () {
146+
expect(
147+
() {
148+
FlutterSecureStoragePlatform.instance =
149+
ImplementsFlutterSecureStoragePlatform();
150+
},
151+
throwsA(isInstanceOf<AssertionError>()),
152+
);
153+
});
154+
155+
test('Can be mocked with `implements`', () {
156+
final mock = MockFlutterSecureStoragePlatform();
157+
FlutterSecureStoragePlatform.instance = mock;
158+
});
159+
160+
test('Can be extended', () {
161+
FlutterSecureStoragePlatform.instance =
162+
ExtendsFlutterSecureStoragePlatform();
163+
});
20164
});
21165

22-
group('FlutterSecureStorage Tests', () {
166+
group('FlutterSecureStorage Methods Invocation Tests', () {
23167
const testKey = 'testKey';
24168
const testValue = 'testValue';
25169

@@ -118,7 +262,7 @@ void main() {
118262
});
119263
});
120264

121-
group('AndroidOptions Tests', () {
265+
group('AndroidOptions Configuration Tests', () {
122266
test('Default AndroidOptions should have correct default values', () {
123267
const options = AndroidOptions.defaultOptions;
124268

@@ -201,7 +345,7 @@ void main() {
201345
});
202346
});
203347

204-
group('WebOptions Tests', () {
348+
group('WebOptions Configuration Tests', () {
205349
test('Default WebOptions should have correct default values', () {
206350
const options = WebOptions.defaultOptions;
207351

@@ -261,7 +405,7 @@ void main() {
261405
});
262406
});
263407

264-
group('WindowsOptions Tests', () {
408+
group('WindowsOptions Configuration Tests', () {
265409
test('Default WindowsOptions should have correct default values', () {
266410
const options = WindowsOptions.defaultOptions;
267411

@@ -308,7 +452,7 @@ void main() {
308452
});
309453
});
310454

311-
group('IOSOptions Tests', () {
455+
group('iOSOptions Configuration Tests', () {
312456
test('Default IOSOptions should have correct default values', () {
313457
const options = IOSOptions.defaultOptions;
314458

@@ -368,8 +512,8 @@ void main() {
368512
});
369513
});
370514

371-
group('MacOsOptions Tests', () {
372-
test('Default MacOsOptions should have correct default values', () {
515+
group('macOSOptions Configuration Tests', () {
516+
test('Default macOSOptions should have correct default values', () {
373517
// Ignore for test
374518
// ignore: use_named_constants
375519
const options = MacOsOptions();
@@ -382,7 +526,7 @@ void main() {
382526
});
383527
});
384528

385-
test('MacOsOptions with custom values', () {
529+
test('macOSOptions with custom values', () {
386530
const options = MacOsOptions(
387531
accountName: 'macAccount',
388532
groupId: 'group.mac.example',
@@ -400,7 +544,7 @@ void main() {
400544
});
401545
});
402546

403-
test('MacOsOptions defaultOptions matches default constructor', () {
547+
test('macOSOptions defaultOptions matches default constructor', () {
404548
const defaultOptions = MacOsOptions.defaultOptions;
405549
// Ignore for test
406550
// ignore: use_named_constants

0 commit comments

Comments
 (0)