From db43da5ccd6095212d81ef6cbd0bb9b5def666fe Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 28 Oct 2022 13:14:35 -0400 Subject: [PATCH 1/4] [path_provider] Switch to Pigeon for macOS Converts from direct method channel use to the new experimental Swift generator. Also switches from a one-call-per-method approach to a single method with an enum, since it's easy to do that in a maintainable way with Pigeon (unlike manual method channels, where keeping enum indexes in sync across the language boundary is error-prone, and requires manual int/enum conversion). --- .../path_provider_macos/CHANGELOG.md | 3 +- .../macos/RunnerTests/RunnerTests.swift | 42 +------ .../path_provider_macos/lib/messages.g.dart | 52 ++++++++ .../lib/path_provider_macos.dart | 20 ++-- .../macos/Classes/PathProviderPlugin.swift | 44 +++---- .../macos/Classes/messages.g.swift | 62 ++++++++++ .../path_provider_macos/pigeons/copyright.txt | 3 + .../path_provider_macos/pigeons/messages.dart | 24 ++++ .../path_provider_macos/pubspec.yaml | 5 +- .../test/messages_test.g.dart | 45 +++++++ .../test/path_provider_macos_test.dart | 112 ++++++++---------- .../test/path_provider_macos_test.mocks.dart | 37 ++++++ 12 files changed, 316 insertions(+), 133 deletions(-) create mode 100644 packages/path_provider/path_provider_macos/lib/messages.g.dart create mode 100644 packages/path_provider/path_provider_macos/macos/Classes/messages.g.swift create mode 100644 packages/path_provider/path_provider_macos/pigeons/copyright.txt create mode 100644 packages/path_provider/path_provider_macos/pigeons/messages.dart create mode 100644 packages/path_provider/path_provider_macos/test/messages_test.g.dart create mode 100644 packages/path_provider/path_provider_macos/test/path_provider_macos_test.mocks.dart diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index 61727e4d364b..211a59b03eff 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.0.7 +* Switches platform channel implementation to Pigeon. * Updates minimum Flutter version to 2.10. ## 2.0.6 diff --git a/packages/path_provider/path_provider_macos/example/macos/RunnerTests/RunnerTests.swift b/packages/path_provider/path_provider_macos/example/macos/RunnerTests/RunnerTests.swift index 35704cdb06d8..1fb4677b5cc6 100644 --- a/packages/path_provider/path_provider_macos/example/macos/RunnerTests/RunnerTests.swift +++ b/packages/path_provider/path_provider_macos/example/macos/RunnerTests/RunnerTests.swift @@ -4,18 +4,12 @@ import FlutterMacOS import XCTest -import path_provider_macos +@testable import path_provider_macos class RunnerTests: XCTestCase { func testGetTemporaryDirectory() throws { let plugin = PathProviderPlugin() - var path: String? - plugin.handle( - FlutterMethodCall(methodName: "getTemporaryDirectory", arguments: nil), - result: { (result: Any?) -> Void in - path = result as? String - - }) + let path = plugin.getDirectoryPath(type: .temp) XCTAssertEqual( path, NSSearchPathForDirectoriesInDomains( @@ -27,13 +21,7 @@ class RunnerTests: XCTestCase { func testGetApplicationDocumentsDirectory() throws { let plugin = PathProviderPlugin() - var path: String? - plugin.handle( - FlutterMethodCall(methodName: "getApplicationDocumentsDirectory", arguments: nil), - result: { (result: Any?) -> Void in - path = result as? String - - }) + let path = plugin.getDirectoryPath(type: .applicationDocuments) XCTAssertEqual( path, NSSearchPathForDirectoriesInDomains( @@ -45,13 +33,7 @@ class RunnerTests: XCTestCase { func testGetApplicationSupportDirectory() throws { let plugin = PathProviderPlugin() - var path: String? - plugin.handle( - FlutterMethodCall(methodName: "getApplicationSupportDirectory", arguments: nil), - result: { (result: Any?) -> Void in - path = result as? String - - }) + let path = plugin.getDirectoryPath(type: .applicationSupport) // The application support directory path should be the system application support // path with an added subdirectory based on the app name. XCTAssert( @@ -66,13 +48,7 @@ class RunnerTests: XCTestCase { func testGetLibraryDirectory() throws { let plugin = PathProviderPlugin() - var path: String? - plugin.handle( - FlutterMethodCall(methodName: "getLibraryDirectory", arguments: nil), - result: { (result: Any?) -> Void in - path = result as? String - - }) + let path = plugin.getDirectoryPath(type: .library) XCTAssertEqual( path, NSSearchPathForDirectoriesInDomains( @@ -84,13 +60,7 @@ class RunnerTests: XCTestCase { func testGetDownloadsDirectory() throws { let plugin = PathProviderPlugin() - var path: String? - plugin.handle( - FlutterMethodCall(methodName: "getDownloadsDirectory", arguments: nil), - result: { (result: Any?) -> Void in - path = result as? String - - }) + let path = plugin.getDirectoryPath(type: .downloads) XCTAssertEqual( path, NSSearchPathForDirectoriesInDomains( diff --git a/packages/path_provider/path_provider_macos/lib/messages.g.dart b/packages/path_provider/path_provider_macos/lib/messages.g.dart new file mode 100644 index 000000000000..0a0ec53379e9 --- /dev/null +++ b/packages/path_provider/path_provider_macos/lib/messages.g.dart @@ -0,0 +1,52 @@ +// 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 (v4.2.3), 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'; + +enum DirectoryType { + applicationDocuments, + applicationSupport, + downloads, + library, + temp, +} + + +class PathProviderApi { + /// Constructor for [PathProviderApi]. 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. + PathProviderApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + Future getDirectoryPath(DirectoryType arg_type) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.PathProviderApi.getDirectoryPath', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_type.index]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as String?); + } + } +} diff --git a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart index 5dc3176e9b89..7c2aaea1f9c6 100644 --- a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart +++ b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart @@ -8,12 +8,11 @@ import 'package:flutter/foundation.dart' show visibleForTesting; import 'package:flutter/services.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; +import 'messages.g.dart'; + /// The macOS implementation of [PathProviderPlatform]. class PathProviderMacOS extends PathProviderPlatform { - /// The method channel used to interact with the native platform. - @visibleForTesting - MethodChannel methodChannel = - const MethodChannel('plugins.flutter.io/path_provider_macos'); + final PathProviderApi _pathProvider = PathProviderApi(); /// Registers this class as the default instance of [PathProviderPlatform] static void registerWith() { @@ -22,13 +21,13 @@ class PathProviderMacOS extends PathProviderPlatform { @override Future getTemporaryPath() { - return methodChannel.invokeMethod('getTemporaryDirectory'); + return _pathProvider.getDirectoryPath(DirectoryType.temp); } @override Future getApplicationSupportPath() async { - final String? path = await methodChannel - .invokeMethod('getApplicationSupportDirectory'); + final String? path = + await _pathProvider.getDirectoryPath(DirectoryType.applicationSupport); if (path != null) { // Ensure the directory exists before returning it, for consistency with // other platforms. @@ -39,13 +38,12 @@ class PathProviderMacOS extends PathProviderPlatform { @override Future getLibraryPath() { - return methodChannel.invokeMethod('getLibraryDirectory'); + return _pathProvider.getDirectoryPath(DirectoryType.library); } @override Future getApplicationDocumentsPath() { - return methodChannel - .invokeMethod('getApplicationDocumentsDirectory'); + return _pathProvider.getDirectoryPath(DirectoryType.applicationDocuments); } @override @@ -67,6 +65,6 @@ class PathProviderMacOS extends PathProviderPlatform { @override Future getDownloadsPath() { - return methodChannel.invokeMethod('getDownloadsDirectory'); + return _pathProvider.getDirectoryPath(DirectoryType.downloads); } } diff --git a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift index e138eee759ac..9d43ce7ee7a7 100644 --- a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift +++ b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift @@ -5,39 +5,41 @@ import FlutterMacOS import Foundation -public class PathProviderPlugin: NSObject, FlutterPlugin { +public class PathProviderPlugin: NSObject, FlutterPlugin, PathProviderApi { public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel( - name: "plugins.flutter.io/path_provider_macos", - binaryMessenger: registrar.messenger) let instance = PathProviderPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) + PathProviderApiSetup.setUp(binaryMessenger: registrar.messenger, api: instance) } - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "getTemporaryDirectory": - result(getDirectory(ofType: FileManager.SearchPathDirectory.cachesDirectory)) - case "getApplicationDocumentsDirectory": - result(getDirectory(ofType: FileManager.SearchPathDirectory.documentDirectory)) - case "getApplicationSupportDirectory": - var path = getDirectory(ofType: FileManager.SearchPathDirectory.applicationSupportDirectory) + func getDirectoryPath(type: DirectoryType) -> String? { + var path = getDirectory(ofType: fileManagerDirectoryForType(type)) + if type == .applicationSupport { if let basePath = path { let basePathURL = URL.init(fileURLWithPath: basePath) path = basePathURL.appendingPathComponent(Bundle.main.bundleIdentifier!).path } - result(path) - case "getLibraryDirectory": - result(getDirectory(ofType: FileManager.SearchPathDirectory.libraryDirectory)) - case "getDownloadsDirectory": - result(getDirectory(ofType: FileManager.SearchPathDirectory.downloadsDirectory)) - default: - result(FlutterMethodNotImplemented) } + return path } } -/// Returns the user-domain director of the given type. +/// Returns the FileManager constant corresponding to the given type. +private func fileManagerDirectoryForType(_ type: DirectoryType) -> FileManager.SearchPathDirectory { + switch type { + case .applicationDocuments: + return FileManager.SearchPathDirectory.documentDirectory + case .applicationSupport: + return FileManager.SearchPathDirectory.applicationSupportDirectory + case .downloads: + return FileManager.SearchPathDirectory.downloadsDirectory + case .library: + return FileManager.SearchPathDirectory.libraryDirectory + case .temp: + return FileManager.SearchPathDirectory.cachesDirectory + } +} + +/// Returns the user-domain directory of the given type. private func getDirectory(ofType directory: FileManager.SearchPathDirectory) -> String? { let paths = NSSearchPathForDirectoriesInDomains( directory, diff --git a/packages/path_provider/path_provider_macos/macos/Classes/messages.g.swift b/packages/path_provider/path_provider_macos/macos/Classes/messages.g.swift new file mode 100644 index 000000000000..f815cd2a8fa1 --- /dev/null +++ b/packages/path_provider/path_provider_macos/macos/Classes/messages.g.swift @@ -0,0 +1,62 @@ +// 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 (v4.2.3), 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. + +enum DirectoryType: Int { + case applicationDocuments = 0 + case applicationSupport = 1 + case downloads = 2 + case library = 3 + case temp = 4 +} +///Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol PathProviderApi { + func getDirectoryPath(type: DirectoryType) -> String? +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class PathProviderApiSetup { + /// The codec used by PathProviderApi. + /// Sets up an instance of `PathProviderApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: PathProviderApi?) { + let getDirectoryPathChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.PathProviderApi.getDirectoryPath", binaryMessenger: binaryMessenger) + if let api = api { + getDirectoryPathChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let typeArg = DirectoryType(rawValue: args[0] as! Int)! + let result = api.getDirectoryPath(type: typeArg) + reply(wrapResult(result)) + } + } else { + getDirectoryPathChannel.setMessageHandler(nil) + } + } +} + +private func wrapResult(_ result: Any?) -> [String: Any?] { + return ["result": result] +} + +private func wrapError(_ error: FlutterError) -> [String: Any?] { + return [ + "error": [ + "code": error.code, + "message": error.message, + "details": error.details + ] + ] +} diff --git a/packages/path_provider/path_provider_macos/pigeons/copyright.txt b/packages/path_provider/path_provider_macos/pigeons/copyright.txt new file mode 100644 index 000000000000..1236b63caf3a --- /dev/null +++ b/packages/path_provider/path_provider_macos/pigeons/copyright.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. diff --git a/packages/path_provider/path_provider_macos/pigeons/messages.dart b/packages/path_provider/path_provider_macos/pigeons/messages.dart new file mode 100644 index 000000000000..8c82ab4fcf14 --- /dev/null +++ b/packages/path_provider/path_provider_macos/pigeons/messages.dart @@ -0,0 +1,24 @@ +// 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( + input: 'pigeons/messages.dart', + swiftOut: 'macos/Classes/messages.g.swift', + dartOut: 'lib/messages.g.dart', + dartTestOut: 'test/messages_test.g.dart', + copyrightHeader: 'pigeons/copyright.txt', +)) +enum DirectoryType { + applicationDocuments, + applicationSupport, + downloads, + library, + temp, +} + +@HostApi(dartHostTestHandler: 'TestPathProviderApi') +abstract class PathProviderApi { + String? getDirectoryPath(DirectoryType type); +} diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index 289e13103ddd..f15ee5e086b6 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider_macos description: macOS implementation of the path_provider plugin repository: https://github.com/flutter/plugins/tree/main/packages/path_provider/path_provider_macos issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 -version: 2.0.6 +version: 2.0.7 environment: sdk: ">=2.12.0 <3.0.0" @@ -22,6 +22,9 @@ dependencies: path_provider_platform_interface: ^2.0.1 dev_dependencies: + build_runner: ^2.3.2 flutter_test: sdk: flutter + mockito: ^5.3.2 path: ^1.8.0 + pigeon: ^4.2.3 diff --git a/packages/path_provider/path_provider_macos/test/messages_test.g.dart b/packages/path_provider/path_provider_macos/test/messages_test.g.dart new file mode 100644 index 000000000000..ebeddb7827bb --- /dev/null +++ b/packages/path_provider/path_provider_macos/test/messages_test.g.dart @@ -0,0 +1,45 @@ +// 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 (v4.2.3), 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:path_provider_macos/messages.g.dart'; + +abstract class TestPathProviderApi { + static const MessageCodec codec = StandardMessageCodec(); + + String? getDirectoryPath(DirectoryType type); + static void setup(TestPathProviderApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.PathProviderApi.getDirectoryPath', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.PathProviderApi.getDirectoryPath was null.'); + final List args = (message as List?)!; + // Manually changed to work around + // https://github.com/flutter/flutter/issues/105742. + final DirectoryType? arg_type = + args[0] == null ? null : DirectoryType.values[args[0] as int]; + assert(arg_type != null, + 'Argument for dev.flutter.pigeon.PathProviderApi.getDirectoryPath was null, expected non-null DirectoryType.'); + final String? output = api.getDirectoryPath(arg_type!); + return {'result': output}; + }); + } + } + } +} diff --git a/packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart b/packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart index 7e783aad24e9..1bd64477f960 100644 --- a/packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart +++ b/packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart @@ -4,61 +4,33 @@ import 'dart:io'; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; import 'package:path/path.dart' as p; +import 'package:path_provider_macos/messages.g.dart'; import 'package:path_provider_macos/path_provider_macos.dart'; +import 'messages_test.g.dart'; +import 'path_provider_macos_test.mocks.dart'; + +@GenerateMocks([TestPathProviderApi]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('PathProviderMacOS', () { late PathProviderMacOS pathProvider; - late List log; + late MockTestPathProviderApi mockApi; // These unit tests use the actual filesystem, since an injectable // filesystem would add a runtime dependency to the package, so everything // is contained to a temporary directory. late Directory testRoot; - late String temporaryPath; - late String applicationSupportPath; - late String libraryPath; - late String applicationDocumentsPath; - late String downloadsPath; - setUp(() async { - pathProvider = PathProviderMacOS(); - testRoot = Directory.systemTemp.createTempSync(); - final String basePath = testRoot.path; - temporaryPath = p.join(basePath, 'temporary', 'path'); - applicationSupportPath = - p.join(basePath, 'application', 'support', 'path'); - libraryPath = p.join(basePath, 'library', 'path'); - applicationDocumentsPath = - p.join(basePath, 'application', 'documents', 'path'); - downloadsPath = p.join(basePath, 'downloads', 'path'); - - log = []; - TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger - .setMockMethodCallHandler(pathProvider.methodChannel, - (MethodCall methodCall) async { - log.add(methodCall); - switch (methodCall.method) { - case 'getTemporaryDirectory': - return temporaryPath; - case 'getApplicationSupportDirectory': - return applicationSupportPath; - case 'getLibraryDirectory': - return libraryPath; - case 'getApplicationDocumentsDirectory': - return applicationDocumentsPath; - case 'getDownloadsDirectory': - return downloadsPath; - default: - return null; - } - }); + pathProvider = PathProviderMacOS(); + mockApi = MockTestPathProviderApi(); + TestPathProviderApi.setup(mockApi); }); tearDown(() { @@ -66,57 +38,71 @@ void main() { }); test('getTemporaryPath', () async { + final String temporaryPath = p.join(testRoot.path, 'temporary', 'path'); + when(mockApi.getDirectoryPath(DirectoryType.temp)) + .thenReturn(temporaryPath); + final String? path = await pathProvider.getTemporaryPath(); - expect( - log, - [isMethodCall('getTemporaryDirectory', arguments: null)], - ); + + verify(mockApi.getDirectoryPath(DirectoryType.temp)); expect(path, temporaryPath); }); test('getApplicationSupportPath', () async { + final String applicationSupportPath = + p.join(testRoot.path, 'application', 'support', 'path'); + when(mockApi.getDirectoryPath(DirectoryType.applicationSupport)) + .thenReturn(applicationSupportPath); + final String? path = await pathProvider.getApplicationSupportPath(); - expect( - log, - [ - isMethodCall('getApplicationSupportDirectory', arguments: null) - ], - ); + + verify(mockApi.getDirectoryPath(DirectoryType.applicationSupport)); expect(path, applicationSupportPath); }); test('getApplicationSupportPath creates the directory if necessary', () async { + final String applicationSupportPath = + p.join(testRoot.path, 'application', 'support', 'path'); + when(mockApi.getDirectoryPath(DirectoryType.applicationSupport)) + .thenReturn(applicationSupportPath); + final String? path = await pathProvider.getApplicationSupportPath(); + expect(Directory(path!).existsSync(), isTrue); }); test('getLibraryPath', () async { + final String libraryPath = p.join(testRoot.path, 'library', 'path'); + when(mockApi.getDirectoryPath(DirectoryType.library)) + .thenReturn(libraryPath); + final String? path = await pathProvider.getLibraryPath(); - expect( - log, - [isMethodCall('getLibraryDirectory', arguments: null)], - ); + + verify(mockApi.getDirectoryPath(DirectoryType.library)); expect(path, libraryPath); }); test('getApplicationDocumentsPath', () async { + final String applicationDocumentsPath = + p.join(testRoot.path, 'application', 'documents', 'path'); + when(mockApi.getDirectoryPath(DirectoryType.applicationDocuments)) + .thenReturn(applicationDocumentsPath); + final String? path = await pathProvider.getApplicationDocumentsPath(); - expect( - log, - [ - isMethodCall('getApplicationDocumentsDirectory', arguments: null) - ], - ); + + verify(mockApi.getDirectoryPath(DirectoryType.applicationDocuments)); expect(path, applicationDocumentsPath); }); test('getDownloadsPath', () async { + final String downloadsPath = p.join(testRoot.path, 'downloads', 'path'); + when(mockApi.getDirectoryPath(DirectoryType.downloads)) + .thenReturn(downloadsPath); + final String? result = await pathProvider.getDownloadsPath(); - expect( - log, - [isMethodCall('getDownloadsDirectory', arguments: null)], - ); + + verify(mockApi.getDirectoryPath(DirectoryType.downloads)); expect(result, downloadsPath); }); diff --git a/packages/path_provider/path_provider_macos/test/path_provider_macos_test.mocks.dart b/packages/path_provider/path_provider_macos/test/path_provider_macos_test.mocks.dart new file mode 100644 index 000000000000..eff00f754bd8 --- /dev/null +++ b/packages/path_provider/path_provider_macos/test/path_provider_macos_test.mocks.dart @@ -0,0 +1,37 @@ +// Mocks generated by Mockito 5.3.2 from annotations +// in path_provider_macos/test/path_provider_macos_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:mockito/mockito.dart' as _i1; +import 'package:path_provider_macos/messages.g.dart' as _i3; + +import 'messages_test.g.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [TestPathProviderApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestPathProviderApi extends _i1.Mock + implements _i2.TestPathProviderApi { + MockTestPathProviderApi() { + _i1.throwOnMissingStub(this); + } + + @override + String? getDirectoryPath(_i3.DirectoryType? type) => + (super.noSuchMethod(Invocation.method( + #getDirectoryPath, + [type], + )) as String?); +} From f3bf0a0faed9fa0e95d3af3b04c5cd528155e1de Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 28 Oct 2022 14:02:09 -0400 Subject: [PATCH 2/4] Format --- .../path_provider_macos/lib/messages.g.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/path_provider/path_provider_macos/lib/messages.g.dart b/packages/path_provider/path_provider_macos/lib/messages.g.dart index 0a0ec53379e9..42b6db06285a 100644 --- a/packages/path_provider/path_provider_macos/lib/messages.g.dart +++ b/packages/path_provider/path_provider_macos/lib/messages.g.dart @@ -18,19 +18,20 @@ enum DirectoryType { temp, } - class PathProviderApi { /// Constructor for [PathProviderApi]. 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. - PathProviderApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + PathProviderApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; static const MessageCodec codec = StandardMessageCodec(); Future getDirectoryPath(DirectoryType arg_type) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.PathProviderApi.getDirectoryPath', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.PathProviderApi.getDirectoryPath', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_type.index]) as Map?; if (replyMap == null) { @@ -39,7 +40,8 @@ class PathProviderApi { message: 'Unable to establish connection on channel.', ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, From f3d36a9b23134941090e52a36d03b24a31c6cf0d Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 28 Oct 2022 14:02:21 -0400 Subject: [PATCH 3/4] Analyzer --- .../path_provider_macos/lib/path_provider_macos.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart index 7c2aaea1f9c6..7563beacd1ff 100644 --- a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart +++ b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart @@ -4,8 +4,6 @@ import 'dart:io'; -import 'package:flutter/foundation.dart' show visibleForTesting; -import 'package:flutter/services.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; import 'messages.g.dart'; From fa1eac4d51ea0fadc65edb51c5469a8085b87109 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 10 Jan 2023 16:15:10 -0500 Subject: [PATCH 4/4] Update to latest version of Pigeon --- .../path_provider_macos/lib/messages.g.dart | 20 +++++++++---------- .../macos/Classes/messages.g.swift | 18 ++++++++--------- .../path_provider_macos/pubspec.yaml | 2 +- .../test/messages_test.g.dart | 7 +++---- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/packages/path_provider/path_provider_macos/lib/messages.g.dart b/packages/path_provider/path_provider_macos/lib/messages.g.dart index 42b6db06285a..81a9cd5cc525 100644 --- a/packages/path_provider/path_provider_macos/lib/messages.g.dart +++ b/packages/path_provider/path_provider_macos/lib/messages.g.dart @@ -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 (v4.2.3), do not edit directly. +// 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'; @@ -32,23 +32,21 @@ class PathProviderApi { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.PathProviderApi.getDirectoryPath', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_type.index]) as Map?; - if (replyMap == null) { + final List? replyList = + await channel.send([arg_type.index]) as List?; + if (replyList == null) { throw PlatformException( code: 'channel-error', message: 'Unable to establish connection on channel.', ); - } else if (replyMap['error'] != null) { - final Map error = - (replyMap['error'] as Map?)!; + } else if (replyList.length > 1) { throw PlatformException( - code: (error['code'] as String?)!, - message: error['message'] as String?, - details: error['details'], + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], ); } else { - return (replyMap['result'] as String?); + return (replyList[0] as String?); } } } diff --git a/packages/path_provider/path_provider_macos/macos/Classes/messages.g.swift b/packages/path_provider/path_provider_macos/macos/Classes/messages.g.swift index f815cd2a8fa1..08ab62aafdb7 100644 --- a/packages/path_provider/path_provider_macos/macos/Classes/messages.g.swift +++ b/packages/path_provider/path_provider_macos/macos/Classes/messages.g.swift @@ -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 (v4.2.3), do not edit directly. +// Autogenerated from Pigeon (v5.0.0), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation @@ -23,7 +23,7 @@ enum DirectoryType: Int { case library = 3 case temp = 4 } -///Generated protocol from Pigeon that represents a handler of messages from Flutter. +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. protocol PathProviderApi { func getDirectoryPath(type: DirectoryType) -> String? } @@ -47,16 +47,14 @@ class PathProviderApiSetup { } } -private func wrapResult(_ result: Any?) -> [String: Any?] { - return ["result": result] +private func wrapResult(_ result: Any?) -> [Any?] { + return [result] } -private func wrapError(_ error: FlutterError) -> [String: Any?] { +private func wrapError(_ error: FlutterError) -> [Any?] { return [ - "error": [ - "code": error.code, - "message": error.message, - "details": error.details - ] + error.code, + error.message, + error.details ] } diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index f15ee5e086b6..2722d26c4b68 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -27,4 +27,4 @@ dev_dependencies: sdk: flutter mockito: ^5.3.2 path: ^1.8.0 - pigeon: ^4.2.3 + pigeon: ^5.0.0 diff --git a/packages/path_provider/path_provider_macos/test/messages_test.g.dart b/packages/path_provider/path_provider_macos/test/messages_test.g.dart index ebeddb7827bb..b0f3c1a2a069 100644 --- a/packages/path_provider/path_provider_macos/test/messages_test.g.dart +++ b/packages/path_provider/path_provider_macos/test/messages_test.g.dart @@ -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 (v4.2.3), do not edit directly. +// 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 @@ -17,6 +17,7 @@ abstract class TestPathProviderApi { static const MessageCodec codec = StandardMessageCodec(); String? getDirectoryPath(DirectoryType type); + static void setup(TestPathProviderApi? api, {BinaryMessenger? binaryMessenger}) { { @@ -30,14 +31,12 @@ abstract class TestPathProviderApi { assert(message != null, 'Argument for dev.flutter.pigeon.PathProviderApi.getDirectoryPath was null.'); final List args = (message as List?)!; - // Manually changed to work around - // https://github.com/flutter/flutter/issues/105742. final DirectoryType? arg_type = args[0] == null ? null : DirectoryType.values[args[0] as int]; assert(arg_type != null, 'Argument for dev.flutter.pigeon.PathProviderApi.getDirectoryPath was null, expected non-null DirectoryType.'); final String? output = api.getDirectoryPath(arg_type!); - return {'result': output}; + return [output]; }); } }