[shared_preferences] Adds new clearWithParameters and getAllWithParameters methods to platform interface. (#4261)

Adds new `clearWithParameters` and `getAllWithParameters` methods.

part of https://github.com/flutter/flutter/issues/128948

precursor to https://github.com/flutter/packages/pull/3794

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [relevant style guides] and ran the
auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages
repo does use `dart format`.)
- [x] I signed the [CLA].
- [x] The title of the PR starts with the name of the package surrounded
by square brackets, e.g. `[shared_preferences]`
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated `pubspec.yaml` with an appropriate new version according
to the [pub versioning philosophy], or this PR is [exempt from version
changes].
- [x] I updated `CHANGELOG.md` to add a description of the change,
[following repository CHANGELOG style].
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[relevant style guides]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md#style
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
[pub versioning philosophy]: https://dart.dev/tools/pub/versioning
[exempt from version changes]:
https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#version-and-changelog-updates
[following repository CHANGELOG style]:
https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changelog-style
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
This commit is contained in:
Tarrin Neal
2023-06-26 18:26:27 -07:00
committed by GitHub
parent 4e71ead104
commit e073e550e0
12 changed files with 349 additions and 33 deletions

View File

@ -182,6 +182,7 @@ class SharedPreferences {
_preferenceCache.clear(); _preferenceCache.clear();
if (_prefixHasBeenChanged) { if (_prefixHasBeenChanged) {
try { try {
// ignore: deprecated_member_use
return _store.clearWithPrefix(_prefix); return _store.clearWithPrefix(_prefix);
} catch (e) { } catch (e) {
// Catching and clarifying UnimplementedError to provide a more robust message. // Catching and clarifying UnimplementedError to provide a more robust message.
@ -213,6 +214,7 @@ Either update the implementation to support setPrefix, or do not call setPrefix.
final Map<String, Object> fromSystem = <String, Object>{}; final Map<String, Object> fromSystem = <String, Object>{};
if (_prefixHasBeenChanged) { if (_prefixHasBeenChanged) {
try { try {
// ignore: deprecated_member_use
fromSystem.addAll(await _store.getAllWithPrefix(_prefix)); fromSystem.addAll(await _store.getAllWithPrefix(_prefix));
} catch (e) { } catch (e) {
// Catching and clarifying UnimplementedError to provide a more robust message. // Catching and clarifying UnimplementedError to provide a more robust message.

View File

@ -335,6 +335,7 @@ class FakeSharedPreferencesStore extends SharedPreferencesStorePlatform {
@override @override
Future<Map<String, Object>> getAllWithPrefix(String prefix) { Future<Map<String, Object>> getAllWithPrefix(String prefix) {
log.add(const MethodCall('getAllWithPrefix')); log.add(const MethodCall('getAllWithPrefix'));
// ignore: deprecated_member_use
return backend.getAllWithPrefix(prefix); return backend.getAllWithPrefix(prefix);
} }

View File

@ -48,10 +48,12 @@ void main() {
}); });
tearDown(() { tearDown(() {
// ignore: deprecated_member_use
preferences.clearWithPrefix(''); preferences.clearWithPrefix('');
}); });
testWidgets('reading', (WidgetTester _) async { testWidgets('reading', (WidgetTester _) async {
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], isNull); expect(values['String'], isNull);
expect(values['Bool'], isNull); expect(values['Bool'], isNull);
@ -83,6 +85,7 @@ void main() {
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
final Map<String, Object> values = final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.'); await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']); expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']); expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
@ -113,14 +116,17 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.'); await preferences.clearWithPrefix('prefix.');
Map<String, Object> values = Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.'); await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null); expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null); expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null); expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null); expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null); expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.'); values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']); expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']); expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
@ -148,6 +154,7 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']); expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']); expect(values['Bool'], allTestValues['Bool']);
@ -180,7 +187,9 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix(''); await preferences.clearWithPrefix('');
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], null); expect(values['String'], null);
expect(values['Bool'], null); expect(values['Bool'], null);
@ -226,6 +235,7 @@ void main() {
await preferences.setValue( await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!); 'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key); await preferences.remove(key);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values[key], isNull); expect(values[key], isNull);
}); });
@ -260,6 +270,7 @@ void main() {
// All writes should succeed. // All writes should succeed.
expect(result.where((bool element) => !element), isEmpty); expect(result.where((bool element) => !element), isEmpty);
// The last write should win. // The last write should win.
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['Int'], writeCount); expect(values['Int'], writeCount);
}); });
@ -268,6 +279,7 @@ void main() {
(WidgetTester _) async { (WidgetTester _) async {
const String key = 'akey'; const String key = 'akey';
const String value = 'a string value'; const String value = 'a string value';
// ignore: deprecated_member_use
await preferences.clearWithPrefix(''); await preferences.clearWithPrefix('');
// Special prefixes used to store datatypes that can't be stored directly // Special prefixes used to store datatypes that can't be stored directly
@ -284,6 +296,7 @@ void main() {
expect(preferences.setValue('String', key, prefix + value), expect(preferences.setValue('String', key, prefix + value),
throwsA(isA<PlatformException>())); throwsA(isA<PlatformException>()));
final Map<String, Object> values = final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix(''); await preferences.getAllWithPrefix('');
expect(values[key], null); expect(values[key], null);
} }

View File

@ -47,10 +47,12 @@ void main() {
}); });
tearDown(() { tearDown(() {
// ignore: deprecated_member_use
preferences.clearWithPrefix(''); preferences.clearWithPrefix('');
}); });
testWidgets('reading', (WidgetTester _) async { testWidgets('reading', (WidgetTester _) async {
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], isNull); expect(values['String'], isNull);
expect(values['Bool'], isNull); expect(values['Bool'], isNull);
@ -82,6 +84,7 @@ void main() {
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
final Map<String, Object> values = final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.'); await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']); expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']); expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
@ -112,14 +115,17 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.'); await preferences.clearWithPrefix('prefix.');
Map<String, Object> values = Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.'); await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null); expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null); expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null); expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null); expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null); expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.'); values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']); expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']); expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
@ -147,6 +153,7 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']); expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']); expect(values['Bool'], allTestValues['Bool']);
@ -179,7 +186,9 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix(''); await preferences.clearWithPrefix('');
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], null); expect(values['String'], null);
expect(values['Bool'], null); expect(values['Bool'], null);
@ -225,6 +234,7 @@ void main() {
await preferences.setValue( await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!); 'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key); await preferences.remove(key);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values[key], isNull); expect(values[key], isNull);
}); });
@ -259,6 +269,7 @@ void main() {
// All writes should succeed. // All writes should succeed.
expect(result.where((bool element) => !element), isEmpty); expect(result.where((bool element) => !element), isEmpty);
// The last write should win. // The last write should win.
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['Int'], writeCount); expect(values['Int'], writeCount);
}); });

