From e56eb3472304505fe4634a8545ec78bcbd6f523a Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 18 Sep 2023 14:05:13 -0700 Subject: [PATCH] [file_selector] Fix unknown extensions on macOS (#4946) Fixes a bug in the type lookup that would cause the dynamic `UTType` created for unknown extensions to not work as a save/open panel filter. As incidental cleanup, removes test timeouts that shouldn't exist per Flutter policy. Fixes https://github.com/flutter/flutter/issues/134963 --- .../file_selector_macos/CHANGELOG.md | 4 + .../macos/RunnerTests/RunnerTests.swift | 73 +++++++++++++++---- .../macos/Classes/FileSelectorPlugin.swift | 8 +- .../file_selector_macos/pubspec.yaml | 2 +- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/packages/file_selector/file_selector_macos/CHANGELOG.md b/packages/file_selector/file_selector_macos/CHANGELOG.md index 4d42d158e6ab..c01020f37df9 100644 --- a/packages/file_selector/file_selector_macos/CHANGELOG.md +++ b/packages/file_selector/file_selector_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.3+3 + +* Fixes handling of unknown file extensions on macOS 11+. + ## 0.9.3+2 * Adds pub topics to package metadata. diff --git a/packages/file_selector/file_selector_macos/example/macos/RunnerTests/RunnerTests.swift b/packages/file_selector/file_selector_macos/example/macos/RunnerTests/RunnerTests.swift index a77f4217311b..53081ed65482 100644 --- a/packages/file_selector/file_selector_macos/example/macos/RunnerTests/RunnerTests.swift +++ b/packages/file_selector/file_selector_macos/example/macos/RunnerTests/RunnerTests.swift @@ -67,7 +67,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) if let panel = panelController.openPanel { XCTAssertTrue(panel.canChooseFiles) @@ -104,7 +104,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) if let panel = panelController.openPanel { XCTAssertEqual(panel.directoryURL?.path, "/some/dir") @@ -140,7 +140,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) } @@ -173,7 +173,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) if let panel = panelController.openPanel { if #available(macOS 11.0, *) { @@ -188,6 +188,51 @@ class exampleTests: XCTestCase { } } + func testFilterUnknownFileExtension() throws { + let panelController = TestPanelController() + let plugin = FileSelectorPlugin( + viewProvider: TestViewProvider(), + panelController: panelController) + + let unknownExtension = "somenewextension" + let returnPath = "/foo/bar" + panelController.openURLs = [URL(fileURLWithPath: returnPath)] + + let called = XCTestExpectation() + let options = OpenPanelOptions( + allowsMultipleSelection: true, + canChooseDirectories: false, + canChooseFiles: true, + baseOptions: SavePanelOptions( + allowedFileTypes: AllowedTypes( + extensions: [unknownExtension], + mimeTypes: [], + utis: []))) + plugin.displayOpenPanel(options: options) { result in + switch result { + case .success(let paths): + XCTAssertEqual(paths[0], returnPath) + case .failure(let error): + XCTFail("\(error)") + } + called.fulfill() + } + + wait(for: [called]) + XCTAssertNotNil(panelController.openPanel) + if let panel = panelController.openPanel { + if #available(macOS 11.0, *) { + XCTAssertEqual(panel.allowedContentTypes.count, 1) + XCTAssertEqual(panel.allowedContentTypes[0].preferredFilenameExtension, unknownExtension) + // If this isn't true, the dynamic type created for the extension won't work as a file + // extension filter. + XCTAssertTrue(panel.allowedContentTypes[0].conforms(to: UTType.data)) + } else { + XCTAssertEqual(panel.allowedFileTypes, [unknownExtension]) + } + } + } + func testOpenWithFilterLegacy() throws { let panelController = TestPanelController() let plugin = FileSelectorPlugin( @@ -218,7 +263,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) if let panel = panelController.openPanel { // On the legacy path, the allowedFileTypes should be set directly. @@ -257,7 +302,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) } @@ -282,7 +327,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.savePanel) } @@ -309,7 +354,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.savePanel) if let panel = panelController.savePanel { XCTAssertEqual(panel.directoryURL?.path, "/some/dir") @@ -335,7 +380,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.savePanel) } @@ -364,7 +409,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) if let panel = panelController.openPanel { XCTAssertTrue(panel.canChooseDirectories) @@ -398,7 +443,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) } @@ -408,7 +453,7 @@ class exampleTests: XCTestCase { viewProvider: TestViewProvider(), panelController: panelController) - let returnPaths = ["/foo/bar", "/foo/test"]; + let returnPaths = ["/foo/bar", "/foo/test"] panelController.openURLs = returnPaths.map({ path in URL(fileURLWithPath: path) }) let called = XCTestExpectation() @@ -427,7 +472,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) if let panel = panelController.openPanel { XCTAssertTrue(panel.canChooseDirectories) @@ -459,7 +504,7 @@ class exampleTests: XCTestCase { called.fulfill() } - wait(for: [called], timeout: 0.5) + wait(for: [called]) XCTAssertNotNil(panelController.openPanel) } } diff --git a/packages/file_selector/file_selector_macos/macos/Classes/FileSelectorPlugin.swift b/packages/file_selector/file_selector_macos/macos/Classes/FileSelectorPlugin.swift index 83103325cf5c..c90d69d4609c 100644 --- a/packages/file_selector/file_selector_macos/macos/Classes/FileSelectorPlugin.swift +++ b/packages/file_selector/file_selector_macos/macos/Classes/FileSelectorPlugin.swift @@ -105,12 +105,12 @@ public class FileSelectorPlugin: NSObject, FlutterPlugin, FileSelectorApi { // that via the types; see messages.dart and https://github.com/flutter/flutter/issues/97848 allowedTypes.append(contentsOf: acceptedTypes.utis.compactMap({ UTType($0!) })) allowedTypes.append( - contentsOf: acceptedTypes.extensions.flatMap({ - UTType.types(tag: $0!, tagClass: UTTagClass.filenameExtension, conformingTo: nil) + contentsOf: acceptedTypes.extensions.compactMap({ + UTType.init(filenameExtension: $0!) })) allowedTypes.append( - contentsOf: acceptedTypes.mimeTypes.flatMap({ - UTType.types(tag: $0!, tagClass: UTTagClass.mimeType, conformingTo: nil) + contentsOf: acceptedTypes.mimeTypes.compactMap({ + UTType.init(mimeType: $0!) })) if !allowedTypes.isEmpty { panel.allowedContentTypes = allowedTypes diff --git a/packages/file_selector/file_selector_macos/pubspec.yaml b/packages/file_selector/file_selector_macos/pubspec.yaml index 540e8eecb3a3..ccc45dff4b54 100644 --- a/packages/file_selector/file_selector_macos/pubspec.yaml +++ b/packages/file_selector/file_selector_macos/pubspec.yaml @@ -2,7 +2,7 @@ name: file_selector_macos description: macOS implementation of the file_selector plugin. repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_macos issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 -version: 0.9.3+2 +version: 0.9.3+3 environment: sdk: ">=2.19.0 <4.0.0"