[shared_preferences] Adds new clearWithParameters and getAllWithParameters methods to all platforms. (#4262)

Adds new `clearWithParameters` and `getAllWithParameters` methods.

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

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

awaiting https://github.com/flutter/packages/pull/4261

## 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-29 11:05:13 -07:00
committed by GitHub
parent d4752c4069
commit d61537115c
40 changed files with 2436 additions and 783 deletions

View File

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

View File

@ -1,7 +1,7 @@
// 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.
// Autogenerated from Pigeon (v9.2.4), do not edit directly.
// Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon
package io.flutter.plugins.sharedpreferences;
@ -75,10 +75,10 @@ public class Messages {
Boolean setStringList(@NonNull String key, @NonNull List<String> value);
/** Removes all properties from shared preferences data set with matching prefix. */
@NonNull
Boolean clearWithPrefix(@NonNull String prefix);
Boolean clear(@NonNull String prefix, @Nullable List<String> allowList);
/** Gets all properties from shared preferences data set with matching prefix. */
@NonNull
Map<String, Object> getAllWithPrefix(@NonNull String prefix);
Map<String, Object> getAll(@NonNull String prefix, @Nullable List<String> allowList);
/** The codec used by SharedPreferencesApi. */
static @NonNull MessageCodec<Object> getCodec() {
@ -263,7 +263,7 @@ public class Messages {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.SharedPreferencesApi.clearWithPrefix",
"dev.flutter.pigeon.SharedPreferencesApi.clear",
getCodec(),
taskQueue);
if (api != null) {
@ -272,8 +272,9 @@ public class Messages {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
String prefixArg = (String) args.get(0);
List<String> allowListArg = (List<String>) args.get(1);
try {
Boolean output = api.clearWithPrefix(prefixArg);
Boolean output = api.clear(prefixArg, allowListArg);
wrapped.add(0, output);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
@ -290,7 +291,7 @@ public class Messages {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.SharedPreferencesApi.getAllWithPrefix",
"dev.flutter.pigeon.SharedPreferencesApi.getAll",
getCodec(),
taskQueue);
if (api != null) {
@ -299,8 +300,9 @@ public class Messages {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
String prefixArg = (String) args.get(0);
List<String> allowListArg = (List<String>) args.get(1);
try {
Map<String, Object> output = api.getAllWithPrefix(prefixArg);
Map<String, Object> output = api.getAll(prefixArg, allowListArg);
wrapped.add(0, output);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);

View File

@ -9,6 +9,7 @@ import android.content.SharedPreferences;
import android.util.Base64;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
@ -21,6 +22,7 @@ import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -111,18 +113,20 @@ public class SharedPreferencesPlugin implements FlutterPlugin, SharedPreferences
}
@Override
public @NonNull Map<String, Object> getAllWithPrefix(@NonNull String prefix)
throws RuntimeException {
return getAllPrefs(prefix);
public @NonNull Map<String, Object> getAll(
@NonNull String prefix, @Nullable List<String> allowList) throws RuntimeException {
final Set<String> allowSet = allowList == null ? null : new HashSet<>(allowList);
return getAllPrefs(prefix, allowSet);
}
@Override
public @NonNull Boolean clearWithPrefix(@NonNull String prefix) throws RuntimeException {
public @NonNull Boolean clear(@NonNull String prefix, @Nullable List<String> allowList)
throws RuntimeException {
SharedPreferences.Editor clearEditor = preferences.edit();
Map<String, ?> allPrefs = preferences.getAll();
ArrayList<String> filteredPrefs = new ArrayList<>();
for (String key : allPrefs.keySet()) {
if (key.startsWith(prefix)) {
if (key.startsWith(prefix) && (allowList == null || allowList.contains(key))) {
filteredPrefs.add(key);
}
}
@ -133,12 +137,14 @@ public class SharedPreferencesPlugin implements FlutterPlugin, SharedPreferences
}
// Gets all shared preferences, filtered to only those set with the given prefix.
// Optionally filtered also to only those items in the optional [allowList].
@SuppressWarnings("unchecked")
private @NonNull Map<String, Object> getAllPrefs(@NonNull String prefix) throws RuntimeException {
private @NonNull Map<String, Object> getAllPrefs(
@NonNull String prefix, @Nullable Set<String> allowList) throws RuntimeException {
Map<String, ?> allPrefs = preferences.getAll();
Map<String, Object> filteredPrefs = new HashMap<>();
for (String key : allPrefs.keySet()) {
if (key.startsWith(prefix)) {
if (key.startsWith(prefix) && (allowList == null || allowList.contains(key))) {
filteredPrefs.put(key, transformPref(key, allPrefs.get(key)));
}
}

View File

@ -67,12 +67,12 @@ public class SharedPreferencesTest {
}
@Test
public void getAllWithPrefix() {
assertEquals(plugin.getAllWithPrefix("").size(), 0);
public void getAll() {
assertEquals(plugin.getAll("", null).size(), 0);
addData();
Map<String, Object> flutterData = plugin.getAllWithPrefix("flutter.");
Map<String, Object> flutterData = plugin.getAll("flutter.", null);
assertEquals(flutterData.size(), 5);
assertEquals(flutterData.get("flutter.Language"), "Java");
@ -81,17 +81,43 @@ public class SharedPreferencesTest {
assertEquals(flutterData.get("flutter.Names"), Arrays.asList("Flutter", "Dart"));
assertEquals(flutterData.get("flutter.NewToFlutter"), false);
Map<String, Object> allData = plugin.getAllWithPrefix("");
Map<String, Object> allData = plugin.getAll("", null);
assertEquals(allData, data);
}
@Test
public void allowList() {
assertEquals(plugin.getAll("", null).size(), 0);
addData();
final List<String> allowList = Arrays.asList("flutter.Language");
Map<String, Object> allData = plugin.getAll("flutter.", allowList);
assertEquals(allData.size(), 1);
assertEquals(allData.get("flutter.Language"), "Java");
assertEquals(allData.get("flutter.Counter"), null);
allData = plugin.getAll("", allowList);
assertEquals(allData.size(), 1);
assertEquals(allData.get("flutter.Language"), "Java");
assertEquals(allData.get("flutter.Counter"), null);
allData = plugin.getAll("prefix.", allowList);
assertEquals(allData.size(), 0);
assertEquals(allData.get("flutter.Language"), null);
}
@Test
public void setString() {
final String key = "language";
final String value = "Java";
plugin.setString(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix("");
Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value);
}
@ -100,7 +126,7 @@ public class SharedPreferencesTest {
final String key = "Counter";
final Long value = 0L;
plugin.setInt(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix("");
Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value);
}
@ -109,7 +135,7 @@ public class SharedPreferencesTest {
final String key = "Pie";
final double value = 3.14;
plugin.setDouble(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix("");
Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value);
}
@ -118,7 +144,7 @@ public class SharedPreferencesTest {
final String key = "Names";
final List<String> value = Arrays.asList("Flutter", "Dart");
plugin.setStringList(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix("");
Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value);
}
@ -127,30 +153,41 @@ public class SharedPreferencesTest {
final String key = "NewToFlutter";
final boolean value = false;
plugin.setBool(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix("");
Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value);
}
@Test
public void clearWithPrefix() {
public void clearWithNoAllowList() {
addData();
assertEquals(plugin.getAllWithPrefix("").size(), 15);
assertEquals(plugin.getAll("", null).size(), 15);
plugin.clearWithPrefix("flutter.");
plugin.clear("flutter.", null);
assertEquals(plugin.getAllWithPrefix("").size(), 10);
assertEquals(plugin.getAll("", null).size(), 10);
}
@Test
public void clearWithAllowList() {
addData();
assertEquals(plugin.getAll("", null).size(), 15);
plugin.clear("flutter.", Arrays.asList("flutter.Language"));
assertEquals(plugin.getAll("", null).size(), 14);
}
@Test
public void clearAll() {
addData();
assertEquals(plugin.getAllWithPrefix("").size(), 15);
assertEquals(plugin.getAll("", null).size(), 15);
plugin.clearWithPrefix("");
plugin.clear("", null);
assertEquals(plugin.getAllWithPrefix("").size(), 0);
assertEquals(plugin.getAll("", null).size(), 0);
}
@Test
@ -158,9 +195,9 @@ public class SharedPreferencesTest {
final String key = "NewToFlutter";
final boolean value = true;
plugin.setBool(key, value);
assert (plugin.getAllWithPrefix("").containsKey(key));
assert (plugin.getAll("", null).containsKey(key));
plugin.remove(key);
assertFalse(plugin.getAllWithPrefix("").containsKey(key));
assertFalse(plugin.getAll("", null).containsKey(key));
}
private void addData() {

View File

@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@ -47,14 +48,20 @@ void main() {
preferences = SharedPreferencesStorePlatform.instance;
});
tearDown(() {
// ignore: deprecated_member_use
preferences.clearWithPrefix('');
tearDown(() async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
});
testWidgets('reading', (WidgetTester _) async {
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], isNull);
expect(values['Bool'], isNull);
expect(values['Int'], isNull);
@ -62,6 +69,35 @@ void main() {
expect(values['StringList'], isNull);
});
Future<void> addData() async {
await preferences.setValue('String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue('Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
testWidgets('getAllWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
@ -94,68 +130,160 @@ void main() {
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
group('withPrefix', () {
testWidgets('clearWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
testWidgets('get all with prefix', (WidgetTester _) async {
await addData();
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('get all with allow list', (WidgetTester _) async {
await addData();
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
await addData();
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
@ -168,29 +296,84 @@ void main() {
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{
'prefix.Double',
'prefix.Int',
'prefix.Bool',
'prefix.String',
},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
@ -204,18 +387,16 @@ void main() {
});
testWidgets('getAll', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
@ -235,8 +416,11 @@ void main() {
await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull);
});
@ -270,8 +454,11 @@ void main() {
// All writes should succeed.
expect(result.where((bool element) => !element), isEmpty);
// The last write should win.
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['Int'], writeCount);
});
@ -279,8 +466,11 @@ void main() {
(WidgetTester _) async {
const String key = 'akey';
const String value = 'a string value';
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
// Special prefixes used to store datatypes that can't be stored directly
// in SharedPreferences as strings instead.
@ -296,8 +486,11 @@ void main() {
expect(preferences.setValue('String', key, prefix + value),
throwsA(isA<PlatformException>()));
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], null);
}
});

View File

@ -16,7 +16,7 @@ dependencies:
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
shared_preferences_platform_interface: ^2.0.0
shared_preferences_platform_interface: ^2.3.0
dev_dependencies:
flutter_driver:

View File

@ -5,6 +5,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'src/messages.g.dart';
@ -52,23 +53,50 @@ class SharedPreferencesAndroid extends SharedPreferencesStorePlatform {
}
@override
Future<bool> clear() {
return clearWithPrefix(_defaultPrefix);
Future<bool> clear() async {
return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
Future<bool> clearWithPrefix(String prefix) async {
return _api.clearWithPrefix(prefix);
return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<Map<String, Object>> getAll() {
return getAllWithPrefix(_defaultPrefix);
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
return _api.clear(
filter.prefix,
filter.allowList?.toList(),
);
}
@override
Future<Map<String, Object>> getAll() async {
return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
final Map<String?, Object?> data = await _api.getAllWithPrefix(prefix);
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?> data =
await _api.getAll(filter.prefix, filter.allowList?.toList());
return data.cast<String, Object>();
}
}

View File

@ -1,7 +1,7 @@
// 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.
// Autogenerated from Pigeon (v9.2.4), do not edit directly.
// Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
@ -190,12 +190,12 @@ class SharedPreferencesApi {
}
/// Removes all properties from shared preferences data set with matching prefix.
Future<bool> clearWithPrefix(String arg_prefix) async {
Future<bool> clear(String arg_prefix, List<String?>? arg_allowList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.SharedPreferencesApi.clearWithPrefix', codec,
'dev.flutter.pigeon.SharedPreferencesApi.clear', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_prefix]) as List<Object?>?;
final List<Object?>? replyList = await channel
.send(<Object?>[arg_prefix, arg_allowList]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@ -218,12 +218,13 @@ class SharedPreferencesApi {
}
/// Gets all properties from shared preferences data set with matching prefix.
Future<Map<String?, Object?>> getAllWithPrefix(String arg_prefix) async {
Future<Map<String?, Object?>> getAll(
String arg_prefix, List<String?>? arg_allowList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.SharedPreferencesApi.getAllWithPrefix', codec,
'dev.flutter.pigeon.SharedPreferencesApi.getAll', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_prefix]) as List<Object?>?;
final List<Object?>? replyList = await channel
.send(<Object?>[arg_prefix, arg_allowList]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',

View File

@ -41,9 +41,15 @@ abstract class SharedPreferencesApi {
/// Removes all properties from shared preferences data set with matching prefix.
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
bool clearWithPrefix(String prefix);
bool clear(
String prefix,
List<String>? allowList,
);
/// Gets all properties from shared preferences data set with matching prefix.
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
Map<String, Object> getAllWithPrefix(String prefix);
Map<String, Object> getAll(
String prefix,
List<String>? allowList,
);
}

View File

@ -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.1.4
version: 2.2.0
environment:
sdk: ">=2.18.0 <4.0.0"
@ -20,7 +20,7 @@ flutter:
dependencies:
flutter:
sdk: flutter
shared_preferences_platform_interface: ^2.2.0
shared_preferences_platform_interface: ^2.3.0
dev_dependencies:
flutter_test:

View File

@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences_android/shared_preferences_android.dart';
import 'package:shared_preferences_android/src/messages.g.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@ -80,6 +81,61 @@ void main() {
expect(all.length, 0);
});
test('clearWithParameters', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
all = await plugin.getAll();
expect(all.length, 5);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 0);
});
test('clearWithParameters with allow list', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
all = await plugin.getAll();
expect(all.length, 5);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 4);
});
test('getAll', () async {
for (final String key in flutterTestValues.keys) {
api.items[key] = flutterTestValues[key]!;
@ -89,15 +145,56 @@ void main() {
expect(all, flutterTestValues);
});
test('getAllWithPrefix', () async {
test('getAllWithNoPrefix', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithPrefix('prefix.');
final Map<String?, Object?> all = await plugin.getAllWithPrefix('');
expect(all.length, 15);
expect(all, allTestValues);
});
test('clearWithNoPrefix', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithPrefix('');
expect(all.length, 15);
await plugin.clearWithPrefix('');
all = await plugin.getAllWithPrefix('');
expect(all.length, 0);
});
test('getAllWithParameters', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
expect(all, prefixTestValues);
});
test('getAllWithParameters with allow list', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(all.length, 1);
expect(all['prefix.Bool'], true);
});
test('setValue', () async {
expect(await plugin.setValue('Bool', 'flutter.Bool', true), isTrue);
expect(api.items['flutter.Bool'], true);
@ -124,7 +221,11 @@ void main() {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithPrefix('');
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 15);
expect(all, allTestValues);
});
@ -134,10 +235,22 @@ void main() {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithPrefix('');
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 15);
await plugin.clearWithPrefix('');
all = await plugin.getAllWithPrefix('');
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 0);
});
}
@ -146,10 +259,19 @@ class _FakeSharedPreferencesApi implements SharedPreferencesApi {
final Map<String, Object> items = <String, Object>{};
@override
Future<Map<String?, Object?>> getAllWithPrefix(String prefix) async {
Future<Map<String?, Object?>> getAll(
String prefix,
List<String?>? allowList,
) async {
Set<String?>? allowSet;
if (allowList != null) {
allowSet = Set<String>.from(allowList);
}
return <String?, Object?>{
for (final String key in items.keys)
if (key.startsWith(prefix)) key: items[key]
if (key.startsWith(prefix) &&
(allowSet == null || allowSet.contains(key)))
key: items[key]
};
}
@ -172,9 +294,10 @@ class _FakeSharedPreferencesApi implements SharedPreferencesApi {
}
@override
Future<bool> clearWithPrefix(String prefix) async {
Future<bool> clear(String prefix, List<String?>? allowList) async {
items.keys.toList().forEach((String key) {
if (key.startsWith(prefix)) {
if (key.startsWith(prefix) &&
(allowList == null || allowList.contains(key))) {
items.remove(key);
}
});

View File

@ -1,5 +1,6 @@
## NEXT
## 2.3.0
* Adds `clearWithParameters` and `getAllWithParameters` methods.
* Updates minimum supported macOS version to 10.14.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.

View File

@ -22,8 +22,8 @@ public class SharedPreferencesPlugin: NSObject, FlutterPlugin, UserDefaultsApi {
UserDefaultsApiSetup.setUp(binaryMessenger: messenger, api: instance)
}
func getAllWithPrefix(prefix: String) -> [String? : Any?] {
return getAllPrefs(prefix: prefix)
func getAll(prefix: String, allowList: [String]?) -> [String? : Any?] {
return getAllPrefs(prefix: prefix, allowList: allowList)
}
func setBool(key: String, value: Bool) {
@ -42,20 +42,26 @@ public class SharedPreferencesPlugin: NSObject, FlutterPlugin, UserDefaultsApi {
UserDefaults.standard.removeObject(forKey: key)
}
func clearWithPrefix(prefix: String) {
func clear(prefix: String, allowList: [String]?) -> Bool {
let defaults = UserDefaults.standard
for (key, _) in getAllPrefs(prefix: prefix) {
for (key, _) in getAllPrefs(prefix: prefix, allowList: allowList) {
defaults.removeObject(forKey: key)
}
return true
}
/// Returns all preferences stored with specified prefix.
func getAllPrefs(prefix: String) -> [String: Any] {
/// If [allowList] is included, only items included will be returned.
func getAllPrefs(prefix: String, allowList: [String]?) -> [String: Any] {
var filteredPrefs: [String: Any] = [:]
var allowSet: Set<String>?;
if let allowList {
allowSet = Set(allowList)
}
if let appDomain = Bundle.main.bundleIdentifier,
let prefs = UserDefaults.standard.persistentDomain(forName: appDomain)
{
for (key, value) in prefs where key.hasPrefix(prefix) {
for (key, value) in prefs where (key.hasPrefix(prefix) && (allowSet == nil || allowSet!.contains(key))) {
filteredPrefs[key] = value
}
}

View File

@ -1,7 +1,7 @@
// 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.
// Autogenerated from Pigeon (v9.2.4), do not edit directly.
// Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@ -42,8 +42,8 @@ protocol UserDefaultsApi {
func setBool(key: String, value: Bool) throws
func setDouble(key: String, value: Double) throws
func setValue(key: String, value: Any) throws
func getAllWithPrefix(prefix: String) throws -> [String?: Any?]
func clearWithPrefix(prefix: String) throws
func getAll(prefix: String, allowList: [String]?) throws -> [String?: Any?]
func clear(prefix: String, allowList: [String]?) throws -> Bool
}
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@ -114,35 +114,37 @@ class UserDefaultsApiSetup {
} else {
setValueChannel.setMessageHandler(nil)
}
let getAllWithPrefixChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix", binaryMessenger: binaryMessenger)
let getAllChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.getAll", binaryMessenger: binaryMessenger)
if let api = api {
getAllWithPrefixChannel.setMessageHandler { message, reply in
getAllChannel.setMessageHandler { message, reply in
let args = message as! [Any]
let prefixArg = args[0] as! String
let allowListArg: [String]? = nilOrValue(args[1])
do {
let result = try api.getAllWithPrefix(prefix: prefixArg)
let result = try api.getAll(prefix: prefixArg, allowList: allowListArg)
reply(wrapResult(result))
} catch {
reply(wrapError(error))
}
}
} else {
getAllWithPrefixChannel.setMessageHandler(nil)
getAllChannel.setMessageHandler(nil)
}
let clearWithPrefixChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix", binaryMessenger: binaryMessenger)
let clearChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.clear", binaryMessenger: binaryMessenger)
if let api = api {
clearWithPrefixChannel.setMessageHandler { message, reply in
clearChannel.setMessageHandler { message, reply in
let args = message as! [Any]
let prefixArg = args[0] as! String
let allowListArg: [String]? = nilOrValue(args[1])
do {
try api.clearWithPrefix(prefix: prefixArg)
reply(wrapResult(nil))
let result = try api.clear(prefix: prefixArg, allowList: allowListArg)
reply(wrapResult(result))
} catch {
reply(wrapError(error))
}
}
} else {
clearWithPrefixChannel.setMessageHandler(nil)
clearChannel.setMessageHandler(nil)
}
}
}

View File

@ -25,7 +25,7 @@ class RunnerTests: XCTestCase {
plugin.setValue(key: "\(aPrefix)aString", value: "hello world")
plugin.setValue(key: "\(aPrefix)aStringList", value: ["hello", "world"])
let storedValues = plugin.getAllWithPrefix(prefix: aPrefix)
let storedValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(storedValues["\(aPrefix)aBool"] as? Bool, true)
XCTAssertEqual(storedValues["\(aPrefix)aDouble"] as! Double, 3.14, accuracy: 0.0001)
XCTAssertEqual(storedValues["\(aPrefix)anInt"] as? Int, 42)
@ -34,6 +34,25 @@ class RunnerTests: XCTestCase {
}
}
func testGetWithAllowList() throws {
for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin()
plugin.setBool(key: "\(aPrefix)aBool", value: true)
plugin.setDouble(key: "\(aPrefix)aDouble", value: 3.14)
plugin.setValue(key: "\(aPrefix)anInt", value: 42)
plugin.setValue(key: "\(aPrefix)aString", value: "hello world")
plugin.setValue(key: "\(aPrefix)aStringList", value: ["hello", "world"])
let storedValues = plugin.getAll(prefix: aPrefix, allowList: ["\(aPrefix)aBool"])
XCTAssertEqual(storedValues["\(aPrefix)aBool"] as? Bool, true)
XCTAssertNil(storedValues["\(aPrefix)aDouble"] ?? nil)
XCTAssertNil(storedValues["\(aPrefix)anInt"] ?? nil)
XCTAssertNil(storedValues["\(aPrefix)aString"] ?? nil)
XCTAssertNil(storedValues["\(aPrefix)aStringList"] ?? nil)
}
}
func testRemove() throws {
for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin()
@ -41,33 +60,50 @@ class RunnerTests: XCTestCase {
plugin.setValue(key: testKey, value: 42)
// Make sure there is something to remove, so the test can't pass due to a set failure.
let preRemovalValues = plugin.getAllWithPrefix(prefix: aPrefix)
let preRemovalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
// Then verify that removing it works.
plugin.remove(key: testKey)
let finalValues = plugin.getAllWithPrefix(prefix: aPrefix)
let finalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertNil(finalValues[testKey] as Any?)
}
}
func testClearWithNoAllowlist() throws {
for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin()
let testKey = "\(aPrefix)foo"
plugin.setValue(key: testKey, value: 42)
func testClear() throws {
for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin()
let testKey = "\(aPrefix)foo"
plugin.setValue(key: testKey, value: 42)
// Make sure there is something to clear, so the test can't pass due to a set failure.
let preRemovalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
// Make sure there is something to clear, so the test can't pass due to a set failure.
let preRemovalValues = plugin.getAllWithPrefix(prefix: aPrefix)
XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
// Then verify that clearing works.
plugin.clear(prefix: aPrefix, allowList: nil)
// Then verify that clearing works.
plugin.clearWithPrefix(prefix: aPrefix)
let finalValues = plugin.getAllWithPrefix(prefix: aPrefix)
XCTAssertNil(finalValues[testKey] as Any?)
let finalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertNil(finalValues[testKey] as Any?)
}
}
func testClearWithAllowlist() throws {
for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin()
let testKey = "\(aPrefix)foo"
plugin.setValue(key: testKey, value: 42)
// Make sure there is something to clear, so the test can't pass due to a set failure.
let preRemovalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
plugin.clear(prefix: aPrefix, allowList: ["\(aPrefix)notfoo"])
let finalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(finalValues[testKey] as? Int, 42)
}
}
}
}

View File

@ -5,6 +5,7 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@ -46,175 +47,375 @@ void main() {
preferences = SharedPreferencesStorePlatform.instance;
});
tearDown(() {
// ignore: deprecated_member_use
preferences.clearWithPrefix('');
tearDown(() async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
});
testWidgets('reading', (WidgetTester _) async {
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], isNull);
expect(values['Bool'], isNull);
expect(values['Int'], isNull);
expect(values['Double'], isNull);
expect(values['StringList'], isNull);
group('withPrefix', () {
testWidgets('reading', (WidgetTester _) async {
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], isNull);
expect(values['Bool'], isNull);
expect(values['Int'], isNull);
expect(values['Double'], isNull);
expect(values['StringList'], isNull);
});
testWidgets('getAllWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
testWidgets('getAllWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
group('withParameters', () {
testWidgets('reading', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], isNull);
expect(values['Bool'], isNull);
expect(values['Int'], isNull);
expect(values['Double'], isNull);
expect(values['StringList'], isNull);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
Future<void> addData() async {
await preferences.setValue(
'String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue(
'Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('get all with prefix', (WidgetTester _) async {
await addData();
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
testWidgets('get all with allow list', (WidgetTester _) async {
await addData();
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await addData();
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list',
(WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
testWidgets('getAll', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
@ -234,8 +435,11 @@ void main() {
await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull);
});
@ -269,8 +473,11 @@ void main() {
// All writes should succeed.
expect(result.where((bool element) => !element), isEmpty);
// The last write should win.
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['Int'], writeCount);
});
});

View File

@ -16,7 +16,7 @@ dependencies:
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
shared_preferences_platform_interface: ^2.0.0
shared_preferences_platform_interface: ^2.3.0
dev_dependencies:
flutter_driver:

View File

@ -1,7 +1,7 @@
// 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.
// Autogenerated from Pigeon (v9.2.4), do not edit directly.
// Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
@ -109,12 +109,13 @@ class UserDefaultsApi {
}
}
Future<Map<String?, Object?>> getAllWithPrefix(String arg_prefix) async {
Future<Map<String?, Object?>> getAll(
String arg_prefix, List<String?>? arg_allowList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix', codec,
'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_prefix]) as List<Object?>?;
final List<Object?>? replyList = await channel
.send(<Object?>[arg_prefix, arg_allowList]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@ -136,12 +137,12 @@ class UserDefaultsApi {
}
}
Future<void> clearWithPrefix(String arg_prefix) async {
Future<bool> clear(String arg_prefix, List<String?>? arg_allowList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix', codec,
'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_prefix]) as List<Object?>?;
final List<Object?>? replyList = await channel
.send(<Object?>[arg_prefix, arg_allowList]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@ -153,8 +154,13 @@ class UserDefaultsApi {
message: replyList[1] as String?,
details: replyList[2],
);
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return;
return (replyList[0] as bool?)!;
}
}
}

View File

@ -4,6 +4,7 @@
import 'package:flutter/services.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'messages.g.dart';
typedef _Setter = Future<void> Function(String key, Object value);
@ -12,7 +13,7 @@ typedef _Setter = Future<void> Function(String key, Object value);
class SharedPreferencesFoundation extends SharedPreferencesStorePlatform {
final UserDefaultsApi _api = UserDefaultsApi();
static const String _defautPrefix = 'flutter.';
static const String _defaultPrefix = 'flutter.';
late final Map<String, _Setter> _setters = <String, _Setter>{
'Bool': (String key, Object value) {
@ -40,24 +41,50 @@ class SharedPreferencesFoundation extends SharedPreferencesStorePlatform {
@override
Future<bool> clear() async {
return clearWithPrefix(_defautPrefix);
return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
Future<bool> clearWithPrefix(String prefix) async {
await _api.clearWithPrefix(prefix);
return true;
return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
return _api.clear(
filter.prefix,
filter.allowList?.toList(),
);
}
@override
Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defautPrefix);
return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
final Map<String?, Object?> result = await _api.getAllWithPrefix(prefix);
return result.cast<String, Object>();
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?> data =
await _api.getAll(filter.prefix, filter.allowList?.toList());
return data.cast<String, Object>();
}
@override

View File

@ -20,6 +20,6 @@ abstract class UserDefaultsApi {
void setValue(String key, Object value);
// TODO(stuartmorgan): Make these non-nullable once
// https://github.com/flutter/flutter/issues/97848 is fixed.
Map<String?, Object?> getAllWithPrefix(String prefix);
void clearWithPrefix(String prefix);
Map<String?, Object?> getAll(String prefix, List<String>? allowList);
bool clear(String prefix, List<String>? allowList);
}

View File

@ -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.2.2
version: 2.3.0
environment:
sdk: ">=2.18.0 <4.0.0"
@ -24,7 +24,7 @@ flutter:
dependencies:
flutter:
sdk: flutter
shared_preferences_platform_interface: ^2.2.0
shared_preferences_platform_interface: ^2.3.0
dev_dependencies:
flutter_test:

View File

@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences_foundation/shared_preferences_foundation.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'test_api.g.dart';
@ -13,10 +14,19 @@ class _MockSharedPreferencesApi implements TestUserDefaultsApi {
final Map<String, Object> items = <String, Object>{};
@override
Map<String?, Object?> getAllWithPrefix(String prefix) {
Map<String?, Object?> getAll(
String prefix,
List<String?>? allowList,
) {
Set<String?>? allowSet;
if (allowList != null) {
allowSet = Set<String>.from(allowList);
}
return <String?, Object?>{
for (final String key in items.keys)
if (key.startsWith(prefix)) key: items[key]
if (key.startsWith(prefix) &&
(allowSet == null || allowSet.contains(key)))
key: items[key]
};
}
@ -41,12 +51,14 @@ class _MockSharedPreferencesApi implements TestUserDefaultsApi {
}
@override
void clearWithPrefix(String prefix) {
bool clear(String prefix, List<String?>? allowList) {
items.keys.toList().forEach((String key) {
if (key.startsWith(prefix)) {
if (key.startsWith(prefix) &&
(allowList == null || allowList.contains(key))) {
items.remove(key);
}
});
return true;
}
}
@ -124,6 +136,63 @@ void main() {
expect(all.length, 0);
});
test('clearWithParameters', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
all = await plugin.getAll();
expect(all.length, 5);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 0);
});
test('clearWithParameters with allow list', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
all = await plugin.getAll();
expect(all.length, 5);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 4);
});
test('getAll', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in flutterTestValues.keys) {
@ -144,6 +213,37 @@ void main() {
expect(all, prefixTestValues);
});
test('getAllWithParameters', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
expect(all, prefixTestValues);
});
test('getAllWithParameters with allow list', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(all.length, 1);
expect(all['prefix.Bool'], prefixTestValues['prefix.Bool']);
});
test('setValue', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
expect(await plugin.setValue('Bool', 'flutter.Bool', true), isTrue);
@ -190,4 +290,43 @@ void main() {
all = await plugin.getAllWithPrefix('');
expect(all.length, 0);
});
test('getAllWithNoPrefix with param', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 15);
expect(all, allTestValues);
});
test('clearWithNoPrefix with param', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 15);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 0);
});
}

View File

@ -1,7 +1,7 @@
// 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.
// Autogenerated from Pigeon (v9.2.4), do not edit directly.
// Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
// ignore_for_file: avoid_relative_lib_imports
@ -26,9 +26,9 @@ abstract class TestUserDefaultsApi {
void setValue(String key, Object value);
Map<String?, Object?> getAllWithPrefix(String prefix);
Map<String?, Object?> getAll(String prefix, List<String?>? allowList);
void clearWithPrefix(String prefix);
bool clear(String prefix, List<String?>? allowList);
static void setup(TestUserDefaultsApi? api,
{BinaryMessenger? binaryMessenger}) {
@ -131,7 +131,7 @@ abstract class TestUserDefaultsApi {
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix', codec,
'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
@ -141,20 +141,22 @@ abstract class TestUserDefaultsApi {
.setMockDecodedMessageHandler<Object?>(channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix was null.');
'Argument for dev.flutter.pigeon.UserDefaultsApi.getAll was null.');
final List<Object?> args = (message as List<Object?>?)!;
final String? arg_prefix = (args[0] as String?);
assert(arg_prefix != null,
'Argument for dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix was null, expected non-null String.');
'Argument for dev.flutter.pigeon.UserDefaultsApi.getAll was null, expected non-null String.');
final List<String?>? arg_allowList =
(args[1] as List<Object?>?)?.cast<String?>();
final Map<String?, Object?> output =
api.getAllWithPrefix(arg_prefix!);
api.getAll(arg_prefix!, arg_allowList);
return <Object?>[output];
});
}
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix', codec,
'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
@ -164,13 +166,15 @@ abstract class TestUserDefaultsApi {
.setMockDecodedMessageHandler<Object?>(channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix was null.');
'Argument for dev.flutter.pigeon.UserDefaultsApi.clear was null.');
final List<Object?> args = (message as List<Object?>?)!;
final String? arg_prefix = (args[0] as String?);
assert(arg_prefix != null,
'Argument for dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix was null, expected non-null String.');
api.clearWithPrefix(arg_prefix!);
return <Object?>[];
'Argument for dev.flutter.pigeon.UserDefaultsApi.clear was null, expected non-null String.');
final List<String?>? arg_allowList =
(args[1] as List<Object?>?)?.cast<String?>();
final bool output = api.clear(arg_prefix!, arg_allowList);
return <Object?>[output];
});
}
}

View File

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

View File

@ -5,101 +5,335 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_linux/shared_preferences_linux.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('SharedPreferencesLinux', () {
const Map<String, Object> kTestValues = <String, Object>{
'flutter.String': 'hello world',
'flutter.bool': true,
'flutter.int': 42,
'flutter.double': 3.14159,
'flutter.List': <String>['foo', 'bar'],
};
const Map<String, Object> kTestValues2 = <String, Object>{
'flutter.String': 'goodbye world',
'flutter.bool': false,
'flutter.int': 1337,
'flutter.double': 2.71828,
'flutter.List': <String>['baz', 'quox'],
};
late SharedPreferencesLinux preferences;
const Map<String, Object> flutterTestValues = <String, Object>{
'flutter.String': 'hello world',
'flutter.Bool': true,
'flutter.Int': 42,
'flutter.Double': 3.14159,
'flutter.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> prefixTestValues = <String, Object>{
'prefix.String': 'hello world',
'prefix.Bool': true,
'prefix.Int': 42,
'prefix.Double': 3.14159,
'prefix.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> nonPrefixTestValues = <String, Object>{
'String': 'hello world',
'Bool': true,
'Int': 42,
'Double': 3.14159,
'StringList': <String>['foo', 'bar'],
};
final Map<String, Object> allTestValues = <String, Object>{};
allTestValues.addAll(flutterTestValues);
allTestValues.addAll(prefixTestValues);
allTestValues.addAll(nonPrefixTestValues);
Future<void> addData() async {
await preferences.setValue('String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue('Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
setUp(() async {
preferences = SharedPreferencesLinux();
await addData();
});
tearDown(() {
preferences.clear();
tearDown(() async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
});
testWidgets('reading', (WidgetTester _) async {
final Map<String, Object> all = await preferences.getAll();
expect(all['flutter.String'], isNull);
expect(all['flutter.bool'], isNull);
expect(all['flutter.int'], isNull);
expect(all['flutter.double'], isNull);
expect(all['flutter.List'], isNull);
testWidgets('getAll', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('writing', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'flutter.String', kTestValues2['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.bool', kTestValues2['flutter.bool']!),
preferences.setValue(
'Int', 'flutter.int', kTestValues2['flutter.int']!),
preferences.setValue(
'Double', 'flutter.double', kTestValues2['flutter.double']!),
preferences.setValue(
'StringList', 'flutter.List', kTestValues2['flutter.List']!)
]);
final Map<String, Object> all = await preferences.getAll();
expect(all['flutter.String'], kTestValues2['flutter.String']);
expect(all['flutter.bool'], kTestValues2['flutter.bool']);
expect(all['flutter.int'], kTestValues2['flutter.int']);
expect(all['flutter.double'], kTestValues2['flutter.double']);
expect(all['flutter.List'], kTestValues2['flutter.List']);
group('withPrefix', () {
testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values[key], isNull);
});
testWidgets('clear', (WidgetTester _) async {
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await preferences.clearWithPrefix('');
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
testWidgets('removing', (WidgetTester _) async {
const String key = 'flutter.testKey';
group('withParameters', () {
testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull);
});
await Future.wait(<Future<bool>>[
preferences.setValue('String', key, kTestValues['flutter.String']!),
preferences.setValue('Bool', key, kTestValues['flutter.bool']!),
preferences.setValue('Int', key, kTestValues['flutter.int']!),
preferences.setValue('Double', key, kTestValues['flutter.double']!),
preferences.setValue('StringList', key, kTestValues['flutter.List']!)
]);
await preferences.remove(key);
final Map<String, Object> all = await preferences.getAll();
expect(all[key], isNull);
});
testWidgets('clear', (WidgetTester _) async {
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
testWidgets('clearing', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'flutter.String', kTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.bool', kTestValues['flutter.bool']!),
preferences.setValue('Int', 'flutter.int', kTestValues['flutter.int']!),
preferences.setValue(
'Double', 'flutter.double', kTestValues['flutter.double']!),
preferences.setValue(
'StringList', 'flutter.List', kTestValues['flutter.List']!)
]);
await preferences.clear();
final Map<String, Object> all = await preferences.getAll();
expect(all['flutter.String'], null);
expect(all['flutter.bool'], null);
expect(all['flutter.int'], null);
expect(all['flutter.double'], null);
expect(all['flutter.List'], null);
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('get all with allow list', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list',
(WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
});
}

View File

@ -16,6 +16,7 @@ dependencies:
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
shared_preferences_platform_interface: ^2.3.0
dev_dependencies:
flutter_driver:

View File

@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart' show debugPrint, visibleForTesting;
import 'package:path/path.dart' as path;
import 'package:path_provider_linux/path_provider_linux.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
/// The Linux implementation of [SharedPreferencesStorePlatform].
///
@ -94,26 +95,52 @@ class SharedPreferencesLinux extends SharedPreferencesStorePlatform {
@override
Future<bool> clear() async {
return clearWithPrefix(_defaultPrefix);
return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
Future<bool> clearWithPrefix(String prefix) async {
return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String, Object> preferences = await _readPreferences();
preferences.removeWhere((String key, _) => key.startsWith(prefix));
preferences.removeWhere((String key, _) =>
key.startsWith(filter.prefix) &&
(filter.allowList == null || filter.allowList!.contains(key)));
return _writePreferences(preferences);
}
@override
Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defaultPrefix);
return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
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> withPrefix =
Map<String, Object>.from(await _readPreferences());
withPrefix.removeWhere((String key, _) => !key.startsWith(prefix));
withPrefix.removeWhere((String key, _) => !(key.startsWith(filter.prefix) &&
(filter.allowList?.contains(key) ?? true)));
return withPrefix;
}

View File

@ -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.2.0
version: 2.3.0
environment:
sdk: ">=2.18.0 <4.0.0"
@ -22,7 +22,7 @@ dependencies:
path: ^1.8.0
path_provider_linux: ^2.0.0
path_provider_platform_interface: ^2.0.0
shared_preferences_platform_interface: ^2.2.0
shared_preferences_platform_interface: ^2.3.0
dev_dependencies:
flutter_test:

View File

@ -10,6 +10,7 @@ import 'package:path_provider_linux/path_provider_linux.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'package:shared_preferences_linux/shared_preferences_linux.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() {
late MemoryFileSystem fs;
@ -98,6 +99,35 @@ void main() {
expect(values, prefixTestValues);
});
test('getAllWithParameters', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesLinux prefs = getPreferences();
final Map<String, Object> values = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values, hasLength(5));
expect(values, prefixTestValues);
});
test('getAllWithParameters with allow list', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesLinux prefs = getPreferences();
final Map<String?, Object?> all = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(all.length, 1);
expect(all['prefix.Bool'], prefixTestValues['prefix.Bool']);
});
test('remove', () async {
await writeTestFile('{"key1":"one","key2":2}');
final SharedPreferencesLinux prefs = getPreferences();
@ -155,6 +185,74 @@ void main() {
final Map<String, Object> noValues = await prefs.getAllWithPrefix('');
expect(noValues, hasLength(0));
});
test('clearWithParameters', () async {
await writeTestFile(json.encode(flutterTestValues));
final SharedPreferencesLinux prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(noValues, hasLength(0));
final Map<String, Object> values = await prefs.getAll();
expect(values, hasLength(5));
expect(values, flutterTestValues);
});
test('clearWithParameters with allow list', () async {
await writeTestFile(json.encode(prefixTestValues));
final SharedPreferencesLinux prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
final Map<String, Object> someValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(someValues, hasLength(4));
});
test('getAllWithNoPrefix', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesLinux prefs = getPreferences();
final Map<String, Object> values = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values, hasLength(15));
expect(values, allTestValues);
});
test('clearWithNoPrefix', () async {
await writeTestFile(json.encode(flutterTestValues));
final SharedPreferencesLinux prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(noValues, hasLength(0));
});
}
/// Fake implementation of PathProviderLinux that returns hard-coded paths,

View File

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

View File

@ -8,6 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.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/types.dart';
import 'package:shared_preferences_web/shared_preferences_web.dart';
const Map<String, dynamic> kTestValues = <String, dynamic>{
@ -21,94 +22,124 @@ const Map<String, dynamic> kTestValues = <String, dynamic>{
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('SharedPreferencesPlugin', () {
setUp(() {
html.window.localStorage.clear();
});
setUp(() {
html.window.localStorage.clear();
});
testWidgets('registers itself', (WidgetTester tester) async {
SharedPreferencesStorePlatform.instance =
MethodChannelSharedPreferencesStore();
expect(SharedPreferencesStorePlatform.instance,
isNot(isA<SharedPreferencesPlugin>()));
SharedPreferencesPlugin.registerWith(null);
expect(SharedPreferencesStorePlatform.instance,
isA<SharedPreferencesPlugin>());
});
testWidgets('registers itself', (WidgetTester tester) async {
SharedPreferencesStorePlatform.instance =
MethodChannelSharedPreferencesStore();
expect(SharedPreferencesStorePlatform.instance,
isNot(isA<SharedPreferencesPlugin>()));
SharedPreferencesPlugin.registerWith(null);
expect(SharedPreferencesStorePlatform.instance,
isA<SharedPreferencesPlugin>());
});
const Map<String, Object> flutterTestValues = <String, Object>{
'flutter.String': 'hello world',
'flutter.Bool': true,
'flutter.Int': 42,
'flutter.Double': 3.14159,
'flutter.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> flutterTestValues = <String, Object>{
'flutter.String': 'hello world',
'flutter.Bool': true,
'flutter.Int': 42,
'flutter.Double': 3.14159,
'flutter.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> prefixTestValues = <String, Object>{
'prefix.String': 'hello world',
'prefix.Bool': true,
'prefix.Int': 42,
'prefix.Double': 3.14159,
'prefix.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> prefixTestValues = <String, Object>{
'prefix.String': 'hello world',
'prefix.Bool': true,
'prefix.Int': 42,
'prefix.Double': 3.14159,
'prefix.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> nonPrefixTestValues = <String, Object>{
'String': 'hello world',
'Bool': true,
'Int': 42,
'Double': 3.14159,
'StringList': <String>['foo', 'bar'],
};
const Map<String, Object> nonPrefixTestValues = <String, Object>{
'String': 'hello world',
'Bool': true,
'Int': 42,
'Double': 3.14159,
'StringList': <String>['foo', 'bar'],
};
final Map<String, Object> allTestValues = <String, Object>{};
final Map<String, Object> allTestValues = <String, Object>{};
allTestValues.addAll(flutterTestValues);
allTestValues.addAll(prefixTestValues);
allTestValues.addAll(nonPrefixTestValues);
allTestValues.addAll(flutterTestValues);
allTestValues.addAll(prefixTestValues);
allTestValues.addAll(nonPrefixTestValues);
late SharedPreferencesStorePlatform preferences;
late SharedPreferencesStorePlatform preferences;
setUp(() async {
preferences = SharedPreferencesStorePlatform.instance;
});
tearDown(() async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
});
testWidgets('reading', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAll();
expect(values.length, 0);
});
Future<void> addData() async {
await preferences.setValue('String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue('Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue(
'StringList', 'prefix.StringList', allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
testWidgets('clear', (WidgetTester _) async {
await addData();
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
group('withPrefix', () {
setUp(() async {
preferences = SharedPreferencesStorePlatform.instance;
await addData();
});
tearDown(() {
// ignore: deprecated_member_use
preferences.clearWithPrefix('');
testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values[key], isNull);
});
testWidgets('reading', (WidgetTester _) async {
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], isNull);
expect(values['Bool'], isNull);
expect(values['Int'], isNull);
expect(values['Double'], isNull);
expect(values['StringList'], isNull);
});
testWidgets('getAllWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
@ -119,28 +150,23 @@ void main() {
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
@ -160,27 +186,76 @@ void main() {
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
await preferences.clearWithPrefix('');
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
group('withParameters', () {
setUp(() async {
await addData();
});
testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull);
});
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('get all with allow list', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
@ -193,29 +268,77 @@ void main() {
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
@ -227,77 +350,23 @@ void main() {
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
testWidgets('getAll', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('remove', (WidgetTester _) async {
const String key = 'testKey';
await preferences.setValue(
'String', key, allTestValues['flutter.String']!);
await preferences.setValue('Bool', key, allTestValues['flutter.Bool']!);
await preferences.setValue('Int', key, allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', key, allTestValues['flutter.Double']!);
await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values[key], isNull);
});
testWidgets('clear', (WidgetTester _) async {
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
testWidgets('simultaneous writes', (WidgetTester _) async {
final List<Future<bool>> writes = <Future<bool>>[];
const int writeCount = 100;
for (int i = 1; i <= writeCount; i++) {
writes.add(preferences.setValue('Int', 'Int', i));
}
final List<bool> result = await Future.wait(writes, eagerError: true);
// All writes should succeed.
expect(result.where((bool element) => !element), isEmpty);
// The last write should win.
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['Int'], writeCount);
});
testWidgets('simultaneous writes', (WidgetTester _) async {
final List<Future<bool>> writes = <Future<bool>>[];
const int writeCount = 100;
for (int i = 1; i <= writeCount; i++) {
writes.add(preferences.setValue('Int', 'Int', i));
}
final List<bool> result = await Future.wait(writes, eagerError: true);
// All writes should succeed.
expect(result.where((bool element) => !element), isEmpty);
// The last write should win.
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['Int'], writeCount);
});
}

View File

@ -8,7 +8,7 @@ environment:
dependencies:
flutter:
sdk: flutter
shared_preferences_platform_interface: ^2.0.0
shared_preferences_platform_interface: ^2.3.0
shared_preferences_web:
path: ../

View File

@ -8,6 +8,7 @@ import 'dart:html' as html;
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
/// The web implementation of [SharedPreferencesStorePlatform].
///
@ -22,27 +23,52 @@ class SharedPreferencesPlugin extends SharedPreferencesStorePlatform {
@override
Future<bool> clear() async {
return clearWithPrefix(_defaultPrefix);
return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
Future<bool> clearWithPrefix(String prefix) async {
return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
// IMPORTANT: Do not use html.window.localStorage.clear() as that will
// remove _all_ local data, not just the keys prefixed with
// _prefix
_getStoredFlutterKeys(prefix).forEach(html.window.localStorage.remove);
_getFilteredKeys(filter.prefix, allowList: filter.allowList)
.forEach(html.window.localStorage.remove);
return true;
}
@override
Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defaultPrefix);
return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
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> allData = <String, Object>{};
for (final String key in _getStoredFlutterKeys(prefix)) {
for (final String key
in _getFilteredKeys(filter.prefix, allowList: filter.allowList)) {
allData[key] = _decodeValue(html.window.localStorage[key]!);
}
return allData;
@ -60,9 +86,12 @@ class SharedPreferencesPlugin extends SharedPreferencesStorePlatform {
return true;
}
Iterable<String> _getStoredFlutterKeys(String prefix) {
return html.window.localStorage.keys
.where((String key) => key.startsWith(prefix));
Iterable<String> _getFilteredKeys(
String prefix, {
Set<String>? allowList,
}) {
return html.window.localStorage.keys.where((String key) =>
key.startsWith(prefix) && (allowList?.contains(key) ?? true));
}
String _encodeValue(Object? value) {

View File

@ -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.1.0
version: 2.2.0
environment:
sdk: ">=2.18.0 <4.0.0"
@ -21,7 +21,7 @@ dependencies:
sdk: flutter
flutter_web_plugins:
sdk: flutter
shared_preferences_platform_interface: ^2.2.0
shared_preferences_platform_interface: ^2.3.0
dev_dependencies:
flutter_test:

View File

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

View File

@ -4,95 +4,336 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'package:shared_preferences_windows/shared_preferences_windows.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('SharedPreferencesWindows', () {
const Map<String, Object> kTestValues = <String, Object>{
late SharedPreferencesWindows preferences;
const Map<String, Object> flutterTestValues = <String, Object>{
'flutter.String': 'hello world',
'flutter.bool': true,
'flutter.int': 42,
'flutter.double': 3.14159,
'flutter.List': <String>['foo', 'bar'],
'flutter.Bool': true,
'flutter.Int': 42,
'flutter.Double': 3.14159,
'flutter.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> kTestValues2 = <String, Object>{
'flutter.String': 'goodbye world',
'flutter.bool': false,
'flutter.int': 1337,
'flutter.double': 2.71828,
'flutter.List': <String>['baz', 'quox'],
const Map<String, Object> prefixTestValues = <String, Object>{
'prefix.String': 'hello world',
'prefix.Bool': true,
'prefix.Int': 42,
'prefix.Double': 3.14159,
'prefix.StringList': <String>['foo', 'bar'],
};
testWidgets('reading', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['String'], isNull);
expect(values['bool'], isNull);
expect(values['int'], isNull);
expect(values['double'], isNull);
expect(values['List'], isNull);
const Map<String, Object> nonPrefixTestValues = <String, Object>{
'String': 'hello world',
'Bool': true,
'Int': 42,
'Double': 3.14159,
'StringList': <String>['foo', 'bar'],
};
final Map<String, Object> allTestValues = <String, Object>{};
allTestValues.addAll(flutterTestValues);
allTestValues.addAll(prefixTestValues);
allTestValues.addAll(nonPrefixTestValues);
Future<void> addData() async {
await preferences.setValue('String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue('Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
setUp(() async {
preferences = SharedPreferencesWindows();
await addData();
});
testWidgets('writing', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
await preferences.clear();
await preferences.setValue(
'String', 'flutter.String', kTestValues2['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.bool', kTestValues2['flutter.bool']!);
await preferences.setValue(
'Int', 'flutter.int', kTestValues2['flutter.int']!);
await preferences.setValue(
'Double', 'flutter.double', kTestValues2['flutter.double']!);
await preferences.setValue(
'StringList', 'flutter.List', kTestValues2['flutter.List']!);
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], kTestValues2['flutter.String']);
expect(values['flutter.bool'], kTestValues2['flutter.bool']);
expect(values['flutter.int'], kTestValues2['flutter.int']);
expect(values['flutter.double'], kTestValues2['flutter.double']);
expect(values['flutter.List'], kTestValues2['flutter.List']);
tearDown(() async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
});
testWidgets('removing', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
await preferences.clear();
const String key = 'flutter.testKey';
await preferences.setValue('String', key, kTestValues['flutter.String']!);
await preferences.setValue('Bool', key, kTestValues['flutter.bool']!);
await preferences.setValue('Int', key, kTestValues['flutter.int']!);
await preferences.setValue('Double', key, kTestValues['flutter.double']!);
await preferences.setValue(
'StringList', key, kTestValues['flutter.List']!);
await preferences.remove(key);
testWidgets('getAll', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAll();
expect(values[key], isNull);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearing', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
await preferences.clear();
await preferences.setValue(
'String', 'flutter.String', kTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.bool', kTestValues['flutter.bool']!);
await preferences.setValue(
'Int', 'flutter.int', kTestValues['flutter.int']!);
await preferences.setValue(
'Double', 'flutter.double', kTestValues['flutter.double']!);
await preferences.setValue(
'StringList', 'flutter.List', kTestValues['flutter.List']!);
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.bool'], null);
expect(values['flutter.int'], null);
expect(values['flutter.double'], null);
expect(values['flutter.List'], null);
group('withPrefix', () {
testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values[key], isNull);
});
testWidgets('clear', (WidgetTester _) async {
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await preferences.clearWithPrefix('');
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
group('withParameters', () {
testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull);
});
testWidgets('clear', (WidgetTester _) async {
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('get all with allow list', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list',
(WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
});
}

View File

@ -9,6 +9,7 @@ environment:
dependencies:
flutter:
sdk: flutter
shared_preferences_platform_interface: ^2.3.0
shared_preferences_windows:
# When depending on this package from a real application you should use:
# shared_preferences_windows: ^x.y.z

View File

@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart' show debugPrint, visibleForTesting;
import 'package:path/path.dart' as path;
import 'package:path_provider_windows/path_provider_windows.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
/// The Windows implementation of [SharedPreferencesStorePlatform].
///
@ -100,26 +101,52 @@ class SharedPreferencesWindows extends SharedPreferencesStorePlatform {
@override
Future<bool> clear() async {
return clearWithPrefix(_defaultPrefix);
return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
Future<bool> clearWithPrefix(String prefix) async {
return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String, Object> preferences = await _readPreferences();
preferences.removeWhere((String key, _) => key.startsWith(prefix));
preferences.removeWhere((String key, _) =>
key.startsWith(filter.prefix) &&
(filter.allowList == null || filter.allowList!.contains(key)));
return _writePreferences(preferences);
}
@override
Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defaultPrefix);
return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
}
@override
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> withPrefix =
Map<String, Object>.from(await _readPreferences());
withPrefix.removeWhere((String key, _) => !key.startsWith(prefix));
withPrefix.removeWhere((String key, _) => !(key.startsWith(filter.prefix) &&
(filter.allowList?.contains(key) ?? true)));
return withPrefix;
}

View File

@ -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.2.0
version: 2.3.0
environment:
sdk: ">=2.18.0 <4.0.0"
@ -22,7 +22,7 @@ dependencies:
path: ^1.8.0
path_provider_platform_interface: ^2.0.0
path_provider_windows: ^2.0.0
shared_preferences_platform_interface: ^2.2.0
shared_preferences_platform_interface: ^2.3.0
dev_dependencies:
flutter_test:

View File

@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'package:path_provider_windows/path_provider_windows.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'package:shared_preferences_windows/shared_preferences_windows.dart';
void main() {
@ -99,6 +100,35 @@ void main() {
expect(values, prefixTestValues);
});
test('getAllWithParameters with Prefix', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesWindows prefs = getPreferences();
final Map<String, Object> values = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values, hasLength(5));
expect(values, prefixTestValues);
});
test('getAllWithParameters with Prefix with allow list', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesWindows prefs = getPreferences();
final Map<String?, Object?> all = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(all.length, 1);
expect(all['prefix.Bool'], prefixTestValues['prefix.Bool']);
});
test('remove', () async {
await writeTestFile('{"key1":"one","key2":2}');
final SharedPreferencesWindows prefs = getPreferences();
@ -156,6 +186,74 @@ void main() {
final Map<String, Object> noValues = await prefs.getAllWithPrefix('');
expect(noValues, hasLength(0));
});
test('clearWithParameters with Prefix', () async {
await writeTestFile(json.encode(flutterTestValues));
final SharedPreferencesWindows prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(noValues, hasLength(0));
final Map<String, Object> values = await prefs.getAll();
expect(values, hasLength(5));
expect(values, flutterTestValues);
});
test('clearWithParameters with allow list', () async {
await writeTestFile(json.encode(prefixTestValues));
final SharedPreferencesWindows prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(noValues, hasLength(4));
});
test('getAllWithNoPrefix', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesWindows prefs = getPreferences();
final Map<String, Object> values = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values, hasLength(15));
expect(values, allTestValues);
});
test('clearWithNoPrefix', () async {
await writeTestFile(json.encode(flutterTestValues));
final SharedPreferencesWindows prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(noValues, hasLength(0));
});
}
/// Fake implementation of PathProviderWindows that returns hard-coded paths,