From 016a99d0c22fc2e5c7791db2c1fe67f1d54758af Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 28 Oct 2025 14:54:41 -0400 Subject: [PATCH 1/4] Remove cruft from Linux --- .../file_selector/file_selector_linux/pigeons/messages.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/file_selector/file_selector_linux/pigeons/messages.dart b/packages/file_selector/file_selector_linux/pigeons/messages.dart index 6427602ce5c..658450c2477 100644 --- a/packages/file_selector/file_selector_linux/pigeons/messages.dart +++ b/packages/file_selector/file_selector_linux/pigeons/messages.dart @@ -52,7 +52,7 @@ class PlatformFileChooserOptions { final bool? selectMultiple; } -@HostApi(dartHostTestHandler: 'TestFileSelectorApi') +@HostApi() abstract class FileSelectorApi { /// Shows an file chooser with the given [type] and [options], returning the /// list of selected paths. From 991b1c0d05fd3d361c201d5707eac65081a035f8 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 28 Oct 2025 15:06:42 -0400 Subject: [PATCH 2/4] Update iOS to use a simple fake --- .../lib/file_selector_ios.dart | 7 +- .../file_selector_ios/pigeons/messages.dart | 3 +- .../file_selector_ios/pubspec.yaml | 2 - .../test/file_selector_ios_test.dart | 94 +++++++++------- .../test/file_selector_ios_test.mocks.dart | 42 -------- .../file_selector_ios/test/test_api.g.dart | 100 ------------------ 6 files changed, 60 insertions(+), 188 deletions(-) delete mode 100644 packages/file_selector/file_selector_ios/test/file_selector_ios_test.mocks.dart delete mode 100644 packages/file_selector/file_selector_ios/test/test_api.g.dart diff --git a/packages/file_selector/file_selector_ios/lib/file_selector_ios.dart b/packages/file_selector/file_selector_ios/lib/file_selector_ios.dart index d7718dbc9f8..ac2af48c7bc 100644 --- a/packages/file_selector/file_selector_ios/lib/file_selector_ios.dart +++ b/packages/file_selector/file_selector_ios/lib/file_selector_ios.dart @@ -3,12 +3,17 @@ // found in the LICENSE file. import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/foundation.dart' show visibleForTesting; import 'src/messages.g.dart'; /// An implementation of [FileSelectorPlatform] for iOS. class FileSelectorIOS extends FileSelectorPlatform { - final FileSelectorApi _hostApi = FileSelectorApi(); + /// Creates a new plugin implementation instance. + FileSelectorIOS({@visibleForTesting FileSelectorApi? api}) + : _hostApi = api ?? FileSelectorApi(); + + final FileSelectorApi _hostApi; /// Registers the iOS implementation. static void registerWith() { diff --git a/packages/file_selector/file_selector_ios/pigeons/messages.dart b/packages/file_selector/file_selector_ios/pigeons/messages.dart index c3663ccb9f4..857e888c284 100644 --- a/packages/file_selector/file_selector_ios/pigeons/messages.dart +++ b/packages/file_selector/file_selector_ios/pigeons/messages.dart @@ -7,7 +7,6 @@ import 'package:pigeon/pigeon.dart'; @ConfigurePigeon( PigeonOptions( dartOut: 'lib/src/messages.g.dart', - dartTestOut: 'test/test_api.g.dart', swiftOut: 'ios/file_selector_ios/Sources/file_selector_ios/messages.g.swift', copyrightHeader: 'pigeons/copyright.txt', @@ -22,7 +21,7 @@ class FileSelectorConfig { bool allowMultiSelection; } -@HostApi(dartHostTestHandler: 'TestFileSelectorApi') +@HostApi() abstract class FileSelectorApi { @async @ObjCSelector('openFileSelectorWithConfig:') diff --git a/packages/file_selector/file_selector_ios/pubspec.yaml b/packages/file_selector/file_selector_ios/pubspec.yaml index 62ee5ff3594..42a3c85ae78 100644 --- a/packages/file_selector/file_selector_ios/pubspec.yaml +++ b/packages/file_selector/file_selector_ios/pubspec.yaml @@ -22,10 +22,8 @@ dependencies: sdk: flutter dev_dependencies: - build_runner: ^2.3.0 flutter_test: sdk: flutter - mockito: ^5.4.4 pigeon: ^25.5.0 topics: diff --git a/packages/file_selector/file_selector_ios/test/file_selector_ios_test.dart b/packages/file_selector/file_selector_ios/test/file_selector_ios_test.dart index 2cf886a6ef9..e19dc3fa6ff 100644 --- a/packages/file_selector/file_selector_ios/test/file_selector_ios_test.dart +++ b/packages/file_selector/file_selector_ios/test/file_selector_ios_test.dart @@ -6,23 +6,18 @@ import 'package:file_selector_ios/file_selector_ios.dart'; import 'package:file_selector_ios/src/messages.g.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; -import 'file_selector_ios_test.mocks.dart'; -import 'test_api.g.dart'; - -@GenerateMocks([TestFileSelectorApi]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final FileSelectorIOS plugin = FileSelectorIOS(); - late MockTestFileSelectorApi mockApi; + late FakeFileSelectorApi api; + late FileSelectorIOS plugin; setUp(() { - mockApi = MockTestFileSelectorApi(); - TestFileSelectorApi.setUp(mockApi); + api = FakeFileSelectorApi(); + plugin = FileSelectorIOS(api: api); }); test('registered instance', () { @@ -32,7 +27,7 @@ void main() { group('openFile', () { setUp(() { - when(mockApi.openFile(any)).thenAnswer((_) async => ['foo']); + api.result = ['foo']; }); test('passes the accepted type groups correctly', () async { @@ -53,16 +48,15 @@ void main() { await plugin.openFile(acceptedTypeGroups: [group, groupTwo]); - final VerificationResult result = verify(mockApi.openFile(captureAny)); - final FileSelectorConfig config = - result.captured[0] as FileSelectorConfig; - // iOS only accepts uniformTypeIdentifiers. expect( - listEquals(config.utis, ['public.text', 'public.image']), + listEquals(api.passedConfig?.utis, [ + 'public.text', + 'public.image', + ]), isTrue, ); - expect(config.allowMultiSelection, isFalse); + expect(api.passedConfig?.allowMultiSelection, isFalse); }); test('throws for a type group that does not support iOS', () async { const XTypeGroup group = XTypeGroup( @@ -78,10 +72,10 @@ void main() { test('correctly handles no type groups', () async { await expectLater(plugin.openFile(), completes); - final VerificationResult result = verify(mockApi.openFile(captureAny)); - final FileSelectorConfig config = - result.captured[0] as FileSelectorConfig; - expect(listEquals(config.utis, ['public.data']), isTrue); + expect( + listEquals(api.passedConfig?.utis, ['public.data']), + isTrue, + ); }); test('correctly handles a wildcard group', () async { @@ -91,16 +85,16 @@ void main() { plugin.openFile(acceptedTypeGroups: [group]), completes, ); - final VerificationResult result = verify(mockApi.openFile(captureAny)); - final FileSelectorConfig config = - result.captured[0] as FileSelectorConfig; - expect(listEquals(config.utis, ['public.data']), isTrue); + expect( + listEquals(api.passedConfig?.utis, ['public.data']), + isTrue, + ); }); }); group('openFiles', () { setUp(() { - when(mockApi.openFile(any)).thenAnswer((_) async => ['foo']); + api.result = ['foo']; }); test('passes the accepted type groups correctly', () async { @@ -121,16 +115,14 @@ void main() { await plugin.openFiles(acceptedTypeGroups: [group, groupTwo]); - final VerificationResult result = verify(mockApi.openFile(captureAny)); - final FileSelectorConfig config = - result.captured[0] as FileSelectorConfig; - - // iOS only accepts uniformTypeIdentifiers. expect( - listEquals(config.utis, ['public.text', 'public.image']), + listEquals(api.passedConfig?.utis, [ + 'public.text', + 'public.image', + ]), isTrue, ); - expect(config.allowMultiSelection, isTrue); + expect(api.passedConfig?.allowMultiSelection, isTrue); }); test('throws for a type group that does not support iOS', () async { @@ -147,10 +139,10 @@ void main() { test('correctly handles no type groups', () async { await expectLater(plugin.openFiles(), completes); - final VerificationResult result = verify(mockApi.openFile(captureAny)); - final FileSelectorConfig config = - result.captured[0] as FileSelectorConfig; - expect(listEquals(config.utis, ['public.data']), isTrue); + expect( + listEquals(api.passedConfig?.utis, ['public.data']), + isTrue, + ); }); test('correctly handles a wildcard group', () async { @@ -160,10 +152,30 @@ void main() { plugin.openFiles(acceptedTypeGroups: [group]), completes, ); - final VerificationResult result = verify(mockApi.openFile(captureAny)); - final FileSelectorConfig config = - result.captured[0] as FileSelectorConfig; - expect(listEquals(config.utis, ['public.data']), isTrue); + expect( + listEquals(api.passedConfig?.utis, ['public.data']), + isTrue, + ); }); }); } + +/// Fake implementation that stores arguments and provides a canned response. +class FakeFileSelectorApi implements FileSelectorApi { + List result = []; + FileSelectorConfig? passedConfig; + + @override + Future> openFile(FileSelectorConfig config) async { + passedConfig = config; + return result; + } + + @override + // ignore: non_constant_identifier_names + BinaryMessenger? get pigeonVar_binaryMessenger => null; + + @override + // ignore: non_constant_identifier_names + String get pigeonVar_messageChannelSuffix => ''; +} diff --git a/packages/file_selector/file_selector_ios/test/file_selector_ios_test.mocks.dart b/packages/file_selector/file_selector_ios/test/file_selector_ios_test.mocks.dart deleted file mode 100644 index eac7136aabc..00000000000 --- a/packages/file_selector/file_selector_ios/test/file_selector_ios_test.mocks.dart +++ /dev/null @@ -1,42 +0,0 @@ -// Mocks generated by Mockito 5.4.4 from annotations -// in file_selector_ios/test/file_selector_ios_test.dart. -// Do not manually edit this file. - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i3; - -import 'package:file_selector_ios/src/messages.g.dart' as _i4; -import 'package:mockito/mockito.dart' as _i1; - -import 'test_api.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: deprecated_member_use -// ignore_for_file: deprecated_member_use_from_same_package -// 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 [TestFileSelectorApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockTestFileSelectorApi extends _i1.Mock - implements _i2.TestFileSelectorApi { - MockTestFileSelectorApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i3.Future> openFile(_i4.FileSelectorConfig? config) => - (super.noSuchMethod( - Invocation.method(#openFile, [config]), - returnValue: _i3.Future>.value([]), - ) - as _i3.Future>); -} diff --git a/packages/file_selector/file_selector_ios/test/test_api.g.dart b/packages/file_selector/file_selector_ios/test/test_api.g.dart deleted file mode 100644 index f2339365eac..00000000000 --- a/packages/file_selector/file_selector_ios/test/test_api.g.dart +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// Autogenerated from Pigeon (v25.5.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, no_leading_underscores_for_local_identifiers -// 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:file_selector_ios/src/messages.g.dart'; - -class _PigeonCodec extends StandardMessageCodec { - const _PigeonCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is FileSelectorConfig) { - buffer.putUint8(129); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 129: - return FileSelectorConfig.decode(readValue(buffer)!); - default: - return super.readValueOfType(type, buffer); - } - } -} - -abstract class TestFileSelectorApi { - static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => - TestDefaultBinaryMessengerBinding.instance; - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - Future> openFile(FileSelectorConfig config); - - static void setUp( - TestFileSelectorApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = messageChannelSuffix.isNotEmpty - ? '.$messageChannelSuffix' - : ''; - { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.file_selector_ios.FileSelectorApi.openFile$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, ( - Object? message, - ) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.file_selector_ios.FileSelectorApi.openFile was null.', - ); - final List args = (message as List?)!; - final FileSelectorConfig? arg_config = - (args[0] as FileSelectorConfig?); - assert( - arg_config != null, - 'Argument for dev.flutter.pigeon.file_selector_ios.FileSelectorApi.openFile was null, expected non-null FileSelectorConfig.', - ); - try { - final List output = await api.openFile(arg_config!); - return [output]; - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException( - code: 'error', - message: e.toString(), - ), - ); - } - }); - } - } - } -} From a3483861ca2cabaddfd59bf9819ef8ffda45eca4 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 28 Oct 2025 15:17:10 -0400 Subject: [PATCH 3/4] Update macOS to use a simple fake --- .../lib/file_selector_macos.dart | 7 +- .../file_selector_macos/pigeons/messages.dart | 3 +- .../file_selector_macos/pubspec.yaml | 2 - .../test/file_selector_macos_test.dart | 207 ++++++------------ .../test/file_selector_macos_test.mocks.dart | 50 ----- .../test/messages_test.g.dart | 163 -------------- 6 files changed, 78 insertions(+), 354 deletions(-) delete mode 100644 packages/file_selector/file_selector_macos/test/file_selector_macos_test.mocks.dart delete mode 100644 packages/file_selector/file_selector_macos/test/messages_test.g.dart diff --git a/packages/file_selector/file_selector_macos/lib/file_selector_macos.dart b/packages/file_selector/file_selector_macos/lib/file_selector_macos.dart index e9928d01df6..9b18cc88ac3 100644 --- a/packages/file_selector/file_selector_macos/lib/file_selector_macos.dart +++ b/packages/file_selector/file_selector_macos/lib/file_selector_macos.dart @@ -3,12 +3,17 @@ // found in the LICENSE file. import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/foundation.dart' show visibleForTesting; import 'src/messages.g.dart'; /// An implementation of [FileSelectorPlatform] for macOS. class FileSelectorMacOS extends FileSelectorPlatform { - final FileSelectorApi _hostApi = FileSelectorApi(); + /// Creates a new plugin implementation instance. + FileSelectorMacOS({@visibleForTesting FileSelectorApi? api}) + : _hostApi = api ?? FileSelectorApi(); + + final FileSelectorApi _hostApi; /// Registers the macOS implementation. static void registerWith() { diff --git a/packages/file_selector/file_selector_macos/pigeons/messages.dart b/packages/file_selector/file_selector_macos/pigeons/messages.dart index 3909fc58cb0..8da0ef9fd26 100644 --- a/packages/file_selector/file_selector_macos/pigeons/messages.dart +++ b/packages/file_selector/file_selector_macos/pigeons/messages.dart @@ -9,7 +9,6 @@ import 'package:pigeon/pigeon.dart'; swiftOut: 'macos/file_selector_macos/Sources/file_selector_macos/messages.g.swift', dartOut: 'lib/src/messages.g.dart', - dartTestOut: 'test/messages_test.g.dart', copyrightHeader: 'pigeons/copyright.txt', ), ) @@ -63,7 +62,7 @@ class OpenPanelOptions { final SavePanelOptions baseOptions; } -@HostApi(dartHostTestHandler: 'TestFileSelectorApi') +@HostApi() abstract class FileSelectorApi { /// Shows an open panel with the given [options], returning the list of /// selected paths. diff --git a/packages/file_selector/file_selector_macos/pubspec.yaml b/packages/file_selector/file_selector_macos/pubspec.yaml index d441597378c..02f0c7ed5e6 100644 --- a/packages/file_selector/file_selector_macos/pubspec.yaml +++ b/packages/file_selector/file_selector_macos/pubspec.yaml @@ -23,10 +23,8 @@ dependencies: sdk: flutter dev_dependencies: - build_runner: ^2.3.2 flutter_test: sdk: flutter - mockito: ^5.4.4 pigeon: ^25.5.0 topics: diff --git a/packages/file_selector/file_selector_macos/test/file_selector_macos_test.dart b/packages/file_selector/file_selector_macos/test/file_selector_macos_test.dart index a338e2926b7..edd4c2e2d7f 100644 --- a/packages/file_selector/file_selector_macos/test/file_selector_macos_test.dart +++ b/packages/file_selector/file_selector_macos/test/file_selector_macos_test.dart @@ -5,30 +5,18 @@ import 'package:file_selector_macos/file_selector_macos.dart'; import 'package:file_selector_macos/src/messages.g.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; -import 'file_selector_macos_test.mocks.dart'; -import 'messages_test.g.dart'; - -@GenerateMocks([TestFileSelectorApi]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); + late FakeFileSelectorApi api; late FileSelectorMacOS plugin; - late MockTestFileSelectorApi mockApi; setUp(() { - plugin = FileSelectorMacOS(); - mockApi = MockTestFileSelectorApi(); - TestFileSelectorApi.setUp(mockApi); - - // Set default stubs for tests that don't expect a specific return value, - // so calls don't throw. Tests that `expect` return values should override - // these locally. - when(mockApi.displayOpenPanel(any)).thenAnswer((_) async => []); - when(mockApi.displaySavePanel(any)).thenAnswer((_) async => null); + api = FakeFileSelectorApi(); + plugin = FileSelectorMacOS(api: api); }); test('registered instance', () { @@ -38,17 +26,12 @@ void main() { group('openFile', () { test('works as expected with no arguments', () async { - when( - mockApi.displayOpenPanel(any), - ).thenAnswer((_) async => ['foo']); + api.result = ['foo']; final XFile? file = await plugin.openFile(); expect(file!.path, 'foo'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.allowsMultipleSelection, false); expect(options.canChooseFiles, true); expect(options.canChooseDirectories, false); @@ -59,7 +42,7 @@ void main() { }); test('handles cancel', () async { - when(mockApi.displayOpenPanel(any)).thenAnswer((_) async => []); + api.result = []; final XFile? file = await plugin.openFile(); @@ -84,10 +67,7 @@ void main() { await plugin.openFile(acceptedTypeGroups: [group, groupTwo]); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.allowedFileTypes!.extensions, [ 'txt', 'jpg', @@ -105,20 +85,14 @@ void main() { test('passes initialDirectory correctly', () async { await plugin.openFile(initialDirectory: '/example/directory'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.directoryPath, '/example/directory'); }); test('passes confirmButtonText correctly', () async { await plugin.openFile(confirmButtonText: 'Open File'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.prompt, 'Open File'); }); @@ -146,18 +120,13 @@ void main() { group('openFiles', () { test('works as expected with no arguments', () async { - when( - mockApi.displayOpenPanel(any), - ).thenAnswer((_) async => ['foo', 'bar']); + api.result = ['foo', 'bar']; final List files = await plugin.openFiles(); expect(files[0].path, 'foo'); expect(files[1].path, 'bar'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.allowsMultipleSelection, true); expect(options.canChooseFiles, true); expect(options.canChooseDirectories, false); @@ -168,7 +137,7 @@ void main() { }); test('handles cancel', () async { - when(mockApi.displayOpenPanel(any)).thenAnswer((_) async => []); + api.result = []; final List files = await plugin.openFiles(); @@ -193,10 +162,7 @@ void main() { await plugin.openFiles(acceptedTypeGroups: [group, groupTwo]); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.allowedFileTypes!.extensions, [ 'txt', 'jpg', @@ -214,20 +180,14 @@ void main() { test('passes initialDirectory correctly', () async { await plugin.openFiles(initialDirectory: '/example/directory'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.directoryPath, '/example/directory'); }); test('passes confirmButtonText correctly', () async { await plugin.openFiles(confirmButtonText: 'Open File'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.prompt, 'Open File'); }); @@ -255,15 +215,12 @@ void main() { group('getSavePath (deprecated)', () { test('works as expected with no arguments', () async { - when(mockApi.displaySavePanel(any)).thenAnswer((_) async => 'foo'); + api.result = ['foo']; final String? path = await plugin.getSavePath(); expect(path, 'foo'); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.allowedFileTypes, null); expect(options.directoryPath, null); expect(options.nameFieldStringValue, null); @@ -271,7 +228,7 @@ void main() { }); test('handles cancel', () async { - when(mockApi.displaySavePanel(any)).thenAnswer((_) async => null); + api.result = []; final String? path = await plugin.getSavePath(); @@ -298,10 +255,7 @@ void main() { acceptedTypeGroups: [group, groupTwo], ); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.allowedFileTypes!.extensions, ['txt', 'jpg']); expect(options.allowedFileTypes!.mimeTypes, [ 'text/plain', @@ -316,20 +270,14 @@ void main() { test('passes initialDirectory correctly', () async { await plugin.getSavePath(initialDirectory: '/example/directory'); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.directoryPath, '/example/directory'); }); test('passes confirmButtonText correctly', () async { await plugin.getSavePath(confirmButtonText: 'Open File'); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.prompt, 'Open File'); }); @@ -373,25 +321,19 @@ void main() { ], ); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.allowedFileTypes, null); }); }); group('getSaveLocation', () { test('works as expected with no arguments', () async { - when(mockApi.displaySavePanel(any)).thenAnswer((_) async => 'foo'); + api.result = ['foo']; final FileSaveLocation? location = await plugin.getSaveLocation(); expect(location?.path, 'foo'); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.allowedFileTypes, null); expect(options.directoryPath, null); expect(options.nameFieldStringValue, null); @@ -399,7 +341,7 @@ void main() { }); test('handles cancel', () async { - when(mockApi.displaySavePanel(any)).thenAnswer((_) async => null); + api.result = []; final FileSaveLocation? location = await plugin.getSaveLocation(); @@ -426,10 +368,7 @@ void main() { acceptedTypeGroups: [group, groupTwo], ); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.allowedFileTypes!.extensions, ['txt', 'jpg']); expect(options.allowedFileTypes!.mimeTypes, [ 'text/plain', @@ -448,10 +387,7 @@ void main() { ), ); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.directoryPath, '/example/directory'); }); @@ -460,10 +396,7 @@ void main() { options: const SaveDialogOptions(confirmButtonText: 'Open File'), ); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.prompt, 'Open File'); }); @@ -507,27 +440,19 @@ void main() { ], ); - final VerificationResult result = verify( - mockApi.displaySavePanel(captureAny), - ); - final SavePanelOptions options = result.captured[0] as SavePanelOptions; + final SavePanelOptions options = api.passedSavePanelOptions!; expect(options.allowedFileTypes, null); }); }); group('getDirectoryPath', () { test('works as expected with no arguments', () async { - when( - mockApi.displayOpenPanel(any), - ).thenAnswer((_) async => ['foo']); + api.result = ['foo']; final String? path = await plugin.getDirectoryPath(); expect(path, 'foo'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.allowsMultipleSelection, false); expect(options.canChooseFiles, false); expect(options.canChooseDirectories, true); @@ -538,7 +463,7 @@ void main() { }); test('handles cancel', () async { - when(mockApi.displayOpenPanel(any)).thenAnswer((_) async => []); + api.result = []; final String? path = await plugin.getDirectoryPath(); @@ -548,33 +473,25 @@ void main() { test('passes initialDirectory correctly', () async { await plugin.getDirectoryPath(initialDirectory: '/example/directory'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.directoryPath, '/example/directory'); }); test('passes confirmButtonText correctly', () async { await plugin.getDirectoryPath(confirmButtonText: 'Open File'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.prompt, 'Open File'); }); }); group('getDirectoryPaths', () { test('works as expected with no arguments', () async { - when(mockApi.displayOpenPanel(any)).thenAnswer( - (_) async => [ - 'firstDirectory', - 'secondDirectory', - 'thirdDirectory', - ], - ); + api.result = [ + 'firstDirectory', + 'secondDirectory', + 'thirdDirectory', + ]; final List path = await plugin.getDirectoryPaths(); @@ -583,10 +500,7 @@ void main() { 'secondDirectory', 'thirdDirectory', ]); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.allowsMultipleSelection, true); expect(options.canChooseFiles, false); expect(options.canChooseDirectories, true); @@ -597,7 +511,7 @@ void main() { }); test('handles cancel', () async { - when(mockApi.displayOpenPanel(any)).thenAnswer((_) async => []); + api.result = []; final List paths = await plugin.getDirectoryPaths(); @@ -607,21 +521,42 @@ void main() { test('passes confirmButtonText correctly', () async { await plugin.getDirectoryPaths(confirmButtonText: 'Select directories'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.prompt, 'Select directories'); }); test('passes initialDirectory correctly', () async { await plugin.getDirectoryPaths(initialDirectory: '/example/directory'); - final VerificationResult result = verify( - mockApi.displayOpenPanel(captureAny), - ); - final OpenPanelOptions options = result.captured[0] as OpenPanelOptions; + final OpenPanelOptions options = api.passedOpenPanelOptions!; expect(options.baseOptions.directoryPath, '/example/directory'); }); }); } + +/// Fake implementation that stores arguments and provides a canned response. +class FakeFileSelectorApi implements FileSelectorApi { + OpenPanelOptions? passedOpenPanelOptions; + SavePanelOptions? passedSavePanelOptions; + List result = []; + + @override + Future> displayOpenPanel(OpenPanelOptions options) async { + passedOpenPanelOptions = options; + return result; + } + + @override + Future displaySavePanel(SavePanelOptions options) async { + passedSavePanelOptions = options; + return result.firstOrNull; + } + + @override + // ignore: non_constant_identifier_names + BinaryMessenger? get pigeonVar_binaryMessenger => null; + + @override + // ignore: non_constant_identifier_names + String get pigeonVar_messageChannelSuffix => ''; +} diff --git a/packages/file_selector/file_selector_macos/test/file_selector_macos_test.mocks.dart b/packages/file_selector/file_selector_macos/test/file_selector_macos_test.mocks.dart deleted file mode 100644 index 6d8611a2a1c..00000000000 --- a/packages/file_selector/file_selector_macos/test/file_selector_macos_test.mocks.dart +++ /dev/null @@ -1,50 +0,0 @@ -// Mocks generated by Mockito 5.4.4 from annotations -// in file_selector_macos/test/file_selector_macos_test.dart. -// Do not manually edit this file. - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i3; - -import 'package:file_selector_macos/src/messages.g.dart' as _i4; -import 'package:mockito/mockito.dart' as _i1; - -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: deprecated_member_use -// ignore_for_file: deprecated_member_use_from_same_package -// 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 [TestFileSelectorApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockTestFileSelectorApi extends _i1.Mock - implements _i2.TestFileSelectorApi { - MockTestFileSelectorApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i3.Future> displayOpenPanel(_i4.OpenPanelOptions? options) => - (super.noSuchMethod( - Invocation.method(#displayOpenPanel, [options]), - returnValue: _i3.Future>.value([]), - ) - as _i3.Future>); - - @override - _i3.Future displaySavePanel(_i4.SavePanelOptions? options) => - (super.noSuchMethod( - Invocation.method(#displaySavePanel, [options]), - returnValue: _i3.Future.value(), - ) - as _i3.Future); -} diff --git a/packages/file_selector/file_selector_macos/test/messages_test.g.dart b/packages/file_selector/file_selector_macos/test/messages_test.g.dart deleted file mode 100644 index 3f830bbe423..00000000000 --- a/packages/file_selector/file_selector_macos/test/messages_test.g.dart +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// Autogenerated from Pigeon (v25.5.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, no_leading_underscores_for_local_identifiers -// 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:file_selector_macos/src/messages.g.dart'; - -class _PigeonCodec extends StandardMessageCodec { - const _PigeonCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is AllowedTypes) { - buffer.putUint8(129); - writeValue(buffer, value.encode()); - } else if (value is SavePanelOptions) { - buffer.putUint8(130); - writeValue(buffer, value.encode()); - } else if (value is OpenPanelOptions) { - buffer.putUint8(131); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 129: - return AllowedTypes.decode(readValue(buffer)!); - case 130: - return SavePanelOptions.decode(readValue(buffer)!); - case 131: - return OpenPanelOptions.decode(readValue(buffer)!); - default: - return super.readValueOfType(type, buffer); - } - } -} - -abstract class TestFileSelectorApi { - static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => - TestDefaultBinaryMessengerBinding.instance; - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - /// Shows an open panel with the given [options], returning the list of - /// selected paths. - /// - /// An empty list corresponds to a cancelled selection. - Future> displayOpenPanel(OpenPanelOptions options); - - /// Shows a save panel with the given [options], returning the selected path. - /// - /// A null return corresponds to a cancelled save. - Future displaySavePanel(SavePanelOptions options); - - static void setUp( - TestFileSelectorApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = messageChannelSuffix.isNotEmpty - ? '.$messageChannelSuffix' - : ''; - { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.file_selector_macos.FileSelectorApi.displayOpenPanel$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, ( - Object? message, - ) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.file_selector_macos.FileSelectorApi.displayOpenPanel was null.', - ); - final List args = (message as List?)!; - final OpenPanelOptions? arg_options = - (args[0] as OpenPanelOptions?); - assert( - arg_options != null, - 'Argument for dev.flutter.pigeon.file_selector_macos.FileSelectorApi.displayOpenPanel was null, expected non-null OpenPanelOptions.', - ); - try { - final List output = await api.displayOpenPanel( - arg_options!, - ); - return [output]; - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException( - code: 'error', - message: e.toString(), - ), - ); - } - }); - } - } - { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.file_selector_macos.FileSelectorApi.displaySavePanel$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, ( - Object? message, - ) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.file_selector_macos.FileSelectorApi.displaySavePanel was null.', - ); - final List args = (message as List?)!; - final SavePanelOptions? arg_options = - (args[0] as SavePanelOptions?); - assert( - arg_options != null, - 'Argument for dev.flutter.pigeon.file_selector_macos.FileSelectorApi.displaySavePanel was null, expected non-null SavePanelOptions.', - ); - try { - final String? output = await api.displaySavePanel(arg_options!); - return [output]; - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException( - code: 'error', - message: e.toString(), - ), - ); - } - }); - } - } - } -} From 510007120675a7a7c98f84eca93e5ed51fe44d07 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 28 Oct 2025 15:30:10 -0400 Subject: [PATCH 4/4] Update Windows to use a simple fake --- .../lib/file_selector_windows.dart | 7 +- .../pigeons/messages.dart | 3 +- .../file_selector_windows/pubspec.yaml | 2 - .../test/file_selector_windows_test.dart | 200 +++++++++--------- .../file_selector_windows_test.mocks.dart | 87 -------- .../test/test_api.g.dart | 176 --------------- 6 files changed, 102 insertions(+), 373 deletions(-) delete mode 100644 packages/file_selector/file_selector_windows/test/file_selector_windows_test.mocks.dart delete mode 100644 packages/file_selector/file_selector_windows/test/test_api.g.dart diff --git a/packages/file_selector/file_selector_windows/lib/file_selector_windows.dart b/packages/file_selector/file_selector_windows/lib/file_selector_windows.dart index e74e2ab049d..4f2ace43976 100644 --- a/packages/file_selector/file_selector_windows/lib/file_selector_windows.dart +++ b/packages/file_selector/file_selector_windows/lib/file_selector_windows.dart @@ -3,12 +3,17 @@ // found in the LICENSE file. import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/foundation.dart' show visibleForTesting; import 'src/messages.g.dart'; /// An implementation of [FileSelectorPlatform] for Windows. class FileSelectorWindows extends FileSelectorPlatform { - final FileSelectorApi _hostApi = FileSelectorApi(); + /// Creates a new plugin implementation instance. + FileSelectorWindows({@visibleForTesting FileSelectorApi? api}) + : _hostApi = api ?? FileSelectorApi(); + + final FileSelectorApi _hostApi; /// Registers the Windows implementation. static void registerWith() { diff --git a/packages/file_selector/file_selector_windows/pigeons/messages.dart b/packages/file_selector/file_selector_windows/pigeons/messages.dart index 5269b04aaf1..dd01a2d70f4 100644 --- a/packages/file_selector/file_selector_windows/pigeons/messages.dart +++ b/packages/file_selector/file_selector_windows/pigeons/messages.dart @@ -7,7 +7,6 @@ import 'package:pigeon/pigeon.dart'; @ConfigurePigeon( PigeonOptions( dartOut: 'lib/src/messages.g.dart', - dartTestOut: 'test/test_api.g.dart', cppOptions: CppOptions(namespace: 'file_selector_windows'), cppHeaderOut: 'windows/messages.g.h', cppSourceOut: 'windows/messages.g.cpp', @@ -48,7 +47,7 @@ class FileDialogResult { int? typeGroupIndex; } -@HostApi(dartHostTestHandler: 'TestFileSelectorApi') +@HostApi() abstract class FileSelectorApi { FileDialogResult showOpenDialog( SelectionOptions options, diff --git a/packages/file_selector/file_selector_windows/pubspec.yaml b/packages/file_selector/file_selector_windows/pubspec.yaml index 48966187bfd..d71a5ff09d9 100644 --- a/packages/file_selector/file_selector_windows/pubspec.yaml +++ b/packages/file_selector/file_selector_windows/pubspec.yaml @@ -23,10 +23,8 @@ dependencies: sdk: flutter dev_dependencies: - build_runner: ^2.3.0 flutter_test: sdk: flutter - mockito: ^5.4.4 pigeon: ^22.4.1 topics: diff --git a/packages/file_selector/file_selector_windows/test/file_selector_windows_test.dart b/packages/file_selector/file_selector_windows/test/file_selector_windows_test.dart index 8685acb06be..f062513bafe 100644 --- a/packages/file_selector/file_selector_windows/test/file_selector_windows_test.dart +++ b/packages/file_selector/file_selector_windows/test/file_selector_windows_test.dart @@ -6,23 +6,18 @@ import 'package:file_selector_platform_interface/file_selector_platform_interfac import 'package:file_selector_windows/file_selector_windows.dart'; import 'package:file_selector_windows/src/messages.g.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; -import 'file_selector_windows_test.mocks.dart'; -import 'test_api.g.dart'; - -@GenerateMocks([TestFileSelectorApi]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final FileSelectorWindows plugin = FileSelectorWindows(); - late MockTestFileSelectorApi mockApi; + late FakeFileSelectorApi api; + late FileSelectorWindows plugin; setUp(() { - mockApi = MockTestFileSelectorApi(); - TestFileSelectorApi.setUp(mockApi); + api = FakeFileSelectorApi(); + plugin = FileSelectorWindows(api: api); }); test('registered instance', () { @@ -32,21 +27,15 @@ void main() { group('openFile', () { setUp(() { - when( - mockApi.showOpenDialog(any, any, any), - ).thenReturn(FileDialogResult(paths: ['foo'])); + api.result = ['foo']; }); test('simple call works', () async { final XFile? file = await plugin.openFile(); expect(file!.path, 'foo'); - final VerificationResult result = verify( - mockApi.showOpenDialog(captureAny, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; - expect(options.allowMultiple, false); - expect(options.selectFolders, false); + expect(api.passedOptions!.allowMultiple, false); + expect(api.passedOptions!.selectFolders, false); }); test('passes the accepted type groups correctly', () async { @@ -64,12 +53,8 @@ void main() { await plugin.openFile(acceptedTypeGroups: [group, groupTwo]); - final VerificationResult result = verify( - mockApi.showOpenDialog(captureAny, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; expect( - _typeGroupListsMatch(options.allowedTypes, [ + _typeGroupListsMatch(api.passedOptions!.allowedTypes, [ TypeGroup(label: 'text', extensions: ['txt']), TypeGroup(label: 'image', extensions: ['jpg']), ]), @@ -80,13 +65,13 @@ void main() { test('passes initialDirectory correctly', () async { await plugin.openFile(initialDirectory: '/example/directory'); - verify(mockApi.showOpenDialog(any, '/example/directory', null)); + expect(api.passedInitialDirectory, '/example/directory'); }); test('passes confirmButtonText correctly', () async { await plugin.openFile(confirmButtonText: 'Open File'); - verify(mockApi.showOpenDialog(any, null, 'Open File')); + expect(api.passedConfirmButtonText, 'Open File'); }); test('throws for a type group that does not support Windows', () async { @@ -113,9 +98,7 @@ void main() { group('openFiles', () { setUp(() { - when( - mockApi.showOpenDialog(any, any, any), - ).thenReturn(FileDialogResult(paths: ['foo', 'bar'])); + api.result = ['foo', 'bar']; }); test('simple call works', () async { @@ -123,12 +106,8 @@ void main() { expect(file[0].path, 'foo'); expect(file[1].path, 'bar'); - final VerificationResult result = verify( - mockApi.showOpenDialog(captureAny, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; - expect(options.allowMultiple, true); - expect(options.selectFolders, false); + expect(api.passedOptions!.allowMultiple, true); + expect(api.passedOptions!.selectFolders, false); }); test('passes the accepted type groups correctly', () async { @@ -146,12 +125,8 @@ void main() { await plugin.openFiles(acceptedTypeGroups: [group, groupTwo]); - final VerificationResult result = verify( - mockApi.showOpenDialog(captureAny, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; expect( - _typeGroupListsMatch(options.allowedTypes, [ + _typeGroupListsMatch(api.passedOptions!.allowedTypes, [ TypeGroup(label: 'text', extensions: ['txt']), TypeGroup(label: 'image', extensions: ['jpg']), ]), @@ -162,13 +137,13 @@ void main() { test('passes initialDirectory correctly', () async { await plugin.openFiles(initialDirectory: '/example/directory'); - verify(mockApi.showOpenDialog(any, '/example/directory', null)); + expect(api.passedInitialDirectory, '/example/directory'); }); test('passes confirmButtonText correctly', () async { await plugin.openFiles(confirmButtonText: 'Open Files'); - verify(mockApi.showOpenDialog(any, null, 'Open Files')); + expect(api.passedConfirmButtonText, 'Open Files'); }); test('throws for a type group that does not support Windows', () async { @@ -195,41 +170,33 @@ void main() { group('getDirectoryPath', () { setUp(() { - when( - mockApi.showOpenDialog(any, any, any), - ).thenReturn(FileDialogResult(paths: ['foo'])); + api.result = ['foo']; }); test('simple call works', () async { final String? path = await plugin.getDirectoryPath(); expect(path, 'foo'); - final VerificationResult result = verify( - mockApi.showOpenDialog(captureAny, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; - expect(options.allowMultiple, false); - expect(options.selectFolders, true); + expect(api.passedOptions!.allowMultiple, false); + expect(api.passedOptions!.selectFolders, true); }); test('passes initialDirectory correctly', () async { await plugin.getDirectoryPath(initialDirectory: '/example/directory'); - verify(mockApi.showOpenDialog(any, '/example/directory', null)); + expect(api.passedInitialDirectory, '/example/directory'); }); test('passes confirmButtonText correctly', () async { await plugin.getDirectoryPath(confirmButtonText: 'Open Directory'); - verify(mockApi.showOpenDialog(any, null, 'Open Directory')); + expect(api.passedConfirmButtonText, 'Open Directory'); }); }); group('getDirectoryPaths', () { setUp(() { - when( - mockApi.showOpenDialog(any, any, any), - ).thenReturn(FileDialogResult(paths: ['foo', 'bar'])); + api.result = ['foo', 'bar']; }); test('simple call works', () async { @@ -237,32 +204,26 @@ void main() { expect(paths[0], 'foo'); expect(paths[1], 'bar'); - final VerificationResult result = verify( - mockApi.showOpenDialog(captureAny, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; - expect(options.allowMultiple, true); - expect(options.selectFolders, true); + expect(api.passedOptions!.allowMultiple, true); + expect(api.passedOptions!.selectFolders, true); }); test('passes initialDirectory correctly', () async { - await plugin.getDirectoryPath(initialDirectory: '/example/directory'); + await plugin.getDirectoryPaths(initialDirectory: '/example/directory'); - verify(mockApi.showOpenDialog(any, '/example/directory', null)); + expect(api.passedInitialDirectory, '/example/directory'); }); test('passes confirmButtonText correctly', () async { - await plugin.getDirectoryPath(confirmButtonText: 'Open Directory'); + await plugin.getDirectoryPaths(confirmButtonText: 'Open Directory'); - verify(mockApi.showOpenDialog(any, null, 'Open Directory')); + expect(api.passedConfirmButtonText, 'Open Directory'); }); }); group('getSaveLocation', () { setUp(() { - when( - mockApi.showSaveDialog(any, any, any, any), - ).thenReturn(FileDialogResult(paths: ['foo'])); + api.result = ['foo']; }); test('simple call works', () async { @@ -270,12 +231,8 @@ void main() { expect(location?.path, 'foo'); expect(location?.activeFilter, null); - final VerificationResult result = verify( - mockApi.showSaveDialog(captureAny, null, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; - expect(options.allowMultiple, false); - expect(options.selectFolders, false); + expect(api.passedOptions!.allowMultiple, false); + expect(api.passedOptions!.selectFolders, false); }); test('passes the accepted type groups correctly', () async { @@ -295,12 +252,8 @@ void main() { acceptedTypeGroups: [group, groupTwo], ); - final VerificationResult result = verify( - mockApi.showSaveDialog(captureAny, null, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; expect( - _typeGroupListsMatch(options.allowedTypes, [ + _typeGroupListsMatch(api.passedOptions!.allowedTypes, [ TypeGroup(label: 'text', extensions: ['txt']), TypeGroup(label: 'image', extensions: ['jpg']), ]), @@ -309,9 +262,8 @@ void main() { }); test('returns the selected type group correctly', () async { - when( - mockApi.showSaveDialog(any, any, any, any), - ).thenReturn(FileDialogResult(paths: ['foo'], typeGroupIndex: 1)); + api.result = ['foo']; + api.resultTypeGroupIndex = 1; const XTypeGroup group = XTypeGroup( label: 'text', extensions: ['txt'], @@ -328,8 +280,6 @@ void main() { acceptedTypeGroups: [group, groupTwo], ); - verify(mockApi.showSaveDialog(captureAny, null, null, null)); - expect(result?.activeFilter, groupTwo); }); @@ -340,7 +290,7 @@ void main() { ), ); - verify(mockApi.showSaveDialog(any, '/example/directory', null, null)); + expect(api.passedInitialDirectory, '/example/directory'); }); test('passes suggestedName correctly', () async { @@ -348,7 +298,7 @@ void main() { options: const SaveDialogOptions(suggestedName: 'baz.txt'), ); - verify(mockApi.showSaveDialog(any, null, 'baz.txt', null)); + expect(api.passedSuggestedName, 'baz.txt'); }); test('passes confirmButtonText correctly', () async { @@ -356,7 +306,7 @@ void main() { options: const SaveDialogOptions(confirmButtonText: 'Save File'), ); - verify(mockApi.showSaveDialog(any, null, null, 'Save File')); + expect(api.passedConfirmButtonText, 'Save File'); }); test('throws for a type group that does not support Windows', () async { @@ -383,21 +333,15 @@ void main() { group('getSavePath (deprecated)', () { setUp(() { - when( - mockApi.showSaveDialog(any, any, any, any), - ).thenReturn(FileDialogResult(paths: ['foo'])); + api.result = ['foo']; }); test('simple call works', () async { final String? path = await plugin.getSavePath(); expect(path, 'foo'); - final VerificationResult result = verify( - mockApi.showSaveDialog(captureAny, null, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; - expect(options.allowMultiple, false); - expect(options.selectFolders, false); + expect(api.passedOptions!.allowMultiple, false); + expect(api.passedOptions!.selectFolders, false); }); test('passes the accepted type groups correctly', () async { @@ -417,12 +361,8 @@ void main() { acceptedTypeGroups: [group, groupTwo], ); - final VerificationResult result = verify( - mockApi.showSaveDialog(captureAny, null, null, null), - ); - final SelectionOptions options = result.captured[0] as SelectionOptions; expect( - _typeGroupListsMatch(options.allowedTypes, [ + _typeGroupListsMatch(api.passedOptions!.allowedTypes, [ TypeGroup(label: 'text', extensions: ['txt']), TypeGroup(label: 'image', extensions: ['jpg']), ]), @@ -433,19 +373,19 @@ void main() { test('passes initialDirectory correctly', () async { await plugin.getSavePath(initialDirectory: '/example/directory'); - verify(mockApi.showSaveDialog(any, '/example/directory', null, null)); + expect(api.passedInitialDirectory, '/example/directory'); }); test('passes suggestedName correctly', () async { await plugin.getSavePath(suggestedName: 'baz.txt'); - verify(mockApi.showSaveDialog(any, null, 'baz.txt', null)); + expect(api.passedSuggestedName, 'baz.txt'); }); test('passes confirmButtonText correctly', () async { await plugin.getSavePath(confirmButtonText: 'Save File'); - verify(mockApi.showSaveDialog(any, null, null, 'Save File')); + expect(api.passedConfirmButtonText, 'Save File'); }); test('throws for a type group that does not support Windows', () async { @@ -494,3 +434,53 @@ bool _typeGroupListsMatch(List a, List b) { bool _typeGroupsMatch(TypeGroup? a, TypeGroup? b) { return a!.label == b!.label && listEquals(a.extensions, b.extensions); } + +/// Fake implementation that stores arguments and provides a canned response. +class FakeFileSelectorApi implements FileSelectorApi { + List result = []; + int? resultTypeGroupIndex; + String? passedInitialDirectory; + String? passedConfirmButtonText; + String? passedSuggestedName; + SelectionOptions? passedOptions; + + @override + Future showOpenDialog( + SelectionOptions options, + String? initialDirectory, + String? confirmButtonText, + ) async { + passedInitialDirectory = initialDirectory; + passedConfirmButtonText = confirmButtonText; + passedOptions = options; + return FileDialogResult( + paths: result, + typeGroupIndex: resultTypeGroupIndex, + ); + } + + @override + Future showSaveDialog( + SelectionOptions options, + String? initialDirectory, + String? suggestedName, + String? confirmButtonText, + ) async { + passedInitialDirectory = initialDirectory; + passedConfirmButtonText = confirmButtonText; + passedSuggestedName = suggestedName; + passedOptions = options; + return FileDialogResult( + paths: result, + typeGroupIndex: resultTypeGroupIndex, + ); + } + + @override + // ignore: non_constant_identifier_names + BinaryMessenger? get pigeonVar_binaryMessenger => null; + + @override + // ignore: non_constant_identifier_names + String get pigeonVar_messageChannelSuffix => ''; +} diff --git a/packages/file_selector/file_selector_windows/test/file_selector_windows_test.mocks.dart b/packages/file_selector/file_selector_windows/test/file_selector_windows_test.mocks.dart deleted file mode 100644 index 5689a48369d..00000000000 --- a/packages/file_selector/file_selector_windows/test/file_selector_windows_test.mocks.dart +++ /dev/null @@ -1,87 +0,0 @@ -// Mocks generated by Mockito 5.4.4 from annotations -// in file_selector_windows/test/file_selector_windows_test.dart. -// Do not manually edit this file. - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:file_selector_windows/src/messages.g.dart' as _i2; -import 'package:mockito/mockito.dart' as _i1; - -import 'test_api.g.dart' as _i3; - -// 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: deprecated_member_use -// ignore_for_file: deprecated_member_use_from_same_package -// 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 - -class _FakeFileDialogResult_0 extends _i1.SmartFake - implements _i2.FileDialogResult { - _FakeFileDialogResult_0(Object parent, Invocation parentInvocation) - : super(parent, parentInvocation); -} - -/// A class which mocks [TestFileSelectorApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockTestFileSelectorApi extends _i1.Mock - implements _i3.TestFileSelectorApi { - MockTestFileSelectorApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i2.FileDialogResult showOpenDialog( - _i2.SelectionOptions? options, - String? initialDirectory, - String? confirmButtonText, - ) => - (super.noSuchMethod( - Invocation.method(#showOpenDialog, [ - options, - initialDirectory, - confirmButtonText, - ]), - returnValue: _FakeFileDialogResult_0( - this, - Invocation.method(#showOpenDialog, [ - options, - initialDirectory, - confirmButtonText, - ]), - ), - ) - as _i2.FileDialogResult); - - @override - _i2.FileDialogResult showSaveDialog( - _i2.SelectionOptions? options, - String? initialDirectory, - String? suggestedName, - String? confirmButtonText, - ) => - (super.noSuchMethod( - Invocation.method(#showSaveDialog, [ - options, - initialDirectory, - suggestedName, - confirmButtonText, - ]), - returnValue: _FakeFileDialogResult_0( - this, - Invocation.method(#showSaveDialog, [ - options, - initialDirectory, - suggestedName, - confirmButtonText, - ]), - ), - ) - as _i2.FileDialogResult); -} diff --git a/packages/file_selector/file_selector_windows/test/test_api.g.dart b/packages/file_selector/file_selector_windows/test/test_api.g.dart deleted file mode 100644 index c71fe36cf57..00000000000 --- a/packages/file_selector/file_selector_windows/test/test_api.g.dart +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// Autogenerated from Pigeon (v22.4.1), 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, no_leading_underscores_for_local_identifiers -// 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:file_selector_windows/src/messages.g.dart'; - -class _PigeonCodec extends StandardMessageCodec { - const _PigeonCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is TypeGroup) { - buffer.putUint8(129); - writeValue(buffer, value.encode()); - } else if (value is SelectionOptions) { - buffer.putUint8(130); - writeValue(buffer, value.encode()); - } else if (value is FileDialogResult) { - buffer.putUint8(131); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 129: - return TypeGroup.decode(readValue(buffer)!); - case 130: - return SelectionOptions.decode(readValue(buffer)!); - case 131: - return FileDialogResult.decode(readValue(buffer)!); - default: - return super.readValueOfType(type, buffer); - } - } -} - -abstract class TestFileSelectorApi { - static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => - TestDefaultBinaryMessengerBinding.instance; - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - FileDialogResult showOpenDialog( - SelectionOptions options, - String? initialDirectory, - String? confirmButtonText, - ); - - FileDialogResult showSaveDialog( - SelectionOptions options, - String? initialDirectory, - String? suggestedName, - String? confirmButtonText, - ); - - static void setUp( - TestFileSelectorApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.file_selector_windows.FileSelectorApi.showOpenDialog$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, ( - Object? message, - ) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.file_selector_windows.FileSelectorApi.showOpenDialog was null.', - ); - final List args = (message as List?)!; - final SelectionOptions? arg_options = - (args[0] as SelectionOptions?); - assert( - arg_options != null, - 'Argument for dev.flutter.pigeon.file_selector_windows.FileSelectorApi.showOpenDialog was null, expected non-null SelectionOptions.', - ); - final String? arg_initialDirectory = (args[1] as String?); - final String? arg_confirmButtonText = (args[2] as String?); - try { - final FileDialogResult output = api.showOpenDialog( - arg_options!, - arg_initialDirectory, - arg_confirmButtonText, - ); - return [output]; - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException( - code: 'error', - message: e.toString(), - ), - ); - } - }); - } - } - { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.file_selector_windows.FileSelectorApi.showSaveDialog$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, ( - Object? message, - ) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.file_selector_windows.FileSelectorApi.showSaveDialog was null.', - ); - final List args = (message as List?)!; - final SelectionOptions? arg_options = - (args[0] as SelectionOptions?); - assert( - arg_options != null, - 'Argument for dev.flutter.pigeon.file_selector_windows.FileSelectorApi.showSaveDialog was null, expected non-null SelectionOptions.', - ); - final String? arg_initialDirectory = (args[1] as String?); - final String? arg_suggestedName = (args[2] as String?); - final String? arg_confirmButtonText = (args[3] as String?); - try { - final FileDialogResult output = api.showSaveDialog( - arg_options!, - arg_initialDirectory, - arg_suggestedName, - arg_confirmButtonText, - ); - return [output]; - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException( - code: 'error', - message: e.toString(), - ), - ); - } - }); - } - } - } -}