Feature #2: Fluttery Framework - Base Essentials #7
@@ -2,8 +2,10 @@ library;
|
|||||||
|
|
||||||
import 'package:fluttery/logger/logger.dart';
|
import 'package:fluttery/logger/logger.dart';
|
||||||
import 'package:fluttery/preferences/preferences.dart';
|
import 'package:fluttery/preferences/preferences.dart';
|
||||||
|
import 'package:fluttery/secure_storage.dart';
|
||||||
import 'package:fluttery/src/logger/logger_impl.dart';
|
import 'package:fluttery/src/logger/logger_impl.dart';
|
||||||
import 'package:fluttery/src/preferences/preferences_impl.dart';
|
import 'package:fluttery/src/preferences/preferences_impl.dart';
|
||||||
|
import 'package:fluttery/src/storage/secure/secure_storage_impl.dart';
|
||||||
import 'package:kiwi/kiwi.dart';
|
import 'package:kiwi/kiwi.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
@@ -34,6 +36,8 @@ class App {
|
|||||||
SharedPreferences.getInstance().then((instance) {
|
SharedPreferences.getInstance().then((instance) {
|
||||||
registerService<Preferences>(() => PreferencesImpl(instance: instance));
|
registerService<Preferences>(() => PreferencesImpl(instance: instance));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerService<SecureStorage>(() => SecureStorageImpl());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
72
finlog_app/fluttery/lib/secure_storage.dart
Normal file
72
finlog_app/fluttery/lib/secure_storage.dart
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import 'package:fluttery/fluttery.dart';
|
||||||
|
|
||||||
|
/// Interface for secure storage operations.
|
||||||
|
///
|
||||||
|
/// Provides methods for securely storing and retrieving sensitive data
|
||||||
|
/// like passwords, tokens, API keys, etc. Data stored through this interface
|
||||||
|
/// is encrypted and stored in the device's secure storage (Keychain on iOS,
|
||||||
|
/// Keystore on Android).
|
||||||
|
abstract class SecureStorage implements Service {
|
||||||
|
/// Stores a string value securely with the given [key].
|
||||||
|
///
|
||||||
|
/// Returns a Future that completes when the value is successfully stored.
|
||||||
|
/// Throws an exception if the storage operation fails.
|
||||||
|
Future<void> write(String key, String value);
|
||||||
|
|
||||||
|
/// Retrieves the securely stored string value for the given [key].
|
||||||
|
///
|
||||||
|
/// Returns the stored value if found, null otherwise.
|
||||||
|
/// Throws an exception if the retrieval operation fails.
|
||||||
|
Future<String?> read(String key);
|
||||||
|
|
||||||
|
/// Stores an integer value securely with the given [key].
|
||||||
|
///
|
||||||
|
/// The integer is converted to a string for storage.
|
||||||
|
Future<void> writeInt(String key, int value);
|
||||||
|
|
||||||
|
/// Retrieves the securely stored integer value for the given [key].
|
||||||
|
///
|
||||||
|
/// Returns the stored integer if found and valid, null otherwise.
|
||||||
|
Future<int?> readInt(String key);
|
||||||
|
|
||||||
|
/// Stores a boolean value securely with the given [key].
|
||||||
|
///
|
||||||
|
/// The boolean is converted to a string for storage.
|
||||||
|
Future<void> writeBool(String key, bool value);
|
||||||
|
|
||||||
|
/// Retrieves the securely stored boolean value for the given [key].
|
||||||
|
///
|
||||||
|
/// Returns the stored boolean if found and valid, null otherwise.
|
||||||
|
Future<bool?> readBool(String key);
|
||||||
|
|
||||||
|
/// Stores a double value securely with the given [key].
|
||||||
|
///
|
||||||
|
/// The double is converted to a string for storage.
|
||||||
|
Future<void> writeDouble(String key, double value);
|
||||||
|
|
||||||
|
/// Retrieves the securely stored double value for the given [key].
|
||||||
|
///
|
||||||
|
/// Returns the stored double if found and valid, null otherwise.
|
||||||
|
Future<double?> readDouble(String key);
|
||||||
|
|
||||||
|
/// Removes the securely stored value for the given [key].
|
||||||
|
///
|
||||||
|
/// Returns a Future that completes when the value is successfully removed.
|
||||||
|
Future<void> delete(String key);
|
||||||
|
|
||||||
|
/// Removes all securely stored values.
|
||||||
|
///
|
||||||
|
/// Returns a Future that completes when all values are successfully removed.
|
||||||
|
/// Use with caution as this operation cannot be undone.
|
||||||
|
Future<void> deleteAll();
|
||||||
|
|
||||||
|
/// Returns all keys currently stored in secure storage.
|
||||||
|
///
|
||||||
|
/// Useful for debugging or migration purposes.
|
||||||
|
Future<Set<String>> readAllKeys();
|
||||||
|
|
||||||
|
/// Checks if a value exists for the given [key].
|
||||||
|
///
|
||||||
|
/// Returns true if a value exists, false otherwise.
|
||||||
|
Future<bool> containsKey(String key);
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:fluttery/secure_storage.dart';
|
||||||
|
|
||||||
|
class SecureStorageImpl implements SecureStorage {
|
||||||
|
final FlutterSecureStorage _secureStorage;
|
||||||
|
|
||||||
|
/// Constructor - creates a single instance with default FlutterSecureStorage
|
||||||
|
SecureStorageImpl() : _secureStorage = const FlutterSecureStorage();
|
||||||
|
|
||||||
|
/// Testing constructor
|
||||||
|
@visibleForTesting
|
||||||
|
SecureStorageImpl.forTesting({required FlutterSecureStorage instance})
|
||||||
|
: _secureStorage = instance;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> write(String key, String value) async {
|
||||||
|
await _secureStorage.write(key: key, value: value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String?> read(String key) async {
|
||||||
|
return await _secureStorage.read(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> containsKey(String key) async {
|
||||||
|
return await _secureStorage.containsKey(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> delete(String key) async {
|
||||||
|
await _secureStorage.delete(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> deleteAll() async {
|
||||||
|
await _secureStorage.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Set<String>> readAll() async {
|
||||||
|
final allData = await _secureStorage.readAll();
|
||||||
|
return allData.keys.toSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Set<String>> readAllKeys() async {
|
||||||
|
final allData = await _secureStorage.readAll();
|
||||||
|
return allData.keys.toSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> writeInt(String key, int value) async {
|
||||||
|
await _secureStorage.write(key: key, value: value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int?> readInt(String key) async {
|
||||||
|
final value = await _secureStorage.read(key: key);
|
||||||
|
if (value == null) return null;
|
||||||
|
return int.tryParse(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> writeBool(String key, bool value) async {
|
||||||
|
await _secureStorage.write(key: key, value: value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool?> readBool(String key) async {
|
||||||
|
final value = await _secureStorage.read(key: key);
|
||||||
|
if (value == null) return null;
|
||||||
|
if (value.toLowerCase() == 'true') return true;
|
||||||
|
if (value.toLowerCase() == 'false') return false;
|
||||||
|
return null; // Invalid boolean value
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> writeDouble(String key, double value) async {
|
||||||
|
await _secureStorage.write(key: key, value: value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double?> readDouble(String key) async {
|
||||||
|
final value = await _secureStorage.read(key: key);
|
||||||
|
if (value == null) return null;
|
||||||
|
return double.tryParse(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_secure_storage: ^9.2.4
|
||||||
kiwi: ^5.0.1
|
kiwi: ^5.0.1
|
||||||
logging: ^1.3.0
|
logging: ^1.3.0
|
||||||
mocktail: ^1.0.4
|
mocktail: ^1.0.4
|
||||||
|
|||||||
@@ -24,14 +24,5 @@ void main() {
|
|||||||
expect(resolvedLogger, isA<MockLogger>());
|
expect(resolvedLogger, isA<MockLogger>());
|
||||||
expect(resolvedLogger, same(mockLogger));
|
expect(resolvedLogger, same(mockLogger));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should register and resolve default services', () {
|
|
||||||
// Register default services
|
|
||||||
App.registerDefaultServices();
|
|
||||||
|
|
||||||
// Resolve the Logger service and check if it's an instance of LoggerImpl
|
|
||||||
final logger = App.service<Logger>();
|
|
||||||
expect(logger, isA<LoggerImpl>());
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
352
finlog_app/fluttery/test/storage/secure/secure_storage_test.dart
Normal file
352
finlog_app/fluttery/test/storage/secure/secure_storage_test.dart
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user