diff --git a/Sources/InfomaniakCore/Chunking/ChunkProvider.swift b/Sources/InfomaniakCore/Chunking/ChunkProvider.swift
index f9972ed..98be160 100644
--- a/Sources/InfomaniakCore/Chunking/ChunkProvider.swift
+++ b/Sources/InfomaniakCore/Chunking/ChunkProvider.swift
@@ -32,31 +32,24 @@ public protocol ChunkProvidable: IteratorProtocol {
public final class ChunkProvider: ChunkProvidable {
public typealias Element = Data
- let fileHandle: FileHandlable
+ let chunkReader: ChunkReader
var ranges: [DataRange]
- deinit {
- do {
- // For the sake of consistency
- try fileHandle.close()
- } catch {}
- }
-
public init?(fileURL: URL, ranges: [DataRange]) {
self.ranges = ranges
- do {
- fileHandle = try FileHandle(forReadingFrom: fileURL)
- } catch {
+ guard let chunkReader = ChunkReader(fileURL: fileURL) else {
return nil
}
+
+ self.chunkReader = chunkReader
}
/// Internal testing method
init(mockedHandlable: FileHandlable, ranges: [DataRange]) {
self.ranges = ranges
- fileHandle = mockedHandlable
+ chunkReader = ChunkReader(mockedHandlable: mockedHandlable)
}
/// Will provide chunks one by one, using the IteratorProtocol
@@ -69,23 +62,12 @@ public final class ChunkProvider: ChunkProvidable {
let range = ranges.removeFirst()
do {
- let chunk = try readChunk(range: range)
+ let chunk = try chunkReader.readChunk(range: range)
return chunk
} catch {
return nil
}
}
-
- // MARK: Internal
-
- func readChunk(range: DataRange) throws -> Data? {
- let offset = range.lowerBound
- try fileHandle.seek(toOffset: offset)
-
- let byteCount = Int(range.upperBound - range.lowerBound) + 1
- let chunk = try fileHandle.read(upToCount: byteCount)
- return chunk
- }
}
/// Print the FileHandle shows the current offset
diff --git a/Sources/InfomaniakCore/Chunking/ChunkReader.swift b/Sources/InfomaniakCore/Chunking/ChunkReader.swift
new file mode 100644
index 0000000..1ba7b2d
--- /dev/null
+++ b/Sources/InfomaniakCore/Chunking/ChunkReader.swift
@@ -0,0 +1,53 @@
+/*
+ Infomaniak kDrive - 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 .
+ */
+
+import Foundation
+
+@available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *)
+public final class ChunkReader: Sendable {
+ let fileHandle: FileHandlable
+
+ deinit {
+ do {
+ // For the sake of consistency
+ try fileHandle.close()
+ } catch {}
+ }
+
+ public init?(fileURL: URL) {
+ do {
+ fileHandle = try FileHandle(forReadingFrom: fileURL)
+ } catch {
+ return nil
+ }
+ }
+
+ /// Internal testing method
+ init(mockedHandlable: FileHandlable) {
+ fileHandle = mockedHandlable
+ }
+
+ public func readChunk(range: DataRange) throws -> Data? {
+ let offset = range.lowerBound
+ try fileHandle.seek(toOffset: offset)
+
+ let byteCount = Int(range.upperBound - range.lowerBound) + 1
+ let chunk = try fileHandle.read(upToCount: byteCount)
+ return chunk
+ }
+}
diff --git a/Sources/InfomaniakCore/Chunking/FileHandlable.swift b/Sources/InfomaniakCore/Chunking/FileHandlable.swift
index 64b4d27..20d9c7d 100644
--- a/Sources/InfomaniakCore/Chunking/FileHandlable.swift
+++ b/Sources/InfomaniakCore/Chunking/FileHandlable.swift
@@ -20,7 +20,7 @@ import Foundation
/// Something that matches most of the FileHandle specification, used for testing
@available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *)
-protocol FileHandlable {
+protocol FileHandlable: Sendable {
var availableData: Data { get }
var description: String { get }
diff --git a/Tests/InfomaniakCoreTests/Chunking/UTChunkProvider.swift b/Tests/InfomaniakCoreTests/Chunking/UTChunkProvider.swift
index 64db526..b46df9a 100644
--- a/Tests/InfomaniakCoreTests/Chunking/UTChunkProvider.swift
+++ b/Tests/InfomaniakCoreTests/Chunking/UTChunkProvider.swift
@@ -106,85 +106,4 @@ final class UTChunkProvider: XCTestCase {
XCTAssertEqual(mckFileHandle.readUpToCountCallCount, expectedRangesCount)
XCTAssertEqual(chunks.count, expectedRangesCount)
}
-
- // MARK: - readChunk(range:)
-
- func testReadChunk_validChunk() throws {
- // GIVEN
- let range: DataRange = 0 ... 1
- let mckFileHandle = MCKFileHandlable()
- mckFileHandle.readUpToCountClosure = { _ in Data() }
- mckFileHandle.seekToOffsetClosure = { index in
- XCTAssertEqual(index, range.lowerBound)
- }
-
- let chunkProvider = ChunkProvider(mockedHandlable: mckFileHandle, ranges: [])
-
- // WHEN
- do {
- let chunk = try chunkProvider.readChunk(range: range)
- XCTAssertNotNil(chunk)
- } catch {
- XCTFail("Unexpected :\(error)")
- return
- }
-
- // THEN
- XCTAssertEqual(mckFileHandle.seekToOffsetCallCount, 1)
- XCTAssertEqual(mckFileHandle.readUpToCountCallCount, 1)
- }
-
- func testReadChunk_throwErrorOnSeek() throws {
- // GIVEN
- let range: DataRange = 0 ... 1
- let mckFileHandle = MCKFileHandlable()
- mckFileHandle.readUpToCountClosure = { _ in Data() }
- mckFileHandle.seekToOffsetError = NSError(domain: "k", code: 1337)
-
- let chunkProvider = ChunkProvider(mockedHandlable: mckFileHandle, ranges: [])
-
- // WHEN
- do {
- _ = try chunkProvider.readChunk(range: range)
- XCTFail("Unexpected")
- return
- } catch {
- guard (error as NSError).code == 1337 else {
- XCTFail("Unexpected")
- return
- }
- // all good
- }
-
- // THEN
- XCTAssertEqual(mckFileHandle.seekToOffsetCallCount, 1)
- XCTAssertEqual(mckFileHandle.readUpToCountCallCount, 0)
- }
-
- func testReadChunk_throwErrorOnRead() throws {
- // GIVEN
- let range: DataRange = 0 ... 1
- let mckFileHandle = MCKFileHandlable()
- mckFileHandle.readUpToCountClosure = { _ in Data() }
- mckFileHandle.readUpToCountError = NSError(domain: "k", code: 1337)
-
- let chunkProvider = ChunkProvider(mockedHandlable: mckFileHandle, ranges: [])
-
- // WHEN
- do {
- _ = try chunkProvider.readChunk(range: range)
- XCTFail("Unexpected")
- return
- } catch {
- guard (error as NSError).code == 1337 else {
- XCTFail("Unexpected")
- return
- }
- // all good
- }
-
- // THEN
- XCTAssertEqual(mckFileHandle.seekToOffsetCallCount, 1)
- XCTAssertEqual(mckFileHandle.readUpToCountCallCount, 1)
- }
}
diff --git a/Tests/InfomaniakCoreTests/Chunking/UTChunkReader.swift b/Tests/InfomaniakCoreTests/Chunking/UTChunkReader.swift
new file mode 100644
index 0000000..6676d2b
--- /dev/null
+++ b/Tests/InfomaniakCoreTests/Chunking/UTChunkReader.swift
@@ -0,0 +1,106 @@
+/*
+ Infomaniak kDrive - 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 .
+ */
+
+import Foundation
+@testable import InfomaniakCore
+import XCTest
+
+/// Unit Tests of the ChunkReader
+@available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *)
+final class UTChunkReader: XCTestCase {
+ // MARK: - readChunk(range:)
+
+ func testReadChunk_validChunk() throws {
+ // GIVEN
+ let range: DataRange = 0 ... 1
+ let mckFileHandle = MCKFileHandlable()
+ mckFileHandle.readUpToCountClosure = { _ in Data() }
+ mckFileHandle.seekToOffsetClosure = { index in
+ XCTAssertEqual(index, range.lowerBound)
+ }
+
+ let chunkProvider = ChunkReader(mockedHandlable: mckFileHandle)
+
+ // WHEN
+ do {
+ let chunk = try chunkProvider.readChunk(range: range)
+ XCTAssertNotNil(chunk)
+ } catch {
+ XCTFail("Unexpected :\(error)")
+ return
+ }
+
+ // THEN
+ XCTAssertEqual(mckFileHandle.seekToOffsetCallCount, 1)
+ XCTAssertEqual(mckFileHandle.readUpToCountCallCount, 1)
+ }
+
+ func testReadChunk_throwErrorOnSeek() throws {
+ // GIVEN
+ let range: DataRange = 0 ... 1
+ let mckFileHandle = MCKFileHandlable()
+ mckFileHandle.readUpToCountClosure = { _ in Data() }
+ mckFileHandle.seekToOffsetError = NSError(domain: "k", code: 1337)
+
+ let chunkProvider = ChunkReader(mockedHandlable: mckFileHandle)
+
+ // WHEN
+ do {
+ _ = try chunkProvider.readChunk(range: range)
+ XCTFail("Unexpected")
+ return
+ } catch {
+ guard (error as NSError).code == 1337 else {
+ XCTFail("Unexpected")
+ return
+ }
+ // all good
+ }
+
+ // THEN
+ XCTAssertEqual(mckFileHandle.seekToOffsetCallCount, 1)
+ XCTAssertEqual(mckFileHandle.readUpToCountCallCount, 0)
+ }
+
+ func testReadChunk_throwErrorOnRead() throws {
+ // GIVEN
+ let range: DataRange = 0 ... 1
+ let mckFileHandle = MCKFileHandlable()
+ mckFileHandle.readUpToCountClosure = { _ in Data() }
+ mckFileHandle.readUpToCountError = NSError(domain: "k", code: 1337)
+
+ let chunkProvider = ChunkReader(mockedHandlable: mckFileHandle)
+
+ // WHEN
+ do {
+ _ = try chunkProvider.readChunk(range: range)
+ XCTFail("Unexpected")
+ return
+ } catch {
+ guard (error as NSError).code == 1337 else {
+ XCTFail("Unexpected")
+ return
+ }
+ // all good
+ }
+
+ // THEN
+ XCTAssertEqual(mckFileHandle.seekToOffsetCallCount, 1)
+ XCTAssertEqual(mckFileHandle.readUpToCountCallCount, 1)
+ }
+}