View File

@ -1,5 +1,7 @@
## NEXT ## 2.3.0
* Adds `clearWithParameters` and `getAllWithParameters` methods.
* Deprecates `clearWithPrefix` and `getAllWithPrefix` methods.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
## 2.2.0 ## 2.2.0

View File

@ -7,6 +7,7 @@ import 'dart:async';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'shared_preferences_platform_interface.dart'; import 'shared_preferences_platform_interface.dart';
import 'types.dart';
const MethodChannel _kChannel = const MethodChannel _kChannel =
MethodChannel('plugins.flutter.io/shared_preferences'); MethodChannel('plugins.flutter.io/shared_preferences');
@ -39,20 +40,25 @@ class MethodChannelSharedPreferencesStore
} }
@override @override
@Deprecated('Use clearWithParameters instead')
Future<bool> clearWithPrefix(String prefix) async { Future<bool> clearWithPrefix(String prefix) async {
return (await _kChannel.invokeMethod<bool>( return clearWithParameters(
'clearWithPrefix', ClearParameters(
<String, dynamic>{'prefix': prefix}, filter: PreferencesFilter(prefix: prefix),
))!; ),
);
} }
@override @override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async { Future<bool> clearWithParameters(ClearParameters parameters) async {
return await _kChannel.invokeMapMethod<String, Object>( final PreferencesFilter filter = parameters.filter;
'getAllWithPrefix', return (await _kChannel.invokeMethod<bool>(
<String, dynamic>{'prefix': prefix}, 'clearWithParameters',
) ?? <String, dynamic>{
<String, Object>{}; 'prefix': filter.prefix,
'allowList': filter.allowList?.toList(),
},
))!;
} }
@override @override
@ -60,4 +66,32 @@ class MethodChannelSharedPreferencesStore
return await _kChannel.invokeMapMethod<String, Object>('getAll') ?? return await _kChannel.invokeMapMethod<String, Object>('getAll') ??
<String, Object>{}; <String, Object>{};
} }
@override
@Deprecated('Use getAllWithParameters instead')
Future<Map<String, Object>> getAllWithPrefix(
String prefix, {
Set<String>? allowList,
}) async {
return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: prefix),
),
);
}
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final List<String>? allowListAsList = filter.allowList?.toList();
return await _kChannel.invokeMapMethod<String, Object>(
'getAllWithParameters',
<String, dynamic>{
'prefix': filter.prefix,
'allowList': allowListAsList
},
) ??
<String, Object>{};
}
} }

