Skip to content
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
29 changes: 25 additions & 4 deletions IONFilesystemLib/IONFILEManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ extension IONFILEManager: IONFILEDirectoryManager {

public func removeDirectory(atURL pathURL: URL, includeIntermediateDirectories: Bool) throws {
try withSecurityScopedAccess(to: pathURL) {
guard fileManager.fileExists(atPath: pathURL.urlPath) else {
throw IONFILEFileManagerError.fileNotFound(atPath: pathURL.urlPath)
}
if !includeIntermediateDirectories {
let directoryContents = try listDirectory(atURL: pathURL)
if !directoryContents.isEmpty {
Expand All @@ -40,7 +43,10 @@ extension IONFILEManager: IONFILEDirectoryManager {

public func listDirectory(atURL pathURL: URL) throws -> [URL] {
try withSecurityScopedAccess(to: pathURL) {
try fileManager.contentsOfDirectory(at: pathURL, includingPropertiesForKeys: nil)
guard fileManager.fileExists(atPath: pathURL.urlPath) else {
throw IONFILEFileManagerError.fileNotFound(atPath: pathURL.urlPath)
}
return try fileManager.contentsOfDirectory(at: pathURL, includingPropertiesForKeys: nil)
}
}
}
Expand All @@ -56,8 +62,11 @@ extension IONFILEManager: IONFILEFileManager {

public func readEntireFile(atURL fileURL: URL, withEncoding encoding: IONFILEEncoding, andOffset offset: Int, andLength length: Int) throws -> IONFILEEncodingValueMapper {
try withSecurityScopedAccess(to: fileURL) {
guard fileManager.fileExists(atPath: fileURL.urlPath) else {
throw IONFILEFileManagerError.fileNotFound(atPath: fileURL.urlPath)
}
let result: IONFILEEncodingValueMapper
if (offset > 0 || length > 0) {
if offset > 0 || length > 0 {
result = try readPartialFile(fileURL, encoding, offset, length)
} else {
switch encoding {
Expand All @@ -75,7 +84,10 @@ extension IONFILEManager: IONFILEFileManager {

public func readFileInChunks(atURL fileURL: URL, withEncoding encoding: IONFILEEncoding, andChunkSize chunkSize: Int, andOffset offset: Int, andLength length: Int) throws -> IONFILEChunkPublisher {
try withSecurityScopedAccess(to: fileURL) {
.init(fileURL, chunkSize, encoding, offset, length)
guard fileManager.fileExists(atPath: fileURL.urlPath) else {
throw IONFILEFileManagerError.fileNotFound(atPath: fileURL.urlPath)
}
return .init(fileURL, chunkSize, encoding, offset, length)
}
}

Expand Down Expand Up @@ -147,13 +159,19 @@ extension IONFILEManager: IONFILEFileManager {

public func getItemAttributes(atURL url: URL) throws -> IONFILEItemAttributeModel {
try withSecurityScopedAccess(to: url) {
guard fileManager.fileExists(atPath: url.urlPath) else {
throw IONFILEFileManagerError.fileNotFound(atPath: url.urlPath)
}
let attributesDictionary = try fileManager.attributesOfItem(atPath: url.urlPath)
return .create(from: attributesDictionary)
}
}

public func renameItem(fromURL originURL: URL, toURL destinationURL: URL) throws {
try withSecurityScopedAccess(to: originURL) {
guard fileManager.fileExists(atPath: originURL.urlPath) else {
throw IONFILEFileManagerError.fileNotFound(atPath: originURL.urlPath)
}
try withSecurityScopedAccess(to: destinationURL) {
guard try shouldPerformDualPathOperation(fromURL: originURL, toURL: destinationURL) else {
return
Expand All @@ -165,6 +183,9 @@ extension IONFILEManager: IONFILEFileManager {

public func copyItem(fromURL originURL: URL, toURL destinationURL: URL) throws {
try withSecurityScopedAccess(to: originURL) {
guard fileManager.fileExists(atPath: originURL.urlPath) else {
throw IONFILEFileManagerError.fileNotFound(atPath: originURL.urlPath)
}
try withSecurityScopedAccess(to: destinationURL) {
guard try shouldPerformDualPathOperation(fromURL: originURL, toURL: destinationURL) else {
return
Expand Down Expand Up @@ -271,7 +292,7 @@ private extension IONFILEManager {
with: "/",
options: .regularExpression
)
if (urlToReturn.absoluteString.contains(":///")) {
if urlToReturn.absoluteString.contains(":///") {
// the regex may ommit a slash after ://, which is incorrect because it breaks in case of an absolute file path
urlStringWithoutDuplicateSeparators = urlStringWithoutDuplicateSeparators.replacingOccurrences(of: "://", with: ":///")
}
Expand Down
42 changes: 35 additions & 7 deletions IONFilesystemLibTests/IONFILEDirectoryManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase {
// MARK: - 'removeDirectory' tests
func test_removeDirectory_butFails_shouldReturnAnError() {
let error = MockFileManagerError.deleteDirectoryError
createFileManager(with: error)
createFileManager(with: error, exclusions: [])
let testDirectory = URL(filePath: "/test/directory")
let shouldIncludeIntermediateDirectories = true

Expand All @@ -81,10 +81,24 @@ final class IONFILEDirectoryManagerTests: XCTestCase {
XCTAssertEqual($0 as? MockFileManagerError, error)
}
}

func test_removeDirectory_butFails_shouldReturnFileNotFound() {
createFileManager(fileExists: false, exclusions: [])
let testDirectory = URL(filePath: "/test/directory")
let shouldIncludeIntermediateDirectories = true

// When
XCTAssertThrowsError(
try sut.removeDirectory(atURL: testDirectory, includeIntermediateDirectories: shouldIncludeIntermediateDirectories)
) {
// Then
XCTAssertEqual($0 as? IONFILEFileManagerError,.fileNotFound(atPath: testDirectory.urlPath))
}
}

func test_removeDirectory_includingIntermediateDirectories_shouldBeSuccessful() throws {
// Given
let fileManager = createFileManager()
let fileManager = createFileManager(exclusions: [])
let testDirectory = URL(filePath: "/test/directory")
let shouldIncludeIntermediateDirectories = true

Expand All @@ -97,7 +111,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase {

func test_removeDirectory_excludingIntermediateDirectories_directoryDoesntHaveContent_shouldBeSuccessful() throws {
// Given
let fileManager = createFileManager()
let fileManager = createFileManager(exclusions: [])
let testDirectory = URL(filePath: "/test/directory")
let shouldIncludeIntermediateDirectories = false

Expand All @@ -109,7 +123,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase {
}

func test_removeDirectory_excludingIntermediateDirectories_directoryHasContent_shouldReturnAnError() {
createFileManager(shouldDirectoryHaveContent: true)
createFileManager(shouldDirectoryHaveContent: true, exclusions: [])
let testDirectory = URL(filePath: "/test/directory")
let shouldIncludeIntermediateDirectories = false

Expand All @@ -125,7 +139,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase {
// MARK: - 'listDirectory' tests
func test_listDirectory_withNoContent_shouldReturnEmptyArray() throws {
// Given
let fileManager = createFileManager()
let fileManager = createFileManager(exclusions: [])
let testDirectory = URL(filePath: "/test/directory")

// When
Expand All @@ -139,7 +153,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase {
// MARK: - 'listDirectory' tests
func test_listDirectory_withContent_shouldReturnNotEmptyArray() throws {
// Given
let fileManager = createFileManager(shouldDirectoryHaveContent: true)
let fileManager = createFileManager(shouldDirectoryHaveContent: true, exclusions: [])
let testDirectory = URL(filePath: "/test/directory")

// When
Expand All @@ -153,7 +167,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase {
func test_listDirectory_butFails_shouldReturnAnError() {
// Given
let error = MockFileManagerError.readDirectoryError
createFileManager(with: error)
createFileManager(with: error, exclusions: [])
let testDirectory = URL(filePath: "/test/directory")

// When
Expand All @@ -164,6 +178,20 @@ final class IONFILEDirectoryManagerTests: XCTestCase {
XCTAssertEqual($0 as? MockFileManagerError, error)
}
}

func test_listDirectory_butFails_shouldReturnFileNotFound() {
// Given
createFileManager(fileExists: false, exclusions: [])
let testDirectory = URL(filePath: "/test/directory")

// When
XCTAssertThrowsError(
try sut.listDirectory(atURL: testDirectory)
) {
// Then
XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: testDirectory.urlPath))
}
}
}

private extension IONFILEDirectoryManagerTests {
Expand Down
80 changes: 71 additions & 9 deletions IONFilesystemLibTests/IONFILEFileManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ extension IONFILEFileManagerTests {
XCTAssertThrowsError(try fetchEntireContent(forURL: fileURL, withEncoding: .string(encoding: .utf8)))
}

func test_readEntireFile_thatDoesntExist_returnsFileNotFound() throws {
// Given
createFileManager(fileExists: false)
let fileURL = URL(filePath: "/file/directory")

// When
XCTAssertThrowsError(try sut.readEntireFile(atURL: fileURL, withEncoding: .string(encoding: .utf8))) {
//Then
XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: fileURL.urlPath))
}
}

func test_readEntireFile_offsetAndLengthWithExampleEncoding_returnsCorrectData() throws {
// Given
createFileManager()
Expand Down Expand Up @@ -104,7 +116,7 @@ extension IONFILEFileManagerTests {
let result = try sut.readEntireFile(atURL: fileURL, withEncoding: .string(encoding: encoding), andOffset: offset, andLength: length)

// Then
guard case .string(let resultEncoding, let resultValue) = result else {
guard case .string(_, let resultValue) = result else {
XCTFail("Wrong result type")
return
}
Expand Down Expand Up @@ -162,6 +174,18 @@ extension IONFILEFileManagerTests {
XCTAssertThrowsError(try fetchChunkedContent(forURL: fileURL, withEncoding: .string(encoding: .utf8)))
}

func test_readFileInChunks_thatDoesntExist_returnsFileNotFound() throws {
// Given
createFileManager(fileExists: false)
let fileURL = URL(filePath: "/file/directory")

// When
XCTAssertThrowsError(try fetchChunkedContent(forURL: fileURL, withEncoding: .string(encoding: .utf8))) {
// Then
XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: fileURL.urlPath))
}
}

func test_readFileInChunks_withOffsetAndLength_returnsContentSuccessfully() throws {
// Given
createFileManager()
Expand Down Expand Up @@ -505,11 +529,11 @@ extension IONFILEFileManagerTests {
// Then
XCTAssertEqual(fileManager.capturedIntermediateDirectories, shouldIncludeIntermediateDirectories)
XCTAssertEqual(fileManager.capturedPath, parentFolderURL)


fileManager.fileExists = true
let savedFileContent = try fetchEntireContent(forURL: fileURL, withEncoding: .string(encoding: stringEncoding))
XCTAssertEqual(savedFileContent, contentToSave)

fileManager.fileExists = true

try sut.deleteFile(atURL: fileURL) // keep things clean by deleting created file
}

Expand Down Expand Up @@ -610,11 +634,11 @@ extension IONFILEFileManagerTests {
XCTAssertEqual(fileManager.capturedIntermediateDirectories, shouldIncludeIntermediateDirectories)

// Then
fileManager.fileExists = true
let savedFileContent = try fetchEntireContent(forURL: fileURL, withEncoding: .string(encoding: stringEncoding))

XCTAssertEqual(savedFileContent, contentToAdd)

fileManager.fileExists = true
try sut.deleteFile(atURL: fileURL) // keep things clean by deleting created file
}

Expand Down Expand Up @@ -731,13 +755,25 @@ extension IONFILEFileManagerTests {
XCTAssertEqual($0 as? MockFileManagerError, error)
}
}

func test_getItemAttributes_fileDoesntExist_returnsFileNotFound() {
// Given
createFileManager(fileExists: false)
let testURL = URL(filePath: "/test/missing-file")

// When
XCTAssertThrowsError(try sut.getItemAttributes(atURL: testURL)) {
// Then
XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: testURL.urlPath))
}
}
}

// MARK: - 'renameItem' tests
extension IONFILEFileManagerTests {
func test_renameItem_shouldBeSuccessful() throws {
// Given
let fileManager = createFileManager(fileExists: false)
let fileManager = createFileManager()
let originPath = URL(filePath: "/test/origin")
let destinationPath = URL(filePath: "/test/destination")

Expand All @@ -751,7 +787,7 @@ extension IONFILEFileManagerTests {

func test_renameItem_sameOriginAndDestination_shouldDoNothing() throws {
// Given
let fileManager = createFileManager(fileExists: false)
let fileManager = createFileManager()
let originPath = URL(filePath: "/test/origin")
let destinationPath = URL(filePath: "/test/origin")

Expand All @@ -762,6 +798,19 @@ extension IONFILEFileManagerTests {
XCTAssertNil(fileManager.capturedOriginPath)
XCTAssertNil(fileManager.capturedDestinationPath)
}

func test_renameItem_fileDoesntExist_returnsFileNotFound() {
// Given
createFileManager(fileExists: false)
let originPath = URL(filePath: "/test/origin")
let destinationPath = URL(filePath: "/test/destination")

// When
XCTAssertThrowsError(try sut.renameItem(fromURL: originPath, toURL: destinationPath)) {
// Then
XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: originPath.urlPath))
}
}

func test_renameDirectory_alreadyExisting_shouldBeSuccessful() throws {
// Given
Expand Down Expand Up @@ -811,7 +860,7 @@ extension IONFILEFileManagerTests {
extension IONFILEFileManagerTests {
func test_copyItem_shouldBeSuccessful() throws {
// Given
let fileManager = createFileManager(fileExists: false)
let fileManager = createFileManager()
let originPath = URL(filePath: "/test/origin")
let destinationPath = URL(filePath: "/test/destination")

Expand All @@ -825,7 +874,7 @@ extension IONFILEFileManagerTests {

func test_copyItem_sameOriginAndDestination_shouldDoNothing() throws {
// Given
let fileManager = createFileManager(fileExists: false)
let fileManager = createFileManager()
let originPath = URL(filePath: "/test/origin")
let destinationPath = URL(filePath: "/test/origin")

Expand All @@ -837,6 +886,19 @@ extension IONFILEFileManagerTests {
XCTAssertNil(fileManager.capturedDestinationPath)

}

func test_copyItem_fileDoesntExist_returnsFileNotFound() {
// Given
createFileManager(fileExists: false)
let originPath = URL(filePath: "/test/origin")
let destinationPath = URL(filePath: "/test/destination")

// When
XCTAssertThrowsError(try sut.copyItem(fromURL: originPath, toURL: destinationPath)) {
// Then
XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: originPath.urlPath))
}
}

func test_copyDirectory_alreadyExisting_shouldBeSuccessful() throws {
// Given
Expand Down
Loading