Skip to content

Commit

Permalink
[shared_preferences] Convert macOS to Pigeon (flutter#6914)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
stuartmorgan authored Jan 6, 2023
1 parent 3a6f63b commit 276cfd4
Show file tree
Hide file tree
Showing 11 changed files with 652 additions and 233 deletions.
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,85 +4,55 @@

import FlutterMacOS
import XCTest
import shared_preferences_macos
@testable import shared_preferences_macos

class RunnerTests: XCTestCase {
func testHandlesCommitNoOp() throws {
func testSetAndGet() 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)

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 testSetAndGet() throws {
func testRemove() 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)
})
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)

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)
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?)
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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},
))!;
Future<bool> clear() async {
await _api.clear();
return true;
}

@override
Future<bool> setValue(String valueType, String key, Object value) async {
return (await _kChannel.invokeMethod<bool>(
'set$valueType',
<String, dynamic>{'key': key, 'value': value},
))!;
Future<Map<String, Object>> getAll() async {
final Map<String?, Object?> result = await _api.getAll();
return result.cast<String, Object>();
}

@override
Future<bool> clear() async {
return (await _kChannel.invokeMethod<bool>('clear'))!;
Future<bool> remove(String key) async {
await _api.remove(key);
return true;
}

@override
Future<Map<String, Object>> getAll() async {
final Map<String, Object>? preferences =
await _kChannel.invokeMapMethod<String, Object>('getAll');

if (preferences == null) {
return <String, Object>{};
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;
}
}
Loading

0 comments on commit 276cfd4

Please sign in to comment.