Integrate secure storage service

This commit is contained in:
2025-09-21 11:53:32 +02:00
parent fc888f9c1b
commit 2df5b6ec62
6 changed files with 519 additions and 9 deletions

View File

@@ -0,0 +1,352 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:fluttery/src/storage/secure/secure_storage_impl.dart';
import 'package:mocktail/mocktail.dart';
class MockFlutterSecureStorage extends Mock implements FlutterSecureStorage {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late SecureStorageImpl secureStorage;
late MockFlutterSecureStorage mockStorage;
// Single instance of SecureStorageImpl used throughout all tests
setUpAll(() {
mockStorage = MockFlutterSecureStorage();
secureStorage = SecureStorageImpl.forTesting(instance: mockStorage);
});
setUp(() {
// Reset mock between tests
reset(mockStorage);
});
group('SecureStorageImpl String Tests', () {
test('write and read string work', () async {
const key = 'testStringKey';
const value = 'testStringValue';
when(
() => mockStorage.write(key: key, value: value),
).thenAnswer((_) async {});
when(() => mockStorage.read(key: key)).thenAnswer((_) async => value);
await secureStorage.write(key, value);
final result = await secureStorage.read(key);
expect(result, value);
verify(() => mockStorage.write(key: key, value: value)).called(1);
verify(() => mockStorage.read(key: key)).called(1);
});
test('read returns null for non-existent string key', () async {
const key = 'nonExistentKey';
when(() => mockStorage.read(key: key)).thenAnswer((_) async => null);
final result = await secureStorage.read(key);
expect(result, isNull);
verify(() => mockStorage.read(key: key)).called(1);
});
test('can overwrite existing string values', () async {
const key = 'overwriteKey';
const initialValue = 'initialValue';
const newValue = 'newValue';
when(
() => mockStorage.write(key: key, value: initialValue),
).thenAnswer((_) async {});
when(
() => mockStorage.write(key: key, value: newValue),
).thenAnswer((_) async {});
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => initialValue);
await secureStorage.write(key, initialValue);
final firstResult = await secureStorage.read(key);
expect(firstResult, initialValue);
when(() => mockStorage.read(key: key)).thenAnswer((_) async => newValue);
await secureStorage.write(key, newValue);
final secondResult = await secureStorage.read(key);
expect(secondResult, newValue);
});
});
group('SecureStorageImpl Integer Tests', () {
test('writeInt and readInt work', () async {
const key = 'testIntKey';
const value = 42;
const stringValue = '42';
when(
() => mockStorage.write(key: key, value: stringValue),
).thenAnswer((_) async {});
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => stringValue);
await secureStorage.writeInt(key, value);
final result = await secureStorage.readInt(key);
expect(result, value);
verify(() => mockStorage.write(key: key, value: stringValue)).called(1);
verify(() => mockStorage.read(key: key)).called(1);
});
test('readInt returns null for non-existent key', () async {
const key = 'nonExistentIntKey';
when(() => mockStorage.read(key: key)).thenAnswer((_) async => null);
final result = await secureStorage.readInt(key);
expect(result, isNull);
verify(() => mockStorage.read(key: key)).called(1);
});
test('readInt handles negative numbers', () async {
const key = 'negativeIntKey';
const value = -123;
const stringValue = '-123';
when(
() => mockStorage.write(key: key, value: stringValue),
).thenAnswer((_) async {});
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => stringValue);
await secureStorage.writeInt(key, value);
final result = await secureStorage.readInt(key);
expect(result, value);
});
test('readInt returns null for invalid integer string', () async {
const key = 'invalidIntKey';
const invalidValue = 'not_a_number';
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => invalidValue);
final result = await secureStorage.readInt(key);
expect(result, isNull);
});
});
group('SecureStorageImpl Boolean Tests', () {
test('writeBool and readBool work with true', () async {
const key = 'testBoolTrueKey';
const value = true;
const stringValue = 'true';
when(
() => mockStorage.write(key: key, value: stringValue),
).thenAnswer((_) async {});
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => stringValue);
await secureStorage.writeBool(key, value);
final result = await secureStorage.readBool(key);
expect(result, value);
});
test('writeBool and readBool work with false', () async {
const key = 'testBoolFalseKey';
const value = false;
const stringValue = 'false';
when(
() => mockStorage.write(key: key, value: stringValue),
).thenAnswer((_) async {});
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => stringValue);
await secureStorage.writeBool(key, value);
final result = await secureStorage.readBool(key);
expect(result, value);
});
test('readBool handles case insensitive true/false', () async {
const key = 'caseInsensitiveKey';
// Test "TRUE"
when(() => mockStorage.read(key: key)).thenAnswer((_) async => 'TRUE');
expect(await secureStorage.readBool(key), true);
// Test "False"
when(() => mockStorage.read(key: key)).thenAnswer((_) async => 'False');
expect(await secureStorage.readBool(key), false);
});
test('readBool returns null for invalid boolean string', () async {
const key = 'invalidBoolKey';
const invalidValue = 'maybe';
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => invalidValue);
final result = await secureStorage.readBool(key);
expect(result, isNull);
});
});
group('SecureStorageImpl Double Tests', () {
test('writeDouble and readDouble work', () async {
const key = 'testDoubleKey';
const value = 3.14159;
const stringValue = '3.14159';
when(
() => mockStorage.write(key: key, value: stringValue),
).thenAnswer((_) async {});
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => stringValue);
await secureStorage.writeDouble(key, value);
final result = await secureStorage.readDouble(key);
expect(result, value);
});
test('readDouble returns null for invalid double string', () async {
const key = 'invalidDoubleKey';
const invalidValue = 'not_a_double';
when(
() => mockStorage.read(key: key),
).thenAnswer((_) async => invalidValue);
final result = await secureStorage.readDouble(key);
expect(result, isNull);
});
});
group('SecureStorageImpl Utility Tests', () {
test('containsKey returns true for existing key', () async {
const key = 'existingKey';
when(
() => mockStorage.containsKey(key: key),
).thenAnswer((_) async => true);
final exists = await secureStorage.containsKey(key);
expect(exists, isTrue);
verify(() => mockStorage.containsKey(key: key)).called(1);
});
test('containsKey returns false for non-existent key', () async {
const key = 'nonExistentKey';
when(
() => mockStorage.containsKey(key: key),
).thenAnswer((_) async => false);
final exists = await secureStorage.containsKey(key);
expect(exists, isFalse);
});
test('delete removes key-value pair', () async {
const key = 'deleteTestKey';
when(() => mockStorage.delete(key: key)).thenAnswer((_) async {});
await secureStorage.delete(key);
verify(() => mockStorage.delete(key: key)).called(1);
});
test('readAll and readAllKeys return all stored keys', () async {
final testData = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'};
when(() => mockStorage.readAll()).thenAnswer((_) async => testData);
final allKeys = await secureStorage.readAll();
final allKeysAlt = await secureStorage.readAllKeys();
expect(allKeys, containsAll(testData.keys));
expect(allKeys.length, testData.length);
expect(allKeysAlt, equals(allKeys));
});
test('deleteAll removes all key-value pairs', () async {
when(() => mockStorage.deleteAll()).thenAnswer((_) async {});
await secureStorage.deleteAll();
verify(() => mockStorage.deleteAll()).called(1);
});
});
group('SecureStorageImpl Mixed Data Type Tests', () {
test('different data types work correctly', () async {
const stringKey = 'stringKey';
const intKey = 'intKey';
const boolKey = 'boolKey';
const doubleKey = 'doubleKey';
const stringValue = 'hello world';
const intValue = 123;
const boolValue = true;
const doubleValue = 45.67;
// Mock all write operations
when(
() => mockStorage.write(key: stringKey, value: stringValue),
).thenAnswer((_) async {});
when(
() => mockStorage.write(key: intKey, value: intValue.toString()),
).thenAnswer((_) async {});
when(
() => mockStorage.write(key: boolKey, value: boolValue.toString()),
).thenAnswer((_) async {});
when(
() => mockStorage.write(key: doubleKey, value: doubleValue.toString()),
).thenAnswer((_) async {});
// Mock all read operations
when(
() => mockStorage.read(key: stringKey),
).thenAnswer((_) async => stringValue);
when(
() => mockStorage.read(key: intKey),
).thenAnswer((_) async => intValue.toString());
when(
() => mockStorage.read(key: boolKey),
).thenAnswer((_) async => boolValue.toString());
when(
() => mockStorage.read(key: doubleKey),
).thenAnswer((_) async => doubleValue.toString());
// Store different types
await secureStorage.write(stringKey, stringValue);
await secureStorage.writeInt(intKey, intValue);
await secureStorage.writeBool(boolKey, boolValue);
await secureStorage.writeDouble(doubleKey, doubleValue);
// Retrieve and verify all types
expect(await secureStorage.read(stringKey), stringValue);
expect(await secureStorage.readInt(intKey), intValue);
expect(await secureStorage.readBool(boolKey), boolValue);
expect(await secureStorage.readDouble(doubleKey), doubleValue);
});
});
}