Skip to content

Commit

Permalink
feat: New ItemProviderPropertyValueRepresentation to Use an ItemProvi…
Browse files Browse the repository at this point in the history
…der wrapping a property list

test: Testing ItemProviderPropertyValueRepresentation
  • Loading branch information
adrien-coye committed Mar 21, 2024
1 parent 254b414 commit c94da92
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 0 deletions.
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
}
}
}
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)
}
}
}

0 comments on commit c94da92

Please sign in to comment.