Skip to content

Commit

Permalink
Add cancel operation feature
Browse files Browse the repository at this point in the history
  • Loading branch information
jwelton committed Jan 19, 2018
1 parent a289cf8 commit cb0a054
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 5 deletions.
28 changes: 23 additions & 5 deletions Zip/Zip.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ public enum ZipError: Error {
case unzipFail
/// Zip fail
case zipFail

/// Operation Cancelled
case operationCancelled

/// User readable description
public var description: String {
switch self {
case .fileNotFound: return NSLocalizedString("File not found.", comment: "")
case .unzipFail: return NSLocalizedString("Failed to unzip file.", comment: "")
case .zipFail: return NSLocalizedString("Failed to zip file.", comment: "")
case .operationCancelled: return NSLocalizedString("Operation cancelled", comment: "")
}
}
}
Expand All @@ -50,12 +53,16 @@ public enum ZipCompression: Int {

/// Zip class
public class Zip {

/**
Set of vaild file extensions
*/
internal static var customFileExtensions: Set<String> = []

/**
Cancellation block. This is set once the progress tracker is has been created
*/
public static var cancelCurrentOperation: (()->Void) = { }

// MARK: Lifecycle

/**
Expand Down Expand Up @@ -113,6 +120,8 @@ public class Zip {
progressTracker.isPausable = false
progressTracker.kind = ProgressKind.file

cancelCurrentOperation = { progressTracker.cancel() }

// Begin unzipping
let zip = unzOpen64(path)
defer {
Expand Down Expand Up @@ -234,16 +243,19 @@ public class Zip {
}

progressTracker.completedUnitCount = Int64(currentPosition)

} while (ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE)

} while (ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE) && !progressTracker.isCancelled

guard !progressTracker.isCancelled else {
throw ZipError.operationCancelled
}

// Completed. Update progress handler.
if let progressHandler = progress{
progressHandler(1.0)
}

progressTracker.completedUnitCount = Int64(totalSize)

}

// MARK: Zip
Expand Down Expand Up @@ -297,6 +309,8 @@ public class Zip {
progressTracker.isPausable = false
progressTracker.kind = ProgressKind.file

cancelCurrentOperation = { progressTracker.cancel() }

// Begin Zipping
let zip = zipOpen(destinationPath, APPEND_STATUS_CREATE)
for path in processedPaths {
Expand Down Expand Up @@ -338,6 +352,10 @@ public class Zip {
}
var length: Int = 0
while (feof(input) == 0) {
guard !progressTracker.isCancelled else {
throw ZipError.operationCancelled
}

length = fread(buffer, 1, chunkSize, input)
zipWriteInFileInZip(zip, buffer, UInt32(length))
}
Expand Down
65 changes: 65 additions & 0 deletions ZipTests/ZipTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,69 @@ class ZipTests: XCTestCase {
XCTAssertTrue(Zip.isValidFileExtension("cbz"))
}

func testCancelDuringZipCancels() {
var currentProgress: Double = 0

let expect = expectation(description: "Zip operation should throw .OperationCancelled")

do {
let progress = Progress()
progress.totalUnitCount = 1

let imageURL1 = Bundle(for: ZipTests.self).url(forResource: "3crBXeO", withExtension: "gif")!
let imageURL2 = Bundle(for: ZipTests.self).url(forResource: "kYkLkPf", withExtension: "gif")!
let documentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
let zipFilePath = documentsFolder.appendingPathComponent("archive.zip")!

try Zip.zipFiles(paths: [imageURL1, imageURL2], zipFilePath: zipFilePath, password: nil) { progress in
currentProgress = progress

if progress > 0 {
Zip.cancelCurrentOperation()
}
}

}
catch {
XCTAssertEqual(error as? ZipError, .operationCancelled)
XCTAssertLessThan(currentProgress, 1, "Progress should be less than 1 when cancelling the current operation")
expect.fulfill()
}

waitForExpectations(timeout: 5) { error in
XCTAssertNil(error)
}
}

func testCancelDuringUnzipCancels() {
var currentProgress: Double = 0
let expect = expectation(description: "Unzip operation should throw .OperationCancelled")

do {
let progress = Progress()
progress.totalUnitCount = 1

let bookURL = Bundle(for: ZipTests.self).url(forResource: "bb8", withExtension: "zip")!
let documentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
let zipFilePath = documentsFolder.appendingPathComponent("contents")!

try Zip.unzipFile(bookURL, destination: zipFilePath, overwrite: true, password: nil, progress: { progress in
currentProgress = progress

if progress > 0 {
Zip.cancelCurrentOperation()
}
}) { _ in }
}
catch {
XCTAssertEqual(error as? ZipError, .operationCancelled)
XCTAssertLessThan(currentProgress, 1, "Progress should be less than 1 when cancelling the current operation")
expect.fulfill()
}

waitForExpectations(timeout: 5) { error in
XCTAssertNil(error)
}
}

}

0 comments on commit cb0a054

Please sign in to comment.