From cdd6e1368ffdf6a4fc9c0c11b72cfc5388f90f2d Mon Sep 17 00:00:00 2001 From: Tarrin Neal Date: Fri, 9 Aug 2024 13:16:24 -0700 Subject: [PATCH] [shared_preferences] fix cast error and mutable list error with `getStringList` (#7355) fixes https://github.com/flutter/flutter/issues/153106 fixes https://github.com/flutter/flutter/issues/153112 Will add a follow up pr adding a test to the top level package after this pr lands. --- .../shared_preferences_android/CHANGELOG.md | 4 +++ .../shared_preferences_test.dart | 10 +++++++ .../src/shared_preferences_async_android.dart | 3 +- .../shared_preferences_android/pubspec.yaml | 2 +- .../CHANGELOG.md | 3 +- .../shared_preferences_test.dart | 10 +++++++ .../shared_preferences_async_foundation.dart | 3 +- .../pubspec.yaml | 2 +- .../shared_preferences_linux/CHANGELOG.md | 4 ++- .../shared_preferences_test.dart | 29 +++++++++++++++--- .../lib/shared_preferences_linux.dart | 10 ++++++- .../shared_preferences_linux/pubspec.yaml | 2 +- .../shared_preferences_web/CHANGELOG.md | 3 +- .../shared_preferences_web_test.dart | 10 +++++++ .../lib/shared_preferences_web.dart | 2 +- .../shared_preferences_web/pubspec.yaml | 2 +- .../shared_preferences_windows/CHANGELOG.md | 4 ++- .../shared_preferences_test.dart | 30 ++++++++++++++++--- .../lib/shared_preferences_windows.dart | 10 ++++++- .../shared_preferences_windows/pubspec.yaml | 2 +- 20 files changed, 123 insertions(+), 22 deletions(-) diff --git a/packages/shared_preferences/shared_preferences_android/CHANGELOG.md b/packages/shared_preferences/shared_preferences_android/CHANGELOG.md index 1691a73764c6..e37c4f051d28 100644 --- a/packages/shared_preferences/shared_preferences_android/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.3.1 + +* Fixes `getStringList` returning immutable list. + ## 2.3.0 * Adds new `SharedPreferencesAsyncAndroid` API. diff --git a/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart index 0c4527f46706..48f451d20a1f 100644 --- a/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart @@ -555,6 +555,16 @@ void main() { expect(await preferences.getStringList(listKey, emptyOptions), testList); }); + testWidgets('getStringList returns mutable list', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + final List? list = + await preferences.getStringList(listKey, emptyOptions); + list?.add('value'); + expect(list?.length, testList.length + 1); + }); + testWidgets('getPreferences', (WidgetTester _) async { final SharedPreferencesAsyncPlatform preferences = await getPreferences(); await Future.wait(>[ diff --git a/packages/shared_preferences/shared_preferences_android/lib/src/shared_preferences_async_android.dart b/packages/shared_preferences/shared_preferences_android/lib/src/shared_preferences_async_android.dart index 7b9b8fa6ade2..7b3f1cb7b352 100644 --- a/packages/shared_preferences/shared_preferences_android/lib/src/shared_preferences_async_android.dart +++ b/packages/shared_preferences/shared_preferences_android/lib/src/shared_preferences_async_android.dart @@ -146,7 +146,8 @@ base class SharedPreferencesAsyncAndroid // is fixed. In practice, the values will never be null, and the native implementation assumes that. return _convertKnownExceptions>(() async => (await _api.getStringList(key, _convertOptionsToPigeonOptions(options))) - ?.cast()); + ?.cast() + .toList()); } Future _convertKnownExceptions(Future Function() method) async { diff --git a/packages/shared_preferences/shared_preferences_android/pubspec.yaml b/packages/shared_preferences/shared_preferences_android/pubspec.yaml index bd1adb8cb9c8..f86a08afdc6d 100644 --- a/packages/shared_preferences/shared_preferences_android/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_android/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_android description: Android implementation of the shared_preferences plugin repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.3.0 +version: 2.3.1 environment: sdk: ^3.4.0 diff --git a/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md b/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md index 1eec97916734..dbd80f8926d5 100644 --- a/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.5.1 +* Fixes `getStringList` returning immutable list. * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. ## 2.5.0 diff --git a/packages/shared_preferences/shared_preferences_foundation/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_foundation/example/integration_test/shared_preferences_test.dart index 67777288d983..672f453e5ecd 100644 --- a/packages/shared_preferences/shared_preferences_foundation/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_foundation/example/integration_test/shared_preferences_test.dart @@ -544,6 +544,16 @@ void main() { expect(await preferences.getStringList(listKey, emptyOptions), testList); }); + testWidgets('getStringList returns mutable list', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + final List? list = + await preferences.getStringList(listKey, emptyOptions); + list?.add('value'); + expect(list?.length, testList.length + 1); + }); + testWidgets('getPreferences', (WidgetTester _) async { final SharedPreferencesAsyncPlatform preferences = await getPreferences(); await Future.wait(>[ diff --git a/packages/shared_preferences/shared_preferences_foundation/lib/src/shared_preferences_async_foundation.dart b/packages/shared_preferences/shared_preferences_foundation/lib/src/shared_preferences_async_foundation.dart index 3bf3bc24149d..df60e88522db 100644 --- a/packages/shared_preferences/shared_preferences_foundation/lib/src/shared_preferences_async_foundation.dart +++ b/packages/shared_preferences/shared_preferences_foundation/lib/src/shared_preferences_async_foundation.dart @@ -158,7 +158,8 @@ base class SharedPreferencesAsyncFoundation return _convertKnownExceptions>(() async => ((await _api.getValue(key, _convertOptionsToPigeonOptions(options))) as List?) - ?.cast()); + ?.cast() + .toList()); } @override diff --git a/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml b/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml index f465f9120d1b..50b20675b808 100644 --- a/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_foundation description: iOS and macOS implementation of the shared_preferences plugin. repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.5.0 +version: 2.5.1 environment: sdk: ^3.3.0 diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index 6d467e9f05ec..43c46f51a84f 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,5 +1,7 @@ -## NEXT +## 2.4.1 +* Fixes `getStringList` returning immutable list. +* Fixes `getStringList` cast error. * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. ## 2.4.0 diff --git a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart index 370839f0e9c3..fdabea41342e 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart @@ -354,12 +354,15 @@ void main() { const double testDouble = 3.14159; const List testList = ['foo', 'bar']; - Future getPreferences() async { + Future getPreferences( + {bool clear = true}) async { final SharedPreferencesAsyncPlatform preferences = SharedPreferencesAsyncPlatform.instance!; - await preferences.clear( - const ClearPreferencesParameters(filter: PreferencesFilters()), - emptyOptions); + if (clear) { + await preferences.clear( + const ClearPreferencesParameters(filter: PreferencesFilters()), + emptyOptions); + } return preferences; } @@ -397,6 +400,24 @@ void main() { await preferences.setStringList(listKey, testList, emptyOptions); expect(await preferences.getStringList(listKey, emptyOptions), testList); }); + testWidgets('getStringList does not throw cast error', + (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + await (preferences as SharedPreferencesAsyncLinux).reload(emptyOptions); + expect(await preferences.getStringList(listKey, emptyOptions), testList); + }); + + testWidgets('getStringList returns mutable list', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + final List? list = + await preferences.getStringList(listKey, emptyOptions); + list?.add('value'); + expect(list?.length, testList.length + 1); + }); testWidgets('getPreferences', (WidgetTester _) async { final SharedPreferencesAsyncPlatform preferences = await getPreferences(); diff --git a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart index 4c7e5268ce1d..d4ede84ec2b9 100644 --- a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart +++ b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart @@ -253,7 +253,7 @@ base class SharedPreferencesAsyncLinux extends SharedPreferencesAsyncPlatform { SharedPreferencesOptions options, ) async { final Map data = await _readAll({key}, options); - return (data[key] as List?)?.toList(); + return (data[key] as List?)?.cast().toList(); } @override @@ -282,6 +282,14 @@ base class SharedPreferencesAsyncLinux extends SharedPreferencesAsyncPlatform { return _readAll(parameters.filter.allowList, options); } + /// Reloads preferences from file. + @visibleForTesting + Future reload( + SharedPreferencesLinuxOptions options, + ) async { + _cachedPreferences = await _reload(options.fileName); + } + Future> _readAll( Set? allowList, SharedPreferencesOptions options, diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index 3e0b0faa64f2..c43a21bdb95f 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_linux issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.4.0 +version: 2.4.1 environment: sdk: ^3.3.0 diff --git a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md index 410e0186fd54..a1c53c014650 100644 --- a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.4.2 +* Fixes `getStringList` returning immutable list. * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. ## 2.4.1 diff --git a/packages/shared_preferences/shared_preferences_web/example/integration_test/shared_preferences_web_test.dart b/packages/shared_preferences/shared_preferences_web/example/integration_test/shared_preferences_web_test.dart index aeb1a6c2a65c..90ebbc5b899c 100644 --- a/packages/shared_preferences/shared_preferences_web/example/integration_test/shared_preferences_web_test.dart +++ b/packages/shared_preferences/shared_preferences_web/example/integration_test/shared_preferences_web_test.dart @@ -444,6 +444,16 @@ void main() { expect(await preferences.getStringList(listKey, emptyOptions), testList); }); + testWidgets('getStringList returns mutable list', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + final List? list = + await preferences.getStringList(listKey, emptyOptions); + list?.add('value'); + expect(list?.length, testList.length + 1); + }); + testWidgets('getPreferences', (WidgetTester _) async { final SharedPreferencesAsyncPlatform preferences = await getPreferences(); await Future.wait(>[ diff --git a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart index be75e1786bd4..97160b5d150e 100644 --- a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart +++ b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart @@ -243,7 +243,7 @@ base class SharedPreferencesAsyncWeb extends SharedPreferencesAsyncPlatform { ) async { final Map data = await _readAllFromLocalStorage({key}, options); - return data[key] as List?; + return (data[key] as List?)?.toList(); } } diff --git a/packages/shared_preferences/shared_preferences_web/pubspec.yaml b/packages/shared_preferences/shared_preferences_web/pubspec.yaml index 623906aeef23..a8592342dc23 100644 --- a/packages/shared_preferences/shared_preferences_web/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_web/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_web description: Web platform implementation of shared_preferences repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.4.1 +version: 2.4.2 environment: sdk: ^3.4.0 diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index f2053f3f9076..d2cf5d62ace9 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,5 +1,7 @@ -## NEXT +## 2.4.1 +* Fixes `getStringList` returning immutable list. +* Fixes `getStringList` cast error. * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. ## 2.4.0 diff --git a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart index 5549b9b5debd..79192ad28ebc 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart @@ -354,12 +354,15 @@ void main() { const double testDouble = 3.14159; const List testList = ['foo', 'bar']; - Future getPreferences() async { + Future getPreferences( + {bool clear = true}) async { final SharedPreferencesAsyncPlatform preferences = SharedPreferencesAsyncPlatform.instance!; - await preferences.clear( - const ClearPreferencesParameters(filter: PreferencesFilters()), - emptyOptions); + if (clear) { + await preferences.clear( + const ClearPreferencesParameters(filter: PreferencesFilters()), + emptyOptions); + } return preferences; } @@ -398,6 +401,25 @@ void main() { expect(await preferences.getStringList(listKey, emptyOptions), testList); }); + testWidgets('getStringList does not throw cast error', + (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + await (preferences as SharedPreferencesAsyncWindows).reload(emptyOptions); + expect(await preferences.getStringList(listKey, emptyOptions), testList); + }); + + testWidgets('getStringList returns mutable list', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + final List? list = + await preferences.getStringList(listKey, emptyOptions); + list?.add('value'); + expect(list?.length, testList.length + 1); + }); + testWidgets('getPreferences', (WidgetTester _) async { final SharedPreferencesAsyncPlatform preferences = await getPreferences(); await preferences.setString(stringKey, testString, emptyOptions); diff --git a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart index 0a2ec7688e7b..5d72b9823b1a 100644 --- a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart +++ b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart @@ -254,7 +254,7 @@ base class SharedPreferencesAsyncWindows SharedPreferencesOptions options, ) async { final Map data = await _readAll({key}, options); - return (data[key] as List?)?.toList(); + return (data[key] as List?)?.cast().toList(); } @override @@ -283,6 +283,14 @@ base class SharedPreferencesAsyncWindows return _readAll(parameters.filter.allowList, options); } + /// Reloads preferences from file. + @visibleForTesting + Future reload( + SharedPreferencesWindowsOptions options, + ) async { + _cachedPreferences = await _readFromFile(options.fileName); + } + Future> _readAll( Set? allowList, SharedPreferencesOptions options, diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index 579e36925dd0..59c3274488b4 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.4.0 +version: 2.4.1 environment: sdk: ^3.3.0