Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Read dictionary from ItemProvider #115

Merged
merged 2 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
Infomaniak Mail - iOS App
Copyright (C) 2024 Infomaniak Network SA

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import Foundation

/// Something that can provide a `Progress` and an async `Result`
/// from a `NSItemProvider` that is conforming to propertyList UTI
///
/// Returns arbitrary Dictionary
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public final class ItemProviderPropertyValueRepresentation: NSObject, ProgressResultable {
/// Progress increment size
private static let progressStep: Int64 = 1

/// Number of steps to complete the task
private static let totalSteps: Int64 = 1

/// Something to transform events to a nice `async Result`
private let flowToAsync = FlowToAsyncResult<Success>()

private let itemProvider: NSItemProvider

/// Domain specific errors
public enum ErrorDomain: Error, Equatable {
/// loadItem cast failed
case unableToReadDictionary
}

public typealias Success = NSDictionary
public typealias Failure = Error

public init(from itemProvider: NSItemProvider) {
progress = Progress(totalUnitCount: Self.totalSteps)

self.itemProvider = itemProvider
super.init()

Task {
let completionProgress = Progress(totalUnitCount: Self.totalSteps)
progress.addChild(completionProgress, withPendingUnitCount: Self.progressStep)

defer {
completionProgress.completedUnitCount += Self.progressStep
}

let propertyListIdentifier = UTI.propertyList.identifier
if self.itemProvider.hasItemConformingToTypeIdentifier(propertyListIdentifier) {
guard let resultDictionary = try await self.itemProvider
.loadItem(forTypeIdentifier: propertyListIdentifier) as? NSDictionary else {
flowToAsync.sendFailure(ErrorDomain.unableToReadDictionary)
return
}

flowToAsync.sendSuccess(resultDictionary)

} else {
flowToAsync.sendFailure(ErrorDomain.unableToReadDictionary)
}
}
}

// MARK: ProgressResultable

public var progress: Progress

public var result: Result<Success, Failure> {
get async {
return await flowToAsync.result
}
}
}
28 changes: 24 additions & 4 deletions Tests/InfomaniakCoreTests/Platform/UTCorePlatform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,36 @@
import InfomaniakCore
import XCTest

final class UTCorePlatform: XCTestCase {
// MARK: - appVersionLabel

func testVersionLabel() {
#if canImport(UIKit)

@available(iOS 13.0, *) final class UTCorePlatform: XCTestCase {
func testVersionLabel_ios() {
// GIVEN
let expectedPrefix = "xctest iOS version"

// WHEN
let versionLabel = CorePlatform.appVersionLabel(fallbackAppName: "xctest")

// THEN
XCTAssertTrue(versionLabel.hasPrefix(expectedPrefix), "wrong text, got :\(versionLabel)")
}
}

#else

@available(macOS 10.15, *) final class UTCorePlatform: XCTestCase {
func testVersionLabel_mac() {
// GIVEN
let expectedPrefix = "xctest macOS version"

// WHEN
let versionLabel = CorePlatform.appVersionLabel(fallbackAppName: "xctest")

// THEN
XCTAssertTrue(versionLabel.hasPrefix(expectedPrefix))
XCTAssertTrue(versionLabel.hasPrefix(expectedPrefix), "wrong text, got :\(versionLabel)")
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
Infomaniak Core - iOS
Copyright (C) 2024 Infomaniak Network SA

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import Foundation
import InfomaniakCore
@testable import InfomaniakDI
import XCTest

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
final class UTItemProviderPropertyValueRepresentation: XCTestCase {
private let fileManager = FileManager.default

override func setUp() {
let factory = Factory(
type: AppGroupPathProvidable.self
) { _, _ in
return AppGroupPathProvider(realmRootPath: "realm", appGroupIdentifier: "com.ik.test")!
}
SimpleResolver.sharedResolver.store(factory: factory)
}

override func tearDown() {
SimpleResolver.sharedResolver.removeAll()
}

// MARK: -

func testProvideDictionary() async {
// GIVEN
let someDictionary: NSDictionary = ["key": "value"]
let item = NSItemProvider(item: someDictionary, typeIdentifier: UTI.propertyList.identifier)

let provider = ItemProviderPropertyValueRepresentation(from: item)
XCTAssertFalse(provider.progress.isFinished)

do {
// WHEN
let result = try await provider.result.get()

// THEN
XCTAssertEqual(result, someDictionary)
XCTAssertTrue(provider.progress.isFinished)
} catch {
XCTFail("Unexpected error:\(error)")
}
}

func testUnableToProvideDictionary() async {
// GIVEN
let garbageInput = "la li lu le lo" as NSSecureCoding
let item = NSItemProvider(item: garbageInput, typeIdentifier: UTI.propertyList.identifier)

let provider = ItemProviderPropertyValueRepresentation(from: item)
XCTAssertFalse(provider.progress.isFinished)

do {
// WHEN
let result = try await provider.result.get()

// THEN
XCTFail("Should throw. got \(result)")
} catch {
guard let error = error as? ItemProviderPropertyValueRepresentation.ErrorDomain else {
XCTFail("Unexpected error :\(error)")
return
}

guard error == .unableToReadDictionary else {
XCTFail("Unexpected domain error :\(error)")
return
}

XCTAssertTrue(provider.progress.isFinished)
}
}
}
Loading