From 003accb7dd47bfb4d804fbabd1c4ba991b94cd1d Mon Sep 17 00:00:00 2001 From: Rafael Amizes Date: Mon, 19 Aug 2024 13:40:48 -0300 Subject: [PATCH] build: bump up dependencies Closes 154 --- CHANGELOG.md | 5 ++ lib/src/json_cache_local_storage.dart | 50 ++++++++------- pubspec.lock | 66 +++++++++---------- pubspec.yaml | 6 +- test/fake_local_storage.dart | 71 +++++++++++++++++++++ test/flutter_secure_storage_mock.dart | 85 ++++++++++++++++++------- test/json_cache_local_storage_test.dart | 60 ++++++++--------- 7 files changed, 230 insertions(+), 113 deletions(-) create mode 100644 test/fake_local_storage.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cf6557..863fbe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Bump up dependencies — + [154](https://github.com/dartoos-dev/json_cache/issues/154). + ### Fixed - Removed code warnings and upgraded dart SDK range and each dependency to latest resolvable version available - [148](https://github.com/dartoos-dev/json_cache/issues/148). diff --git a/lib/src/json_cache_local_storage.dart b/lib/src/json_cache_local_storage.dart index 6bf35ea..8b0325a 100644 --- a/lib/src/json_cache_local_storage.dart +++ b/lib/src/json_cache_local_storage.dart @@ -1,45 +1,47 @@ +import 'dart:convert'; + import 'package:json_cache/json_cache.dart'; import 'package:localstorage/localstorage.dart'; +/// {@template json_cache_local_storage} +/// /// Implementation on top of the LocalStorage package. /// +/// Before using it, don't forget to call: +/// +/// ```dart +/// WidgetsFlutterBinding.ensureInitialized(); +/// await initLocalStorage(); +/// ``` +/// /// See: [local storage](https://pub.dev/packages/localstorage) -class JsonCacheLocalStorage implements JsonCache { - /// Encapsulates a [LocalStorage] instance. - const JsonCacheLocalStorage(this._storage); +/// +/// {@endtemplate} +final class JsonCacheLocalStorage implements JsonCache { + /// {@macro json_cache_local_storage} + JsonCacheLocalStorage([LocalStorage? customLocalStorage]) + : _storage = customLocalStorage ?? localStorage; final LocalStorage _storage; @override - Future clear() async { - await _getReady; - await _storage.clear(); - } + Future clear() async => _storage.clear(); @override - Future refresh(String key, Map value) async { - await _getReady; - await _storage.setItem(key, value); - } + Future refresh(String key, Map value) async => + _storage.setItem(key, json.encode(value)); @override - Future remove(String key) async { - await _getReady; - await _storage.deleteItem(key); - } + Future remove(String key) async => _storage.removeItem(key); @override Future?> value(String key) async { - await _getReady; - return await _storage.getItem(key) as Map?; + final strJson = _storage.getItem(key); + return strJson == null + ? null + : json.decode(strJson) as Map; } @override - Future contains(String key) async { - await _getReady; - final Object? item = _storage.getItem(key); - return item != null; - } - - Future get _getReady => _storage.ready; + Future contains(String key) async => _storage.getItem(key) != null; } diff --git a/pubspec.lock b/pubspec.lock index 5532403..9f95999 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -122,50 +122,50 @@ packages: dependency: "direct main" description: name: flutter_secure_storage - sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685 + sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0" url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "9.2.2" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e" + sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c + sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.1.2" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e" + sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.2" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20" + sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.1" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108" + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.2" flutter_test: dependency: "direct dev" description: flutter @@ -276,10 +276,10 @@ packages: dependency: "direct main" description: name: localstorage - sha256: fdff4f717114e992acfd4045dc4a9ab9b987ca57f020965d63e3eb34089c60d8 + sha256: "6340acefdd3a969cceb044a69cde2dc5877c5b861b2e02d0803930ed483dbe91" url: "https://pub.dev" source: hosted - version: "4.0.1+4" + version: "5.0.0" logging: dependency: transitive description: @@ -364,10 +364,10 @@ packages: dependency: transitive description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" path_provider_android: dependency: transitive description: @@ -452,58 +452,58 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.3.2" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: a7e8467e9181cef109f601e3f65765685786c1a738a83d7fbbde377589c0d974 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.1" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.5.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.4.2" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shelf: dependency: transitive description: @@ -665,10 +665,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "1.0.0" web_socket_channel: dependency: transitive description: @@ -711,4 +711,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.5.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index 5224c1c..ae99370 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,12 +11,12 @@ environment: dependencies: flutter: sdk: flutter - flutter_secure_storage: ^9.0.0 + flutter_secure_storage: ^9.2.2 hive: ^2.2.3 - localstorage: ^4.0.1+4 + localstorage: ^5.0.0 mutex: ^3.1.0 safe_local_storage: ^1.0.2 - shared_preferences: ^2.2.2 + shared_preferences: ^2.3.2 dev_dependencies: flutter_test: diff --git a/test/fake_local_storage.dart b/test/fake_local_storage.dart new file mode 100644 index 0000000..ba669ff --- /dev/null +++ b/test/fake_local_storage.dart @@ -0,0 +1,71 @@ +import 'package:localstorage/localstorage.dart'; + +typedef IndexValue = ({int index, String value}); + +/// {@template fake_local_storage} +/// +/// Unit-testing purposes implementation of the [LocalStorage] interface. +/// +/// {@endtemplate} +final class FakeLocalStorage implements LocalStorage { + /// {@macro fake_local_storage} + FakeLocalStorage(); + + final Map _data = {}; + final List _keys = []; + + @override + void clear() { + _data.clear(); + _keys.clear(); + } + + @override + String? getItem(String key) => _data[key]?.value; + + @override + String? key(int index) { + if (index >= 0 && index < _keys.length) { + return _keys[index]; + } + return null; + } + + @override + int get length => _data.keys.length; + + @override + void removeItem(String key) { + final pair = _data[key]; + if (pair != null) { + _removeItemAndDecreaseIndexes(key, pair); + } + } + + @override + void setItem(String key, String value) { + final pair = _data[key]; + if (pair != null) { + final currIndex = pair.index; + _data[key] = (index: currIndex, value: value); + } else { + _keys.add(key); + final newIndex = _keys.length - 1; + _data[key] = (index: newIndex, value: value); + } + } + + void _removeItemAndDecreaseIndexes( + String key, + ({int index, String value}) pair, + ) { + _keys.removeAt(pair.index); + _data.remove(key); + _data.keys.forEach(_decreaseIndexAt); + } + + void _decreaseIndexAt(String key) { + final pair = _data[key]!; + _data[key] = (index: pair.index - 1, value: pair.value); + } +} diff --git a/test/flutter_secure_storage_mock.dart b/test/flutter_secure_storage_mock.dart index fcce372..ae0f976 100644 --- a/test/flutter_secure_storage_mock.dart +++ b/test/flutter_secure_storage_mock.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:flutter/src/foundation/basic_types.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:json_cache/json_cache.dart'; @@ -13,10 +14,6 @@ class FlutterSecureStorageMock implements FlutterSecureStorage { final JsonCache _fakeCache; - /// throws [UnimplementedError]. - @override - AndroidOptions get aOptions => throw UnimplementedError(); - /// Tells how many times [write] has been invoked. int writeInvokations = 0; @@ -28,6 +25,7 @@ class FlutterSecureStorageMock implements FlutterSecureStorage { /// Tells how many times [deleteAll] has been invoked. int deleteAllInvokations = 0; + @override Future containsKey({ required String key, @@ -68,18 +66,6 @@ class FlutterSecureStorageMock implements FlutterSecureStorage { await _fakeCache.clear(); } - /// throws [UnimplementedError]. - @override - IOSOptions get iOptions => throw UnimplementedError(); - - /// throws [UnimplementedError]. - @override - LinuxOptions get lOptions => throw UnimplementedError(); - - /// throws [UnimplementedError]. - @override - MacOsOptions get mOptions => throw UnimplementedError(); - @override Future read({ required String key, @@ -109,14 +95,6 @@ class FlutterSecureStorageMock implements FlutterSecureStorage { throw UnimplementedError(); } - /// throws [UnimplementedError]. - @override - WindowsOptions get wOptions => throw UnimplementedError(); - - /// throws [UnimplementedError]. - @override - WebOptions get webOptions => throw UnimplementedError(); - @override Future write({ required String key, @@ -133,4 +111,63 @@ class FlutterSecureStorageMock implements FlutterSecureStorage { await _fakeCache.refresh(key, json.decode(value) as Map); } } + + /// throws [UnimplementedError]. + @override + WindowsOptions get wOptions => throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + WebOptions get webOptions => throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + AndroidOptions get aOptions => throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + IOSOptions get iOptions => throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + LinuxOptions get lOptions => throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + MacOsOptions get mOptions => throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + Future isCupertinoProtectedDataAvailable() => + throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + Stream? get onCupertinoProtectedDataAvailabilityChanged => + throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + void registerListener({ + required String key, + required ValueChanged listener, + }) => + throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + void unregisterAllListeners() => throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + void unregisterAllListenersForKey({required String key}) => + throw UnimplementedError(); + + /// throws [UnimplementedError]. + @override + void unregisterListener({ + required String key, + required ValueChanged listener, + }) => + throw UnimplementedError(); } diff --git a/test/json_cache_local_storage_test.dart b/test/json_cache_local_storage_test.dart index faeeb98..57c0412 100644 --- a/test/json_cache_local_storage_test.dart +++ b/test/json_cache_local_storage_test.dart @@ -1,21 +1,19 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:json_cache/json_cache.dart'; -import 'package:localstorage/localstorage.dart'; + +import 'fake_local_storage.dart'; void main() { - final LocalStorage storage = - LocalStorage('json_cache_local_storage_unit_test'); group('JsonCacheLocalStorage', () { test('clear, recover and refresh', () async { const profKey = 'profile'; const profData = {'id': 1, 'name': 'John Due'}; - final JsonCacheLocalStorage localStorageCache = - JsonCacheLocalStorage(storage); - await localStorageCache.refresh(profKey, profData); - var prof = await localStorageCache.value(profKey); + final JsonCacheLocalStorage jsonCache = _fakeInstance; + await jsonCache.refresh(profKey, profData); + var prof = await jsonCache.value(profKey); expect(prof, profData); - await localStorageCache.clear(); - prof = await localStorageCache.value(profKey); + await jsonCache.clear(); + prof = await jsonCache.value(profKey); expect(prof, isNull); }); @@ -27,21 +25,21 @@ void main() { 'theme': 'dark', 'notifications': {'enabled': true}, }; - final crossLocal = JsonCacheLocalStorage(storage); + final JsonCacheLocalStorage jsonCache = _fakeInstance; // update data - await crossLocal.refresh(profKey, profData); - await crossLocal.refresh(prefKey, prefData); + await jsonCache.refresh(profKey, profData); + await jsonCache.refresh(prefKey, prefData); // test for `true` - expect(await crossLocal.contains(profKey), true); - expect(await crossLocal.contains(prefKey), true); + expect(await jsonCache.contains(profKey), true); + expect(await jsonCache.contains(prefKey), true); // test for `false` - expect(await crossLocal.contains('a key'), false); - await crossLocal.remove(profKey); - expect(await crossLocal.contains(profKey), false); - await crossLocal.remove(prefKey); - expect(await crossLocal.contains(prefKey), false); + expect(await jsonCache.contains('a key'), false); + await jsonCache.remove(profKey); + expect(await jsonCache.contains(profKey), false); + await jsonCache.remove(prefKey); + expect(await jsonCache.contains(prefKey), false); }); test('remove', () async { const profKey = 'profile'; @@ -51,23 +49,27 @@ void main() { 'theme': 'dark', 'notifications': {'enabled': true}, }; - final JsonCacheLocalStorage localStorageCache = - JsonCacheLocalStorage(storage); - await localStorageCache.refresh(profKey, profData); - await localStorageCache.refresh(prefKey, prefData); + final JsonCacheLocalStorage jsonCache = _fakeInstance; + await jsonCache.refresh(profKey, profData); + await jsonCache.refresh(prefKey, prefData); - var prof = await localStorageCache.value(profKey); + var prof = await jsonCache.value(profKey); expect(prof, profData); - await localStorageCache.remove(profKey); - prof = await localStorageCache.value(profKey); + await jsonCache.remove(profKey); + prof = await jsonCache.value(profKey); expect(prof, isNull); - var pref = await localStorageCache.value(prefKey); + var pref = await jsonCache.value(prefKey); expect(pref, prefData); - await localStorageCache.remove(prefKey); - pref = await localStorageCache.value(prefKey); + await jsonCache.remove(prefKey); + pref = await jsonCache.value(prefKey); expect(pref, isNull); }); }); } + +/// Helper factory getter. +JsonCacheLocalStorage get _fakeInstance { + return JsonCacheLocalStorage(FakeLocalStorage()); +}