From 17d4e2adb2847ffd683397a66bd5486ceb31a347 Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Thu, 18 Jun 2026 17:36:17 +0900 Subject: [PATCH] [shared_preferences] Add integration tests based on upstream v2.5.5 Port the upstream legacy-to-async migration-utility integration tests from shared_preferences v2.5.5, consolidated into the existing test file. For each of the no-prefix, setPrefix, setPrefix+allowList, and empty-prefix legacy configurations: - data is successfully transferred to new system - migrationCompleted key is set - re-running migration tool does not overwrite data The upstream platform-specific async option variants (Android/iOS/Linux/ Windows) collapse to the default options on Tizen and were omitted. The empty-prefix "re-running" case is skipped because the Tizen legacy and async stores share a single preference namespace (matching how upstream skips it on other shared-namespace platforms). Test-only change; recorded under a NEXT changelog entry without a version bump. Validated on a Raspberry Pi 4 device: 75 passed, 1 skipped, 0 failed. --- packages/shared_preferences/CHANGELOG.md | 4 + .../shared_preferences_test.dart | 152 +++++++++++++++++- 2 files changed, 150 insertions(+), 6 deletions(-) diff --git a/packages/shared_preferences/CHANGELOG.md b/packages/shared_preferences/CHANGELOG.md index 9cc292006..af6d7aa36 100644 --- a/packages/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## NEXT + +* Add 12 integration test cases for the legacy-to-async migration utility. + ## 2.3.3 * Update shared_preferences to 2.5.5. diff --git a/packages/shared_preferences/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/example/integration_test/shared_preferences_test.dart index ce25a8722..93829beb2 100644 --- a/packages/shared_preferences/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/example/integration_test/shared_preferences_test.dart @@ -5,16 +5,24 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:shared_preferences/util/legacy_to_async_migration_util.dart'; + +const String testString = 'hello world'; +const bool testBool = true; +const int testInt = 42; +const double testDouble = 3.14159; +const List testList = ['foo', 'bar']; + +const String stringKey = 'testString'; +const String boolKey = 'testBool'; +const String intKey = 'testInt'; +const String doubleKey = 'testDouble'; +const String listKey = 'testList'; +const String migrationCompletedKey = 'migrationCompleted'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - const String testString = 'hello world'; - const bool testBool = true; - const int testInt = 42; - const double testDouble = 3.14159; - const List testList = ['foo', 'bar']; - const String testString2 = 'goodbye world'; const bool testBool2 = false; const int testInt2 = 1337; @@ -686,4 +694,136 @@ void main() { }); }); }); + + // Migration util tests (ported from shared_preferences_migration_util_test.dart v2.5.5). + // The upstream platform-specific async option variants (Android/iOS/Linux/Windows) all + // collapse to the default SharedPreferencesOptions() on Tizen, so only the + // default-options group is kept. + group('SharedPreferences without setting prefix', () { + runAllGroups(() {}); + }); + + group('SharedPreferences with setPrefix', () { + runAllGroups(() { + SharedPreferences.setPrefix('prefix.'); + }); + }); + + group('SharedPreferences with setPrefix and allowList', () { + runAllGroups(() { + final Set allowList = { + 'prefix.$boolKey', + 'prefix.$intKey', + 'prefix.$doubleKey', + 'prefix.$listKey', + }; + SharedPreferences.setPrefix('prefix.', allowList: allowList); + }, stringValue: null); + }); + + group('SharedPreferences with prefix set to empty string', () { + runAllGroups(() { + SharedPreferences.setPrefix(''); + }, keysCollide: true); + }); +} + +void runAllGroups( + void Function() legacySharedPrefsConfig, { + String? stringValue = testString, + bool keysCollide = false, +}) { + group('default sharedPreferencesAsyncOptions', () { + runTests( + legacySharedPrefsConfig, + stringValue: stringValue, + keysAndNamesCollide: keysCollide, + ); + }); +} + +void runTests( + void Function() legacySharedPrefsConfig, { + String? stringValue = testString, + bool keysAndNamesCollide = false, +}) { + const SharedPreferencesOptions sharedPreferencesAsyncOptions = + SharedPreferencesOptions(); + + setUp(() async { + // Configure and populate the source legacy shared preferences. + SharedPreferences.resetStatic(); + legacySharedPrefsConfig(); + + final SharedPreferences preferences = await SharedPreferences.getInstance(); + await preferences.clear(); + await preferences.setBool(boolKey, testBool); + await preferences.setInt(intKey, testInt); + await preferences.setDouble(doubleKey, testDouble); + await preferences.setString(stringKey, testString); + await preferences.setStringList(listKey, testList); + }); + + tearDown(() async { + await SharedPreferencesAsync().clear(); + }); + + testWidgets('data is successfully transferred to new system', ( + WidgetTester _, + ) async { + final SharedPreferences preferences = await SharedPreferences.getInstance(); + await migrateLegacySharedPreferencesToSharedPreferencesAsyncIfNecessary( + legacySharedPreferencesInstance: preferences, + sharedPreferencesAsyncOptions: sharedPreferencesAsyncOptions, + migrationCompletedKey: migrationCompletedKey, + ); + + final SharedPreferencesAsync asyncPreferences = SharedPreferencesAsync(); + + expect(await asyncPreferences.getBool(boolKey), testBool); + expect(await asyncPreferences.getInt(intKey), testInt); + expect(await asyncPreferences.getDouble(doubleKey), testDouble); + expect(await asyncPreferences.getString(stringKey), stringValue); + expect(await asyncPreferences.getStringList(listKey), testList); + }); + + testWidgets('migrationCompleted key is set', (WidgetTester _) async { + final SharedPreferences preferences = await SharedPreferences.getInstance(); + await migrateLegacySharedPreferencesToSharedPreferencesAsyncIfNecessary( + legacySharedPreferencesInstance: preferences, + sharedPreferencesAsyncOptions: sharedPreferencesAsyncOptions, + migrationCompletedKey: migrationCompletedKey, + ); + + final SharedPreferencesAsync asyncPreferences = SharedPreferencesAsync(); + + expect(await asyncPreferences.getBool(migrationCompletedKey), true); + }); + + testWidgets( + 're-running migration tool does not overwrite data', + (WidgetTester _) async { + final SharedPreferences preferences = + await SharedPreferences.getInstance(); + await migrateLegacySharedPreferencesToSharedPreferencesAsyncIfNecessary( + legacySharedPreferencesInstance: preferences, + sharedPreferencesAsyncOptions: sharedPreferencesAsyncOptions, + migrationCompletedKey: migrationCompletedKey, + ); + + final SharedPreferencesAsync asyncPreferences = SharedPreferencesAsync(); + await preferences.setInt(intKey, -0); + await migrateLegacySharedPreferencesToSharedPreferencesAsyncIfNecessary( + legacySharedPreferencesInstance: preferences, + sharedPreferencesAsyncOptions: sharedPreferencesAsyncOptions, + migrationCompletedKey: migrationCompletedKey, + ); + expect(await asyncPreferences.getInt(intKey), testInt); + }, + // On Tizen the legacy and async stores share a single preference + // namespace, so with an empty prefix their keys collide and this + // scenario cannot be distinguished (matches how upstream skips it on + // other shared-namespace platforms). + skip: keysAndNamesCollide, + ); }