diff --git a/Cassette.xcodeproj/project.pbxproj b/Cassette.xcodeproj/project.pbxproj index 09f6548..a75268a 100644 --- a/Cassette.xcodeproj/project.pbxproj +++ b/Cassette.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 6E126C031B1F816300856CCA /* CASQueueFileTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E126C021B1F816300856CCA /* CASQueueFileTests.m */; }; 6E126C0E1B1F818100856CCA /* CASQueueFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E126C0C1B1F818100856CCA /* CASQueueFile.h */; }; 6E126C0F1B1F818100856CCA /* CASQueueFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E126C0D1B1F818100856CCA /* CASQueueFile.m */; }; + 86D0403326BC33D5009A1615 /* CASSwiftChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86D0403226BC33D5009A1615 /* CASSwiftChanges.swift */; }; 91C04B422677CA8000874F5E /* CASDataSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 91C04B412677CA8000874F5E /* CASDataSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 91C04B482677CB8700874F5E /* CASDefaultDataSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 91C04B462677CB8700874F5E /* CASDefaultDataSerializer.h */; }; 91C04B492677CB8700874F5E /* CASDefaultDataSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C04B472677CB8700874F5E /* CASDefaultDataSerializer.m */; }; @@ -114,6 +115,8 @@ 6E126C0C1B1F818100856CCA /* CASQueueFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CASQueueFile.h; sourceTree = ""; }; 6E126C0D1B1F818100856CCA /* CASQueueFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CASQueueFile.m; sourceTree = ""; }; 7F66F602AB0D8B57684B1FDD /* Pods-Cassette.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cassette.debug.xcconfig"; path = "Target Support Files/Pods-Cassette/Pods-Cassette.debug.xcconfig"; sourceTree = ""; }; + 86D0402F26BC338D009A1615 /* CassetteTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CassetteTests-Bridging-Header.h"; sourceTree = ""; }; + 86D0403226BC33D5009A1615 /* CASSwiftChanges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CASSwiftChanges.swift; sourceTree = ""; }; 91C04B412677CA8000874F5E /* CASDataSerializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CASDataSerializer.h; sourceTree = ""; }; 91C04B462677CB8700874F5E /* CASDefaultDataSerializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CASDefaultDataSerializer.h; sourceTree = ""; }; 91C04B472677CB8700874F5E /* CASDefaultDataSerializer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CASDefaultDataSerializer.m; sourceTree = ""; }; @@ -253,6 +256,8 @@ 6E126C021B1F816300856CCA /* CASQueueFileTests.m */, 3C4A836F2311DD4000D06FAE /* CASFileObjectQueueTests.m */, 3C4A83792313075000D06FAE /* CASInMemoryObjectQueueTests.m */, + 86D0403226BC33D5009A1615 /* CASSwiftChanges.swift */, + 86D0402F26BC338D009A1615 /* CassetteTests-Bridging-Header.h */, ); path = CassetteTests; sourceTree = ""; @@ -416,6 +421,7 @@ 6E126BFA1B1F816300856CCA = { CreatedOnToolsVersion = 6.3.1; DevelopmentTeam = 57Y47U492U; + LastSwiftMigration = 1250; }; 92FAF8E126A355BE00EF78A7 = { CreatedOnToolsVersion = 12.5; @@ -554,6 +560,7 @@ buildActionMask = 2147483647; files = ( 3C4A83702311DD4000D06FAE /* CASFileObjectQueueTests.m in Sources */, + 86D0403326BC33D5009A1615 /* CASSwiftChanges.swift in Sources */, 3C4A837A2313075000D06FAE /* CASInMemoryObjectQueueTests.m in Sources */, 6E126C031B1F816300856CCA /* CASQueueFileTests.m in Sources */, ); @@ -816,6 +823,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 20064E82733FF0AC4F765955 /* Pods-Cassette-CassetteTests.debug.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -831,6 +839,9 @@ "@loader_path/Frameworks", ); PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "CassetteTests/CassetteTests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -838,6 +849,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 0D910F2975ED908A5492A170 /* Pods-Cassette-CassetteTests.release.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -849,6 +861,8 @@ "@loader_path/Frameworks", ); PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "CassetteTests/CassetteTests-Bridging-Header.h"; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/Cassette/CASObjectQueue.h b/Cassette/CASObjectQueue.h index 24cc8b6..9ca4ab3 100644 --- a/Cassette/CASObjectQueue.h +++ b/Cassette/CASObjectQueue.h @@ -22,14 +22,14 @@ NS_ASSUME_NONNULL_BEGIN * Closes the queue. Do not use this object after this method returns. * Returns YES on success. On failure, returns NO and sets *error to the error. */ -- (BOOL)closeAndReturnError:(NSError * __autoreleasing * _Nullable)error; +- (BOOL)closeAndReturnError:(NSError * __autoreleasing * _Nullable)error NS_SWIFT_NAME(close()); /** * Adds an element to the end of the queue. * * Please use the API @c add:error: instead. */ -- (void)add:(T)data __attribute__((deprecated("Use -add:error: instead."))); +- (void)add:(T)data __attribute__((deprecated("Use -add:error: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); /** * Adds an element to the end of the queue. @@ -59,7 +59,13 @@ NS_ASSUME_NONNULL_BEGIN * * Please use the API @c peek:error: instead. */ -- (nullable T)peek __attribute__((deprecated("Use -peek:error: instead."))); +- (nullable T)peek __attribute__((deprecated("Use -peek:error: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); + +/** + * Returns the head of the queue, or nil if the queue is empty. Does not modify the + * queue. + */ +- (nullable T)peekWithError:(NSError * __autoreleasing * _Nullable)error NS_SWIFT_NAME(peek()); /** * Reads up to the specified amount of entries from the head of the queue without removing @@ -69,7 +75,7 @@ NS_ASSUME_NONNULL_BEGIN * * Please use the API @c peek:error: instead. */ -- (NSArray *)peek:(NSUInteger)amount __attribute__((deprecated("Use -peek:error: instead."))); +- (NSArray *)peek:(NSUInteger)amount __attribute__((deprecated("Use -peek:error: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); /** * Reads up to the specified amount of entries from the head of the queue without removing @@ -86,14 +92,14 @@ NS_ASSUME_NONNULL_BEGIN * * Please use the API @c pop:error: instead. */ -- (void)pop __attribute__((deprecated("Use -pop:error: instead.")));; +- (void)pop __attribute__((deprecated("Use -pop:error: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift");; /** * Removes the specified amount of entries from the head of the queue. * * Please use the API @c pop:error: instead. */ -- (void)pop:(NSUInteger)amount __attribute__((deprecated("Use -peek:error: instead."))); +- (void)pop:(NSUInteger)amount __attribute__((deprecated("Use -peek:error: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); /** * Removes the specified amount of entries from the head of the queue. @@ -106,13 +112,13 @@ NS_ASSUME_NONNULL_BEGIN * * Please use the API @c clearAndReturnError: instead. */ -- (void)clear __attribute__((deprecated("Use -clearAndReturnError: instead.")));; +- (void)clear __attribute__((deprecated("Use -clearAndReturnError: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); /** * Clears this queue. Truncates the file to the initial size. * Returns YES on success. On failure, returns NO and sets *error to the error. */ -- (BOOL)clearAndReturnError:(NSError * __autoreleasing * _Nullable)error; +- (BOOL)clearAndReturnError:(NSError * __autoreleasing * _Nullable)error NS_SWIFT_NAME(clear()); @end diff --git a/Cassette/CASObjectQueue.m b/Cassette/CASObjectQueue.m index 55ec9ba..c294e59 100644 --- a/Cassette/CASObjectQueue.m +++ b/Cassette/CASObjectQueue.m @@ -46,6 +46,10 @@ - (id)peek { return [self peek:1 error:NULL].firstObject; } +- (id)peekWithError:(NSError * __autoreleasing * _Nullable)error { + return [self peek:1 error:error].firstObject; +} + - (NSArray *)peek:(NSUInteger)amount { return [self peek:amount error:NULL] ?: @[]; } diff --git a/Cassette/CASQueueFile.h b/Cassette/CASQueueFile.h index 52f408c..1e9f083 100644 --- a/Cassette/CASQueueFile.h +++ b/Cassette/CASQueueFile.h @@ -38,14 +38,14 @@ NS_ASSUME_NONNULL_BEGIN * Closes the queue file. Do not use this object after this method returns. * Returns YES on success. On failure, returns NO and sets *error to the error. */ -- (BOOL)closeAndReturnError:(NSError * __autoreleasing * _Nullable)error; +- (BOOL)closeAndReturnError:(NSError * __autoreleasing * _Nullable)error NS_SWIFT_NAME(close()); /** * Adds an element to the end of the queue. * * Please use the API @c add:error: instead. */ -- (void)add:(NSData *)data __attribute__((deprecated("Use -add:error: instead."))); +- (void)add:(NSData *)data __attribute__((deprecated("Use -add:error: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); /** * Adds an element to the end of the queue. @@ -77,7 +77,7 @@ NS_ASSUME_NONNULL_BEGIN * * Please use the API @c peek:error: instead. */ -- (NSArray *)peek:(NSUInteger)amount __attribute__((deprecated("Use peek:error: instead."))); +- (NSArray *)peek:(NSUInteger)amount __attribute__((deprecated("Use peek:error: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); /** * Reads up to the specified amount of entries from the head of the queue without removing @@ -94,7 +94,7 @@ NS_ASSUME_NONNULL_BEGIN * * Please use the API @c pop:error: instead. */ -- (void)pop:(NSUInteger)amount __attribute__((deprecated("Use -pop:error: instead."))); +- (void)pop:(NSUInteger)amount __attribute__((deprecated("Use -pop:error: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); /** * Removes the specified amount of entries from the head of the queue. @@ -107,13 +107,13 @@ NS_ASSUME_NONNULL_BEGIN * * Please use the API @c clearAndReturnError: instead. */ -- (void)clear __attribute__((deprecated("Use -clearAndReturnError: instead."))); +- (void)clear __attribute__((deprecated("Use -clearAndReturnError: instead."))) NS_SWIFT_UNAVAILABLE("Not available in Swift"); /** * Clears this queue. Truncates the file to the initial size. * Returns YES on success. On failure, returns NO and sets *error to the error. */ -- (BOOL)clearAndReturnError:(NSError * __autoreleasing * _Nullable)error; +- (BOOL)clearAndReturnError:(NSError * __autoreleasing * _Nullable)error NS_SWIFT_NAME(clear()); @end diff --git a/CassetteTests/CASSwiftChanges.swift b/CassetteTests/CASSwiftChanges.swift new file mode 100644 index 0000000..7e7923d --- /dev/null +++ b/CassetteTests/CASSwiftChanges.swift @@ -0,0 +1,75 @@ +// +// CASSwiftChanges.swift +// CassetteTests +// +// Created by Alfons Hoogervorst on 05/08/2021. +// + +import XCTest +import Cassette + +class CASSwiftChanges: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + fileprivate func testOperations(with queue: CASObjectQueue) { + try? queue.add(1) + try? queue.add(2) + try? queue.add(3) + XCTAssert(queue.size() == 3, "Should contain 3 elements") + try? queue.pop(1) + let secondValue = try? queue.peek() + XCTAssert(secondValue == 2, "Should be value 2") + try? queue.clear() + XCTAssert(queue.size() == 0, "Should have zero items") + try? queue.add(NSNumber(integerLiteral: 2)) + XCTAssert(queue.size() == 1, "Should have 1 item") + try? queue.clear() + XCTAssert(queue.size() == 0, "Should have zero items") + try? queue.add(4) + let fourthValue = try? queue.peek() + XCTAssert(fourthValue == 4, "Should be value 4") + try? queue.pop(1) + XCTAssertThrowsError(try queue.peek(), "Should throw an error") + } + + func testChangesCASInMemoryQueue() throws { + let queue = CASInMemoryObjectQueue() + self.testOperations(with: queue) + } + + func testChangesCASFileObjectQueue() throws { + let queueFileName = "\(NSTemporaryDirectory())/\(UUID().uuidString)" + // remove old remnants + try? FileManager.default.removeItem(atPath: queueFileName) + let queue = try? CASFileObjectQueue(absolutePath: queueFileName) + XCTAssertNotNil(queue) + self.testOperations(with: queue!) + } + + func testChangesCASFileObjectQueueReopen() throws { + let queueFileName = "\(NSTemporaryDirectory())/\(UUID().uuidString)" + // remove old remnants + try? FileManager.default.removeItem(atPath: queueFileName) + let queue = try? CASFileObjectQueue(absolutePath: queueFileName) + XCTAssertNotNil(queue) + self.testOperations(with: queue!) + try? queue?.add(5) + XCTAssertNoThrow(try queue?.close()) + let reopenedQueue = try? CASFileObjectQueue(absolutePath: queueFileName) + XCTAssertNotNil(reopenedQueue) + let value = try? reopenedQueue?.peek(5) + XCTAssertNotNil(value) + XCTAssert(value!.count == 1, "Array with one element") + XCTAssertNoThrow(try reopenedQueue?.pop(1)) + XCTAssert(reopenedQueue!.size() == 0, "Should now have no contents.") + XCTAssert(value!.first == 5, "Value should be 5") + } + +} diff --git a/CassetteTests/CassetteTests-Bridging-Header.h b/CassetteTests/CassetteTests-Bridging-Header.h new file mode 100644 index 0000000..66c9874 --- /dev/null +++ b/CassetteTests/CassetteTests-Bridging-Header.h @@ -0,0 +1,6 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "Cassette.h" +#import "CASQueueFile.h"