View File

@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'method_channel_shared_preferences.dart'; import 'method_channel_shared_preferences.dart';
import 'types.dart';
/// The interface that implementations of shared_preferences must implement. /// The interface that implementations of shared_preferences must implement.
/// ///
@ -69,11 +70,17 @@ abstract class SharedPreferencesStorePlatform extends PlatformInterface {
/// prefix 'flutter.'. /// prefix 'flutter.'.
Future<bool> clear(); Future<bool> clear();
/// Removes all keys and values in the store with given prefix. /// Removes all keys and values in the store with given [prefix].
@Deprecated('Use clearWithParameters instead')
Future<bool> clearWithPrefix(String prefix) { Future<bool> clearWithPrefix(String prefix) {
throw UnimplementedError('clearWithPrefix is not implemented.'); throw UnimplementedError('clearWithPrefix is not implemented.');
} }
/// Removes all keys and values in the store that match [options].
Future<bool> clearWithParameters(ClearParameters parameters) {
throw UnimplementedError('clearWithParameters is not implemented.');
}
/// Returns all key/value pairs persisted in this store where the key starts with 'flutter.'. /// Returns all key/value pairs persisted in this store where the key starts with 'flutter.'.
/// ///
/// This default behavior is for backwards compatibility with older versions of this /// This default behavior is for backwards compatibility with older versions of this
@ -82,9 +89,16 @@ abstract class SharedPreferencesStorePlatform extends PlatformInterface {
Future<Map<String, Object>> getAll(); Future<Map<String, Object>> getAll();
/// Returns all key/value pairs persisting in this store that have given [prefix]. /// Returns all key/value pairs persisting in this store that have given [prefix].
@Deprecated('Use getAllWithParameters instead')
Future<Map<String, Object>> getAllWithPrefix(String prefix) { Future<Map<String, Object>> getAllWithPrefix(String prefix) {
throw UnimplementedError('getAllWithPrefix is not implemented.'); throw UnimplementedError('getAllWithPrefix is not implemented.');
} }
/// Returns all key/value pairs persisting in this store that match [options].
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) {
throw UnimplementedError('getAllWithParameters is not implemented.');
}
} }
/// Stores data in memory. /// Stores data in memory.
@ -103,24 +117,60 @@ class InMemorySharedPreferencesStore extends SharedPreferencesStorePlatform {
@override @override
Future<bool> clear() async { Future<bool> clear() async {
return clearWithPrefix(_defaultPrefix); return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<bool> clearWithPrefix(String prefix) async { Future<bool> clearWithPrefix(String prefix) async {
_data.removeWhere((String key, _) => key.startsWith(prefix)); return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: prefix),
),
);
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
if (filter.allowList != null) {
_data.removeWhere((String key, _) =>
key.startsWith(filter.prefix) && filter.allowList!.contains(key));
} else {
_data.removeWhere((String key, _) => key.startsWith(filter.prefix));
}
return true; return true;
} }
@override @override
Future<Map<String, Object>> getAll() async { Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defaultPrefix); return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async { Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: prefix),
),
);
}
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String, Object> preferences = Map<String, Object>.from(_data); final Map<String, Object> preferences = Map<String, Object>.from(_data);
preferences.removeWhere((String key, _) => !key.startsWith(prefix)); preferences.removeWhere((String key, _) =>
!key.startsWith(filter.prefix) ||
(filter.allowList != null && !filter.allowList!.contains(key)));
return preferences; return preferences;
} }

View File

@ -0,0 +1,38 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// Filter options used to get and clear preferences.
class PreferencesFilter {
/// Constructor.
PreferencesFilter({
required this.prefix,
this.allowList,
});
/// A prefix to limit getting and clearing to only items that begin with
/// this string.
String prefix;
/// A list of preference keys that will limit getting and clearing to only
/// items included in this list.
Set<String>? allowList;
}
/// Parameters for use in [getAll] methods.
class GetAllParameters {
/// Constructor.
GetAllParameters({required this.filter});
/// Filter to limit which preferences are returned.
PreferencesFilter filter;
}
/// Parameters for use in [clear] methods.
class ClearParameters {
/// Constructor.
ClearParameters({required this.filter});
/// Filter to limit which preferences are cleared.
PreferencesFilter filter;
}

View File

@ -2,7 +2,7 @@ name: shared_preferences_platform_interface
description: A common platform interface for the shared_preferences plugin. description: A common platform interface for the shared_preferences plugin.
repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_platform_interface repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_platform_interface
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
version: 2.2.0 version: 2.3.0
environment: environment:
sdk: ">=2.18.0 <4.0.0" sdk: ">=2.18.0 <4.0.0"

