[shared_preferences] Convert macOS to Pigeon (#6914)
* Add Pigeon and update Dart, based on iOS implementation
* Update Swift implementation
* Update Swift tests
* Adjust Dart test and add Pigeon TODOs
* Version bump
* Format
* Update to Pigeon 5.0 for Swift warning fix
diff --git a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md
index fc8a78a..f0a8526 100644
--- a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md
+++ b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 2.0.5
+* Converts platform channel to Pigeon.
* Updates code for `no_leading_underscores_for_local_identifiers` lint.
* Updates minimum Flutter version to 2.10.
diff --git a/packages/shared_preferences/shared_preferences_macos/example/macos/RunnerTests/RunnerTests.swift b/packages/shared_preferences/shared_preferences_macos/example/macos/RunnerTests/RunnerTests.swift
index 7da66cb..9a1b2f0 100644
--- a/packages/shared_preferences/shared_preferences_macos/example/macos/RunnerTests/RunnerTests.swift
+++ b/packages/shared_preferences/shared_preferences_macos/example/macos/RunnerTests/RunnerTests.swift
@@ -4,85 +4,55 @@
import FlutterMacOS
import XCTest
-import shared_preferences_macos
+@testable import shared_preferences_macos
class RunnerTests: XCTestCase {
- func testHandlesCommitNoOp() throws {
- let plugin = SharedPreferencesPlugin()
- let call = FlutterMethodCall(methodName: "commit", arguments: nil)
- var called = false
- plugin.handle(
- call,
- result: { (result: Any?) -> Void in
- called = true
- XCTAssert(result as? Bool == true)
- })
- XCTAssert(called)
- }
-
func testSetAndGet() throws {
let plugin = SharedPreferencesPlugin()
- let setCall = FlutterMethodCall(
- methodName: "setInt",
- arguments: [
- "key": "flutter.foo",
- "value": 42,
- ])
- plugin.handle(
- setCall,
- result: { (result: Any?) -> Void in
- XCTAssert(result as? Bool == true)
- })
- var value: Int?
- plugin.handle(
- FlutterMethodCall(methodName: "getAll", arguments: nil),
- result: { (result: Any?) -> Void in
- if let prefs = result as? [String: Any] {
- value = prefs["flutter.foo"] as? Int
- }
- })
- XCTAssertEqual(value, 42)
+ plugin.setBool(key: "flutter.aBool", value: true)
+ plugin.setDouble(key: "flutter.aDouble", value: 3.14)
+ plugin.setValue(key: "flutter.anInt", value: 42)
+ plugin.setValue(key: "flutter.aString", value: "hello world")
+ plugin.setValue(key: "flutter.aStringList", value: ["hello", "world"])
+
+ let storedValues = plugin.getAll()
+ XCTAssertEqual(storedValues["flutter.aBool"] as? Bool, true)
+ XCTAssertEqual(storedValues["flutter.aDouble"] as! Double, 3.14, accuracy: 0.0001)
+ XCTAssertEqual(storedValues["flutter.anInt"] as? Int, 42)
+ XCTAssertEqual(storedValues["flutter.aString"] as? String, "hello world")
+ XCTAssertEqual(storedValues["flutter.aStringList"] as? Array<String>, ["hello", "world"])
+ }
+
+ func testRemove() throws {
+ let plugin = SharedPreferencesPlugin()
+ let testKey = "flutter.foo"
+ 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.getAll()
+ XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
+
+ // Then verify that removing it works.
+ plugin.remove(key: testKey)
+
+ let finalValues = plugin.getAll()
+ XCTAssertNil(finalValues[testKey] as Any?)
}
func testClear() throws {
let plugin = SharedPreferencesPlugin()
- let setCall = FlutterMethodCall(
- methodName: "setInt",
- arguments: [
- "key": "flutter.foo",
- "value": 42,
- ])
- plugin.handle(setCall, result: { (result: Any?) -> Void in })
+ let testKey = "flutter.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 getCall = FlutterMethodCall(methodName: "getAll", arguments: nil)
- var value: Int?
- plugin.handle(
- getCall,
- result: { (result: Any?) -> Void in
- if let prefs = result as? [String: Any] {
- value = prefs["flutter.foo"] as? Int
- }
- })
- XCTAssertEqual(value, 42)
+ let preRemovalValues = plugin.getAll()
+ XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
- // Clear the value.
- plugin.handle(
- FlutterMethodCall(methodName: "clear", arguments: nil),
- result: { (result: Any?) -> Void in
- XCTAssert(result as? Bool == true)
- })
+ // Then verify that clearing works.
+ plugin.clear()
- // Get the value again, which should clear |value|.
- plugin.handle(
- getCall,
- result: { (result: Any?) -> Void in
- if let prefs = result as? [String: Any] {
- value = prefs["flutter.foo"] as? Int
- XCTAssert(prefs.isEmpty)
- }
- })
- XCTAssertEqual(value, nil)
+ let finalValues = plugin.getAll()
+ XCTAssertNil(finalValues[testKey] as Any?)
}
}
diff --git a/packages/shared_preferences/shared_preferences_macos/lib/messages.g.dart b/packages/shared_preferences/shared_preferences_macos/lib/messages.g.dart
new file mode 100644
index 0000000..f7c6c21
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_macos/lib/messages.g.dart
@@ -0,0 +1,157 @@
+// 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 (v5.0.0), 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
+import 'dart:async';
+import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
+
+import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
+import 'package:flutter/services.dart';
+
+class UserDefaultsApi {
+ /// Constructor for [UserDefaultsApi]. The [binaryMessenger] named argument is
+ /// available for dependency injection. If it is left null, the default
+ /// BinaryMessenger will be used which routes to the host platform.
+ UserDefaultsApi({BinaryMessenger? binaryMessenger})
+ : _binaryMessenger = binaryMessenger;
+ final BinaryMessenger? _binaryMessenger;
+
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+ Future<void> remove(String arg_key) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.remove', codec,
+ binaryMessenger: _binaryMessenger);
+ final List<Object?>? replyList =
+ await channel.send(<Object?>[arg_key]) as List<Object?>?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else {
+ return;
+ }
+ }
+
+ Future<void> setBool(String arg_key, bool arg_value) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.setBool', codec,
+ binaryMessenger: _binaryMessenger);
+ final List<Object?>? replyList =
+ await channel.send(<Object?>[arg_key, arg_value]) as List<Object?>?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else {
+ return;
+ }
+ }
+
+ Future<void> setDouble(String arg_key, double arg_value) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.setDouble', codec,
+ binaryMessenger: _binaryMessenger);
+ final List<Object?>? replyList =
+ await channel.send(<Object?>[arg_key, arg_value]) as List<Object?>?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else {
+ return;
+ }
+ }
+
+ Future<void> setValue(String arg_key, Object arg_value) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.setValue', codec,
+ binaryMessenger: _binaryMessenger);
+ final List<Object?>? replyList =
+ await channel.send(<Object?>[arg_key, arg_value]) as List<Object?>?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else {
+ return;
+ }
+ }
+
+ Future<Map<String?, Object?>> getAll() async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
+ binaryMessenger: _binaryMessenger);
+ final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ 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 (replyList[0] as Map<Object?, Object?>?)!.cast<String?, Object?>();
+ }
+ }
+
+ Future<void> clear() async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
+ binaryMessenger: _binaryMessenger);
+ final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else {
+ return;
+ }
+ }
+}
diff --git a/packages/shared_preferences/shared_preferences_macos/lib/shared_preferences_macos.dart b/packages/shared_preferences/shared_preferences_macos/lib/shared_preferences_macos.dart
index a97fe13..25e8c5d 100644
--- a/packages/shared_preferences/shared_preferences_macos/lib/shared_preferences_macos.dart
+++ b/packages/shared_preferences/shared_preferences_macos/lib/shared_preferences_macos.dart
@@ -2,52 +2,66 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:async';
-
import 'package:flutter/services.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
+import 'messages.g.dart';
-const MethodChannel _kChannel =
- MethodChannel('plugins.flutter.io/shared_preferences_macos');
+typedef _Setter = Future<void> Function(String key, Object value);
-/// The macOS implementation of [SharedPreferencesStorePlatform].
-///
-/// This class implements the `package:shared_preferences` functionality for macOS.
+/// macOS implementation of shared_preferences.
class SharedPreferencesMacOS extends SharedPreferencesStorePlatform {
- /// Registers this class as the default instance of [SharedPreferencesStorePlatform].
+ final UserDefaultsApi _api = UserDefaultsApi();
+ late final Map<String, _Setter> _setters = <String, _Setter>{
+ 'Bool': (String key, Object value) {
+ return _api.setBool(key, value as bool);
+ },
+ 'Double': (String key, Object value) {
+ return _api.setDouble(key, value as double);
+ },
+ 'Int': (String key, Object value) {
+ return _api.setValue(key, value as int);
+ },
+ 'String': (String key, Object value) {
+ return _api.setValue(key, value as String);
+ },
+ 'StringList': (String key, Object value) {
+ return _api.setValue(key, value as List<String?>);
+ },
+ };
+
+ /// Registers this class as the default instance of
+ /// [SharedPreferencesStorePlatform].
static void registerWith() {
SharedPreferencesStorePlatform.instance = SharedPreferencesMacOS();
}
@override
- Future<bool> remove(String key) async {
- return (await _kChannel.invokeMethod<bool>(
- 'remove',
- <String, dynamic>{'key': key},
- ))!;
- }
-
- @override
- Future<bool> setValue(String valueType, String key, Object value) async {
- return (await _kChannel.invokeMethod<bool>(
- 'set$valueType',
- <String, dynamic>{'key': key, 'value': value},
- ))!;
- }
-
- @override
Future<bool> clear() async {
- return (await _kChannel.invokeMethod<bool>('clear'))!;
+ await _api.clear();
+ return true;
}
@override
Future<Map<String, Object>> getAll() async {
- final Map<String, Object>? preferences =
- await _kChannel.invokeMapMethod<String, Object>('getAll');
+ final Map<String?, Object?> result = await _api.getAll();
+ return result.cast<String, Object>();
+ }
- if (preferences == null) {
- return <String, Object>{};
+ @override
+ Future<bool> remove(String key) async {
+ await _api.remove(key);
+ return true;
+ }
+
+ @override
+ Future<bool> setValue(String valueType, String key, Object value) async {
+ final _Setter? setter = _setters[valueType];
+ if (setter == null) {
+ throw PlatformException(
+ code: 'InvalidOperation',
+ message: '"$valueType" is not a supported type.');
}
- return preferences;
+ await setter(key, value);
+ return true;
}
}
diff --git a/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift b/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift
index 91b4244..6e5e79d 100644
--- a/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift
+++ b/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift
@@ -5,44 +5,36 @@
import FlutterMacOS
import Foundation
-public class SharedPreferencesPlugin: NSObject, FlutterPlugin {
+public class SharedPreferencesPlugin: NSObject, FlutterPlugin, UserDefaultsApi {
public static func register(with registrar: FlutterPluginRegistrar) {
- let channel = FlutterMethodChannel(
- name: "plugins.flutter.io/shared_preferences_macos",
- binaryMessenger: registrar.messenger)
let instance = SharedPreferencesPlugin()
- registrar.addMethodCallDelegate(instance, channel: channel)
+ UserDefaultsApiSetup.setUp(binaryMessenger: registrar.messenger, api: instance)
}
- public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
- switch call.method {
- case "getAll":
- result(getAllPrefs())
- case "setBool",
- "setInt",
- "setDouble",
- "setString",
- "setStringList":
- let arguments = call.arguments as! [String: Any]
- let key = arguments["key"] as! String
- UserDefaults.standard.set(arguments["value"], forKey: key)
- result(true)
- case "commit":
- // UserDefaults does not need to be synchronized.
- result(true)
- case "remove":
- let arguments = call.arguments as! [String: Any]
- let key = arguments["key"] as! String
- UserDefaults.standard.removeObject(forKey: key)
- result(true)
- case "clear":
- let defaults = UserDefaults.standard
- for (key, _) in getAllPrefs() {
- defaults.removeObject(forKey: key)
- }
- result(true)
- default:
- result(FlutterMethodNotImplemented)
+ func getAll() -> [String? : Any?] {
+ return getAllPrefs();
+ }
+
+ func setBool(key: String, value: Bool) {
+ UserDefaults.standard.set(value, forKey: key)
+ }
+
+ func setDouble(key: String, value: Double) {
+ UserDefaults.standard.set(value, forKey: key)
+ }
+
+ func setValue(key: String, value: Any) {
+ UserDefaults.standard.set(value, forKey: key)
+ }
+
+ func remove(key: String) {
+ UserDefaults.standard.removeObject(forKey: key)
+ }
+
+ func clear() {
+ let defaults = UserDefaults.standard
+ for (key, _) in getAllPrefs() {
+ defaults.removeObject(forKey: key)
}
}
}
diff --git a/packages/shared_preferences/shared_preferences_macos/macos/Classes/messages.g.swift b/packages/shared_preferences/shared_preferences_macos/macos/Classes/messages.g.swift
new file mode 100644
index 0000000..933217b
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_macos/macos/Classes/messages.g.swift
@@ -0,0 +1,111 @@
+// 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 (v5.0.0), do not edit directly.
+// See also: https://pub.dev/packages/pigeon
+
+import Foundation
+#if os(iOS)
+import Flutter
+#elseif os(macOS)
+import FlutterMacOS
+#else
+#error("Unsupported platform.")
+#endif
+
+
+/// Generated class from Pigeon.
+/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
+protocol UserDefaultsApi {
+ func remove(key: String)
+ func setBool(key: String, value: Bool)
+ func setDouble(key: String, value: Double)
+ func setValue(key: String, value: Any)
+ func getAll() -> [String?: Any?]
+ func clear()
+}
+
+/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
+class UserDefaultsApiSetup {
+ /// The codec used by UserDefaultsApi.
+ /// Sets up an instance of `UserDefaultsApi` to handle messages through the `binaryMessenger`.
+ static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UserDefaultsApi?) {
+ let removeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.remove", binaryMessenger: binaryMessenger)
+ if let api = api {
+ removeChannel.setMessageHandler { message, reply in
+ let args = message as! [Any?]
+ let keyArg = args[0] as! String
+ api.remove(key: keyArg)
+ reply(wrapResult(nil))
+ }
+ } else {
+ removeChannel.setMessageHandler(nil)
+ }
+ let setBoolChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setBool", binaryMessenger: binaryMessenger)
+ if let api = api {
+ setBoolChannel.setMessageHandler { message, reply in
+ let args = message as! [Any?]
+ let keyArg = args[0] as! String
+ let valueArg = args[1] as! Bool
+ api.setBool(key: keyArg, value: valueArg)
+ reply(wrapResult(nil))
+ }
+ } else {
+ setBoolChannel.setMessageHandler(nil)
+ }
+ let setDoubleChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setDouble", binaryMessenger: binaryMessenger)
+ if let api = api {
+ setDoubleChannel.setMessageHandler { message, reply in
+ let args = message as! [Any?]
+ let keyArg = args[0] as! String
+ let valueArg = args[1] as! Double
+ api.setDouble(key: keyArg, value: valueArg)
+ reply(wrapResult(nil))
+ }
+ } else {
+ setDoubleChannel.setMessageHandler(nil)
+ }
+ let setValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setValue", binaryMessenger: binaryMessenger)
+ if let api = api {
+ setValueChannel.setMessageHandler { message, reply in
+ let args = message as! [Any?]
+ let keyArg = args[0] as! String
+ let valueArg = args[1]!
+ api.setValue(key: keyArg, value: valueArg)
+ reply(wrapResult(nil))
+ }
+ } else {
+ setValueChannel.setMessageHandler(nil)
+ }
+ let getAllChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.getAll", binaryMessenger: binaryMessenger)
+ if let api = api {
+ getAllChannel.setMessageHandler { _, reply in
+ let result = api.getAll()
+ reply(wrapResult(result))
+ }
+ } else {
+ getAllChannel.setMessageHandler(nil)
+ }
+ let clearChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.clear", binaryMessenger: binaryMessenger)
+ if let api = api {
+ clearChannel.setMessageHandler { _, reply in
+ api.clear()
+ reply(wrapResult(nil))
+ }
+ } else {
+ clearChannel.setMessageHandler(nil)
+ }
+ }
+}
+
+private func wrapResult(_ result: Any?) -> [Any?] {
+ return [result]
+}
+
+private func wrapError(_ error: FlutterError) -> [Any?] {
+ return [
+ error.code,
+ error.message,
+ error.details
+ ]
+}
diff --git a/packages/shared_preferences/shared_preferences_macos/pigeons/copyright_header.txt b/packages/shared_preferences/shared_preferences_macos/pigeons/copyright_header.txt
new file mode 100644
index 0000000..fb682b1
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_macos/pigeons/copyright_header.txt
@@ -0,0 +1,3 @@
+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.
\ No newline at end of file
diff --git a/packages/shared_preferences/shared_preferences_macos/pigeons/messages.dart b/packages/shared_preferences/shared_preferences_macos/pigeons/messages.dart
new file mode 100644
index 0000000..bda7185
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_macos/pigeons/messages.dart
@@ -0,0 +1,25 @@
+// 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.
+
+import 'package:pigeon/pigeon.dart';
+
+@ConfigurePigeon(PigeonOptions(
+ dartOut: 'lib/messages.g.dart',
+ dartTestOut: 'test/test_api.g.dart',
+ swiftOut: 'macos/Classes/messages.g.swift',
+ copyrightHeader: 'pigeons/copyright_header.txt',
+))
+@HostApi(dartHostTestHandler: 'TestUserDefaultsApi')
+abstract class UserDefaultsApi {
+ void remove(String key);
+ // TODO(stuartmorgan): Give these setters better Swift signatures (_,forKey:)
+ // once https://github.com/flutter/flutter/issues/105932 is fixed.
+ void setBool(String key, bool value);
+ void setDouble(String key, double value);
+ 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?> getAll();
+ void clear();
+}
diff --git a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml
index 77f5f11..2ddf998 100644
--- a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml
+++ b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml
@@ -2,7 +2,7 @@
description: macOS implementation of the shared_preferences plugin.
repository: https://github.com/flutter/plugins/tree/main/packages/shared_preferences/shared_preferences_macos
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
-version: 2.0.4
+version: 2.0.5
environment:
sdk: ">=2.12.0 <3.0.0"
@@ -24,3 +24,4 @@
dev_dependencies:
flutter_test:
sdk: flutter
+ pigeon: ^5.0.0
diff --git a/packages/shared_preferences/shared_preferences_macos/test/shared_preferences_macos_test.dart b/packages/shared_preferences/shared_preferences_macos/test/shared_preferences_macos_test.dart
index 8e71e40..f32ba4c 100644
--- a/packages/shared_preferences/shared_preferences_macos/test/shared_preferences_macos_test.dart
+++ b/packages/shared_preferences/shared_preferences_macos/test/shared_preferences_macos_test.dart
@@ -5,113 +5,111 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences_macos/shared_preferences_macos.dart';
-import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
+import 'test_api.g.dart';
+
+class _MockSharedPreferencesApi implements TestUserDefaultsApi {
+ final Map<String, Object> items = <String, Object>{};
+
+ @override
+ Map<String?, Object?> getAll() {
+ return items;
+ }
+
+ @override
+ void remove(String key) {
+ items.remove(key);
+ }
+
+ @override
+ void setBool(String key, bool value) {
+ items[key] = value;
+ }
+
+ @override
+ void setDouble(String key, double value) {
+ items[key] = value;
+ }
+
+ @override
+ void setValue(String key, Object value) {
+ items[key] = value;
+ }
+
+ @override
+ void clear() {
+ items.clear();
+ }
+}
+
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
+ late _MockSharedPreferencesApi api;
- group(MethodChannelSharedPreferencesStore, () {
- const MethodChannel channel = MethodChannel(
- 'plugins.flutter.io/shared_preferences_macos',
- );
+ setUp(() {
+ api = _MockSharedPreferencesApi();
+ TestUserDefaultsApi.setup(api);
+ });
- const Map<String, Object> kTestValues = <String, Object>{
- 'flutter.String': 'hello world',
- 'flutter.Bool': true,
- 'flutter.Int': 42,
- 'flutter.Double': 3.14159,
- 'flutter.StringList': <String>['foo', 'bar'],
- };
- // Create a dummy in-memory implementation to back the mocked method channel
- // API to simplify validation of the expected calls.
- late InMemorySharedPreferencesStore testData;
+ test('registerWith', () {
+ SharedPreferencesMacOS.registerWith();
+ expect(
+ SharedPreferencesStorePlatform.instance, isA<SharedPreferencesMacOS>());
+ });
- final List<MethodCall> log = <MethodCall>[];
- late SharedPreferencesStorePlatform store;
+ test('remove', () async {
+ final SharedPreferencesMacOS plugin = SharedPreferencesMacOS();
+ api.items['flutter.hi'] = 'world';
+ expect(await plugin.remove('flutter.hi'), isTrue);
+ expect(api.items.containsKey('flutter.hi'), isFalse);
+ });
- setUp(() async {
- testData = InMemorySharedPreferencesStore.empty();
+ test('clear', () async {
+ final SharedPreferencesMacOS plugin = SharedPreferencesMacOS();
+ api.items['flutter.hi'] = 'world';
+ expect(await plugin.clear(), isTrue);
+ expect(api.items.containsKey('flutter.hi'), isFalse);
+ });
- channel.setMockMethodCallHandler((MethodCall methodCall) async {
- log.add(methodCall);
- if (methodCall.method == 'getAll') {
- return testData.getAll();
- }
- if (methodCall.method == 'remove') {
- final String key = (methodCall.arguments['key'] as String?)!;
- return testData.remove(key);
- }
- if (methodCall.method == 'clear') {
- return testData.clear();
- }
- final RegExp setterRegExp = RegExp(r'set(.*)');
- final Match? match = setterRegExp.matchAsPrefix(methodCall.method);
- if (match?.groupCount == 1) {
- final String valueType = match!.group(1)!;
- final String key = (methodCall.arguments['key'] as String?)!;
- final Object value = (methodCall.arguments['value'] as Object?)!;
- return testData.setValue(valueType, key, value);
- }
- fail('Unexpected method call: ${methodCall.method}');
- });
- log.clear();
- });
+ test('getAll', () async {
+ final SharedPreferencesMacOS plugin = SharedPreferencesMacOS();
+ api.items['flutter.aBool'] = true;
+ api.items['flutter.aDouble'] = 3.14;
+ api.items['flutter.anInt'] = 42;
+ api.items['flutter.aString'] = 'hello world';
+ api.items['flutter.aStringList'] = <String>['hello', 'world'];
+ final Map<String?, Object?> all = await plugin.getAll();
+ expect(all.length, 5);
+ expect(all['flutter.aBool'], api.items['flutter.aBool']);
+ expect(all['flutter.aDouble'],
+ closeTo(api.items['flutter.aDouble']! as num, 0.0001));
+ expect(all['flutter.anInt'], api.items['flutter.anInt']);
+ expect(all['flutter.aString'], api.items['flutter.aString']);
+ expect(all['flutter.aStringList'], api.items['flutter.aStringList']);
+ });
- test('registers instance', () {
- SharedPreferencesMacOS.registerWith();
- expect(SharedPreferencesStorePlatform.instance,
- isA<SharedPreferencesMacOS>());
- });
+ test('setValue', () async {
+ final SharedPreferencesMacOS plugin = SharedPreferencesMacOS();
+ expect(await plugin.setValue('Bool', 'flutter.Bool', true), isTrue);
+ expect(api.items['flutter.Bool'], true);
+ expect(await plugin.setValue('Double', 'flutter.Double', 1.5), isTrue);
+ expect(api.items['flutter.Double'], 1.5);
+ expect(await plugin.setValue('Int', 'flutter.Int', 12), isTrue);
+ expect(api.items['flutter.Int'], 12);
+ expect(await plugin.setValue('String', 'flutter.String', 'hi'), isTrue);
+ expect(api.items['flutter.String'], 'hi');
+ expect(
+ await plugin
+ .setValue('StringList', 'flutter.StringList', <String>['hi']),
+ isTrue);
+ expect(api.items['flutter.StringList'], <String>['hi']);
+ });
- test('getAll', () async {
- store = SharedPreferencesMacOS();
- testData = InMemorySharedPreferencesStore.withData(kTestValues);
- expect(await store.getAll(), kTestValues);
- expect(log.single.method, 'getAll');
- });
-
- test('remove', () async {
- store = SharedPreferencesMacOS();
- testData = InMemorySharedPreferencesStore.withData(kTestValues);
- expect(await store.remove('flutter.String'), true);
- expect(await store.remove('flutter.Bool'), true);
- expect(await store.remove('flutter.Int'), true);
- expect(await store.remove('flutter.Double'), true);
- expect(await testData.getAll(), <String, dynamic>{
- 'flutter.StringList': <String>['foo', 'bar'],
- });
-
- expect(log, hasLength(4));
- for (final MethodCall call in log) {
- expect(call.method, 'remove');
- }
- });
-
- test('setValue', () async {
- store = SharedPreferencesMacOS();
- expect(await testData.getAll(), isEmpty);
- for (final String key in kTestValues.keys) {
- final Object value = kTestValues[key]!;
- expect(await store.setValue(key.split('.').last, key, value), true);
- }
- expect(await testData.getAll(), kTestValues);
-
- expect(log, hasLength(5));
- expect(log[0].method, 'setString');
- expect(log[1].method, 'setBool');
- expect(log[2].method, 'setInt');
- expect(log[3].method, 'setDouble');
- expect(log[4].method, 'setStringList');
- });
-
- test('clear', () async {
- store = SharedPreferencesMacOS();
- testData = InMemorySharedPreferencesStore.withData(kTestValues);
- expect(await testData.getAll(), isNotEmpty);
- expect(await store.clear(), true);
- expect(await testData.getAll(), isEmpty);
- expect(log.single.method, 'clear');
- });
+ test('setValue with unsupported type', () {
+ final SharedPreferencesMacOS plugin = SharedPreferencesMacOS();
+ expect(() async {
+ await plugin.setValue('Map', 'flutter.key', <String, String>{});
+ }, throwsA(isA<PlatformException>()));
});
}
diff --git a/packages/shared_preferences/shared_preferences_macos/test/test_api.g.dart b/packages/shared_preferences/shared_preferences_macos/test/test_api.g.dart
new file mode 100644
index 0000000..baa6737
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_macos/test/test_api.g.dart
@@ -0,0 +1,147 @@
+// 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 (v5.0.0), 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
+import 'dart:async';
+import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
+import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:shared_preferences_macos/messages.g.dart';
+
+abstract class TestUserDefaultsApi {
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+ void remove(String key);
+
+ void setBool(String key, bool value);
+
+ void setDouble(String key, double value);
+
+ void setValue(String key, Object value);
+
+ Map<String?, Object?> getAll();
+
+ void clear();
+
+ static void setup(TestUserDefaultsApi? api,
+ {BinaryMessenger? binaryMessenger}) {
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.remove', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.remove was null.');
+ final List<Object?> args = (message as List<Object?>?)!;
+ final String? arg_key = (args[0] as String?);
+ assert(arg_key != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.remove was null, expected non-null String.');
+ api.remove(arg_key!);
+ return <Object?>[];
+ });
+ }
+ }
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.setBool', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setBool was null.');
+ final List<Object?> args = (message as List<Object?>?)!;
+ final String? arg_key = (args[0] as String?);
+ assert(arg_key != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setBool was null, expected non-null String.');
+ final bool? arg_value = (args[1] as bool?);
+ assert(arg_value != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setBool was null, expected non-null bool.');
+ api.setBool(arg_key!, arg_value!);
+ return <Object?>[];
+ });
+ }
+ }
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.setDouble', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setDouble was null.');
+ final List<Object?> args = (message as List<Object?>?)!;
+ final String? arg_key = (args[0] as String?);
+ assert(arg_key != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setDouble was null, expected non-null String.');
+ final double? arg_value = (args[1] as double?);
+ assert(arg_value != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setDouble was null, expected non-null double.');
+ api.setDouble(arg_key!, arg_value!);
+ return <Object?>[];
+ });
+ }
+ }
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.setValue', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setValue was null.');
+ final List<Object?> args = (message as List<Object?>?)!;
+ final String? arg_key = (args[0] as String?);
+ assert(arg_key != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setValue was null, expected non-null String.');
+ final Object? arg_value = (args[1] as Object?);
+ assert(arg_value != null,
+ 'Argument for dev.flutter.pigeon.UserDefaultsApi.setValue was null, expected non-null Object.');
+ api.setValue(arg_key!, arg_value!);
+ return <Object?>[];
+ });
+ }
+ }
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ // ignore message
+ final Map<String?, Object?> output = api.getAll();
+ return <Object?>[output];
+ });
+ }
+ }
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ // ignore message
+ api.clear();
+ return <Object?>[];
+ });
+ }
+ }
+ }
+}