View File

@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart'; import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
@ -65,11 +66,27 @@ void main() {
if (methodCall.method == 'getAll') { if (methodCall.method == 'getAll') {
return testData.getAll(); return testData.getAll();
} }
if (methodCall.method == 'getAllWithPrefix') { if (methodCall.method == 'getAllWithParameters') {
final Map<String, Object?> arguments = final Map<String, Object?> arguments =
getArgumentDictionary(methodCall); getArgumentDictionary(methodCall);
final String prefix = arguments['prefix']! as String; final String prefix = arguments['prefix']! as String;
return testData.getAllWithPrefix(prefix); Set<String>? allowSet;
final List<dynamic>? allowList =
arguments['allowList'] as List<dynamic>?;
if (allowList != null) {
allowSet = <String>{};
for (final dynamic key in allowList) {
allowSet.add(key as String);
}
}
return testData.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: prefix,
allowList: allowSet,
),
),
);
} }
if (methodCall.method == 'remove') { if (methodCall.method == 'remove') {
final Map<String, Object?> arguments = final Map<String, Object?> arguments =
@ -80,11 +97,24 @@ void main() {
if (methodCall.method == 'clear') { if (methodCall.method == 'clear') {
return testData.clear(); return testData.clear();
} }
if (methodCall.method == 'clearWithPrefix') { if (methodCall.method == 'clearWithParameters') {
final Map<String, Object?> arguments = final Map<String, Object?> arguments =
getArgumentDictionary(methodCall); getArgumentDictionary(methodCall);
final String prefix = arguments['prefix']! as String; final String prefix = arguments['prefix']! as String;
return testData.clearWithPrefix(prefix); Set<String>? allowSet;
final List<dynamic>? allowList =
arguments['allowList'] as List<dynamic>?;
if (allowList != null) {
allowSet = <String>{};
for (final dynamic key in allowList) {
allowSet.add(key as String);
}
}
return testData.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: prefix, allowList: allowSet),
),
);
} }
final RegExp setterRegExp = RegExp(r'set(.*)'); final RegExp setterRegExp = RegExp(r'set(.*)');
final Match? match = setterRegExp.matchAsPrefix(methodCall.method); final Match? match = setterRegExp.matchAsPrefix(methodCall.method);
@ -112,10 +142,31 @@ void main() {
expect(log.single.method, 'getAll'); expect(log.single.method, 'getAll');
}); });
test('getAllWithPrefix', () async { test('getAllWithParameters with Prefix', () async {
testData = InMemorySharedPreferencesStore.withData(allTestValues); testData = InMemorySharedPreferencesStore.withData(allTestValues);
expect(await store.getAllWithPrefix('prefix.'), prefixTestValues); expect(
expect(log.single.method, 'getAllWithPrefix'); await store.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
),
prefixTestValues);
expect(log.single.method, 'getAllWithParameters');
});
test('getAllWithParameters with allow list', () async {
testData = InMemorySharedPreferencesStore.withData(allTestValues);
final Map<String, Object> data = await store.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(data.length, 1);
expect(data['prefix.Bool'], true);
expect(log.single.method, 'getAllWithParameters');
}); });
test('remove', () async { test('remove', () async {
@ -158,26 +209,95 @@ void main() {
expect(log.single.method, 'clear'); expect(log.single.method, 'clear');
}); });
test('clearWithPrefix', () async { test('clearWithParameters with Prefix', () async {
testData = InMemorySharedPreferencesStore.withData(allTestValues); testData = InMemorySharedPreferencesStore.withData(allTestValues);
expect(await testData.getAllWithPrefix('prefix.'), isNotEmpty); expect(
expect(await store.clearWithPrefix('prefix.'), true); await testData.getAllWithParameters(
expect(await testData.getAllWithPrefix('prefix.'), isEmpty); GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
),
isNotEmpty);
expect(
await store.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
),
true);
expect(
await testData.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
),
isEmpty);
}); });
test('getAllWithNoPrefix', () async { test('getAllWithParameters with no Prefix', () async {
testData = InMemorySharedPreferencesStore.withData(allTestValues); testData = InMemorySharedPreferencesStore.withData(allTestValues);
expect(await testData.getAllWithPrefix(''), hasLength(15)); expect(
await testData.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
),
hasLength(15));
}); });
test('clearWithNoPrefix', () async { test('clearWithNoPrefix', () async {
testData = InMemorySharedPreferencesStore.withData(allTestValues); testData = InMemorySharedPreferencesStore.withData(allTestValues);
expect(await testData.getAllWithPrefix(''), isNotEmpty); expect(
expect(await store.clearWithPrefix(''), true); await testData.getAllWithParameters(
expect(await testData.getAllWithPrefix(''), isEmpty); GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
),
isNotEmpty);
expect(
await store.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
),
true);
expect(
await testData.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
),
isEmpty);
});
test('clearWithParameters with allow list', () async {
testData = InMemorySharedPreferencesStore.withData(allTestValues);
expect(
await testData.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
),
isNotEmpty);
expect(
await store.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
),
true);
expect(
(await testData.getAllWithParameters(GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'))))
.length,
4);
}); });
}); });
} }

View File

@ -5,6 +5,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
@ -51,6 +52,11 @@ class IllegalImplementation implements SharedPreferencesStorePlatform {
throw UnimplementedError(); throw UnimplementedError();
} }
@override
Future<bool> clearWithParameters(ClearParameters parameters) {
throw UnimplementedError();
}
@override @override
Future<Map<String, Object>> getAll() { Future<Map<String, Object>> getAll() {
throw UnimplementedError(); throw UnimplementedError();
@ -61,6 +67,12 @@ class IllegalImplementation implements SharedPreferencesStorePlatform {
throw UnimplementedError(); throw UnimplementedError();
} }
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) {
throw UnimplementedError();
}
@override @override
Future<bool> remove(String key) { Future<bool> remove(String key) {
throw UnimplementedError(); throw UnimplementedError();
@ -86,6 +98,11 @@ class LegacyIsMockImplementation implements SharedPreferencesStorePlatform {
throw UnimplementedError(); throw UnimplementedError();
} }
@override
Future<bool> clearWithParameters(ClearParameters parameters) {
throw UnimplementedError();
}
@override @override
Future<Map<String, Object>> getAll() { Future<Map<String, Object>> getAll() {
throw UnimplementedError(); throw UnimplementedError();
@ -96,6 +113,12 @@ class LegacyIsMockImplementation implements SharedPreferencesStorePlatform {
throw UnimplementedError(); throw UnimplementedError();
} }
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) {
throw UnimplementedError();
}
@override @override
Future<bool> remove(String key) { Future<bool> remove(String key) {
throw UnimplementedError(); throw UnimplementedError();
@ -123,6 +146,11 @@ class ModernMockImplementation
throw UnimplementedError(); throw UnimplementedError();
} }
@override
Future<bool> clearWithParameters(ClearParameters parameters) {
throw UnimplementedError();
}
@override @override
Future<Map<String, Object>> getAll() { Future<Map<String, Object>> getAll() {
throw UnimplementedError(); throw UnimplementedError();
@ -133,6 +161,12 @@ class ModernMockImplementation
throw UnimplementedError(); throw UnimplementedError();
} }
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) {
throw UnimplementedError();
}
@override @override
Future<bool> remove(String key) { Future<bool> remove(String key) {
throw UnimplementedError(); throw UnimplementedError();

View File

@ -73,10 +73,12 @@ void main() {
}); });
tearDown(() { tearDown(() {
// ignore: deprecated_member_use
preferences.clearWithPrefix(''); preferences.clearWithPrefix('');
}); });
testWidgets('reading', (WidgetTester _) async { testWidgets('reading', (WidgetTester _) async {
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], isNull); expect(values['String'], isNull);
expect(values['Bool'], isNull); expect(values['Bool'], isNull);
@ -108,6 +110,7 @@ void main() {
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
final Map<String, Object> values = final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.'); await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']); expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']); expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
@ -138,14 +141,17 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.'); await preferences.clearWithPrefix('prefix.');
Map<String, Object> values = Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.'); await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null); expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null); expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null); expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null); expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null); expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.'); values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']); expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']); expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
@ -173,6 +179,7 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']); expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']); expect(values['Bool'], allTestValues['Bool']);
@ -205,7 +212,9 @@ void main() {
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!) allTestValues['flutter.StringList']!)
]); ]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix(''); await preferences.clearWithPrefix('');
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], null); expect(values['String'], null);
expect(values['Bool'], null); expect(values['Bool'], null);
@ -251,6 +260,7 @@ void main() {
await preferences.setValue( await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!); 'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key); await preferences.remove(key);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values[key], isNull); expect(values[key], isNull);
}); });
@ -285,6 +295,7 @@ void main() {
// All writes should succeed. // All writes should succeed.
expect(result.where((bool element) => !element), isEmpty); expect(result.where((bool element) => !element), isEmpty);
// The last write should win. // The last write should win.
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['Int'], writeCount); expect(values['Int'], writeCount);
}); });