@@ -2,11 +2,12 @@ import XCTest
22
33@testable import Lockman
44
5- // ✅ IMPLEMENTED : Comprehensive LockmanResult enum tests with 3-phase approach
6- // ✅ 13 test methods covering all enum cases, protocol conformance, and integration scenarios
7- // ✅ Phase 1: Basic enum case testing (success, successWithPrecedingCancellation, cancel)
5+ // ✅ UPDATED : Comprehensive LockmanResult enum tests updated for new API with unlockToken
6+ // ✅ 13 test methods covering all enum cases with unlockToken parameter
7+ // ✅ Phase 1: Basic enum case testing (success, successWithPrecedingCancellation, cancel) with unlockToken
88// ✅ Phase 2: Sendable conformance and concurrent access testing
99// ✅ Phase 3: Error protocol integration, documentation examples, and type system testing
10+ // ✅ Phase 4: unlockToken functionality and type safety testing
1011
1112final class LockmanResultTests : XCTestCase {
1213
@@ -20,7 +21,7 @@ final class LockmanResultTests: XCTestCase {
2021 LockmanManager . cleanup. all ( )
2122 }
2223
23- // MARK: - Test Error Types for Testing
24+ // MARK: - Test Error Types and Mock Objects for Testing
2425
2526 // Basic error for testing .cancel case
2627 private struct TestBasicError : LockmanError {
@@ -42,55 +43,69 @@ final class LockmanResultTests: XCTestCase {
4243
4344 init (
4445 message: String , cancelledInfo: any LockmanInfo ,
45- boundaryId: any LockmanBoundaryId = "testBoundary"
46+ boundaryId: any LockmanBoundaryId = TestBoundaryId . test
4647 ) {
4748 self . message = message
4849 self . cancelledInfo = cancelledInfo
4950 self . boundary = boundaryId
5051 }
5152 }
5253
53- // Basic LockmanInfo for testing
54- private struct TestLockmanInfo: LockmanInfo {
55- let strategyId: LockmanStrategyId
56- let actionId: LockmanActionId
57- let uniqueId: UUID
58-
59- init(strategyId: LockmanStrategyId = "TestStrategy", actionId: LockmanActionId = "testAction") {
60- self.strategyId = strategyId
61- self.actionId = actionId
62- self.uniqueId = UUID()
63- }
64-
65- var debugDescription: String {
66- "TestLockmanInfo(actionId: '\(actionId)')"
67- }
54+ // Test boundary ID type alias for easier usage
55+ private typealias TestBoundary = TestBoundaryId
56+
57+ // Helper method to create unlock token for testing
58+ private func createTestUnlockToken(
59+ boundaryId: TestBoundary = TestBoundary . test,
60+ info: TestLockmanInfo = TestLockmanInfo (
61+ actionId: " testAction " ,
62+ strategyId: " TestSingleExecutionStrategy "
63+ )
64+ ) -> LockmanUnlock < TestBoundary , TestLockmanInfo > {
65+ let strategy = TestSingleExecutionStrategy ( )
66+ let anyStrategy = AnyLockmanStrategy ( strategy)
67+ return LockmanUnlock (
68+ id: boundaryId,
69+ info: info,
70+ strategy: anyStrategy,
71+ unlockOption: . immediate
72+ )
6873 }
6974
7075 // MARK: - Phase 1: Basic Enum Cases
7176
7277 func testLockmanResultSuccessCase( ) {
73- // Test .success case
74- let result = LockmanResult.success
78+ // Test .success case with unlockToken
79+ let unlockToken = createTestUnlockToken ( )
80+ let result = LockmanResult < TestBoundary , TestLockmanInfo > . success ( unlockToken: unlockToken)
7581
7682 // Test pattern matching
7783 switch result {
78- case .success:
79- XCTAssertTrue(true) // Success case matched
84+ case . success( let token) :
85+ XCTAssertNotNil ( token)
86+ // Verify unlock token exists (info properties are internal)
8087 default :
8188 XCTFail ( " Should match .success case " )
8289 }
8390 }
8491
8592 func testLockmanResultSuccessWithPrecedingCancellationCase( ) {
86- // Test .successWithPrecedingCancellation case
87- let testInfo = TestLockmanInfo(actionId: "testAction")
93+ // Test .successWithPrecedingCancellation case with unlockToken
94+ let testInfo = TestLockmanInfo ( actionId: " testAction " , strategyId : " TestSingleExecutionStrategy " )
8895 let error = TestPrecedingError ( message: " Previous operation cancelled " , cancelledInfo: testInfo)
89- let result = LockmanResult.successWithPrecedingCancellation(error: error)
96+ let unlockToken = createTestUnlockToken ( info: testInfo)
97+ let result = LockmanResult < TestBoundary , TestLockmanInfo > . successWithPrecedingCancellation (
98+ unlockToken: unlockToken,
99+ error: error
100+ )
90101
91102 // Test pattern matching
92103 switch result {
93- case .successWithPrecedingCancellation(let precedingError):
104+ case . successWithPrecedingCancellation( let token, let precedingError) :
105+ // Test unlock token
106+ XCTAssertNotNil ( token)
107+
108+ // Test error
94109 XCTAssertEqual ( precedingError. errorDescription, " Previous operation cancelled " )
95110 XCTAssertTrue ( precedingError is TestPrecedingError )
96111 if let testError = precedingError as? TestPrecedingError {
@@ -102,9 +117,9 @@ final class LockmanResultTests: XCTestCase {
102117 }
103118
104119 func testLockmanResultCancelCase( ) {
105- // Test .cancel case
120+ // Test .cancel case (no unlock token since lock failed)
106121 let error = TestBasicError ( message: " Operation cancelled " )
107- let result = LockmanResult.cancel(error)
122+ let result = LockmanResult < TestBoundary , TestLockmanInfo > . cancel ( error)
108123
109124 // Test pattern matching
110125 switch result {
@@ -120,10 +135,14 @@ final class LockmanResultTests: XCTestCase {
120135
121136 func testLockmanResultSendableConformance( ) async {
122137 // Test Sendable conformance with concurrent access
123- let testInfo = TestLockmanInfo(actionId: "concurrentTest")
138+ let testInfo = TestLockmanInfo ( actionId: " concurrentTest " , strategyId : " TestSingleExecutionStrategy " )
124139 let precedingError = TestPrecedingError (
125140 message: " Concurrent test error " , cancelledInfo: testInfo)
126- let result = LockmanResult.successWithPrecedingCancellation(error: precedingError)
141+ let unlockToken = createTestUnlockToken ( info: testInfo)
142+ let result = LockmanResult < TestBoundary , TestLockmanInfo > . successWithPrecedingCancellation (
143+ unlockToken: unlockToken,
144+ error: precedingError
145+ )
127146
128147 await withTaskGroup ( of: String . self) { group in
129148 group. addTask {
@@ -165,7 +184,7 @@ final class LockmanResultTests: XCTestCase {
165184 func testLockmanResultWithLockmanErrorProtocol( ) {
166185 // Test with different LockmanError implementations
167186 let basicError = TestBasicError ( message: " Basic error test " )
168- let cancelResult = LockmanResult.cancel(basicError)
187+ let cancelResult = LockmanResult < TestBoundary , TestLockmanInfo > . cancel ( basicError)
169188
170189 switch cancelResult {
171190 case . cancel( let error) :
@@ -179,13 +198,20 @@ final class LockmanResultTests: XCTestCase {
179198
180199 func testLockmanResultWithPrecedingCancellationErrorProtocol( ) {
181200 // Test with LockmanPrecedingCancellationError protocol
182- let testInfo = TestLockmanInfo(actionId: "protocolTest")
201+ let testInfo = TestLockmanInfo ( actionId: " protocolTest " , strategyId : " TestSingleExecutionStrategy " )
183202 let precedingError = TestPrecedingError (
184203 message: " Preceding error test " , cancelledInfo: testInfo)
185- let result = LockmanResult.successWithPrecedingCancellation(error: precedingError)
204+ let unlockToken = createTestUnlockToken ( info: testInfo)
205+ let result = LockmanResult < TestBoundary , TestLockmanInfo > . successWithPrecedingCancellation (
206+ unlockToken: unlockToken,
207+ error: precedingError
208+ )
186209
187210 switch result {
188- case .successWithPrecedingCancellation(let error):
211+ case . successWithPrecedingCancellation( let token, let error) :
212+ // Test unlock token
213+ XCTAssertNotNil ( token)
214+
189215 // Test LockmanPrecedingCancellationError protocol conformance
190216 XCTAssertTrue ( error is any LockmanPrecedingCancellationError )
191217 XCTAssertTrue ( error is any LockmanError ) // Should also conform to base protocol
@@ -200,11 +226,13 @@ final class LockmanResultTests: XCTestCase {
200226
201227 func testLockmanResultExhaustivePatternMatching( ) {
202228 // Test all cases in a single comprehensive function
203- let testInfo = TestLockmanInfo(actionId: "comprehensiveTest")
229+ let testInfo = TestLockmanInfo ( actionId: " comprehensiveTest " , strategyId: " TestSingleExecutionStrategy " )
230+ let unlockToken = createTestUnlockToken ( info: testInfo)
204231
205- let results: [LockmanResult] = [
206- .success,
232+ let results : [ LockmanResult < TestBoundary , TestLockmanInfo > ] = [
233+ . success( unlockToken : createTestUnlockToken ( ) ) ,
207234 . successWithPrecedingCancellation(
235+ unlockToken: unlockToken,
208236 error: TestPrecedingError (
209237 message: " Comprehensive preceding error " ,
210238 cancelledInfo: testInfo
@@ -214,11 +242,13 @@ final class LockmanResultTests: XCTestCase {
214242
215243 for (index, result) in results. enumerated ( ) {
216244 switch result {
217- case .success:
245+ case . success( let token ) :
218246 XCTAssertEqual ( index, 0 , " Success should be first result " )
247+ XCTAssertNotNil ( token)
219248
220- case .successWithPrecedingCancellation(let error):
249+ case . successWithPrecedingCancellation( let token , let error) :
221250 XCTAssertEqual ( index, 1 , " SuccessWithPrecedingCancellation should be second result " )
251+ XCTAssertNotNil ( token)
222252 XCTAssertNotNil ( error. errorDescription)
223253 XCTAssertEqual ( error. lockmanInfo. actionId, " comprehensiveTest " )
224254
@@ -231,14 +261,14 @@ final class LockmanResultTests: XCTestCase {
231261
232262 func testLockmanResultNestedSwitchHandling( ) {
233263 // Test nested pattern matching scenarios
234- let testInfo = TestLockmanInfo(actionId: "nestedTest")
264+ let testInfo = TestLockmanInfo ( actionId: " nestedTest " , strategyId : " TestSingleExecutionStrategy " )
235265
236- func processResult(_ result: LockmanResult) -> String {
266+ func processResult( _ result: LockmanResult < TestBoundary , TestLockmanInfo > ) -> String {
237267 switch result {
238268 case . success:
239269 return " proceed_immediately "
240270
241- case .successWithPrecedingCancellation(let error):
271+ case . successWithPrecedingCancellation( _ , let error) :
242272 // Test nested logic for preceding cancellation
243273 if error. lockmanInfo. actionId. contains ( " nested " ) {
244274 return " cancel_and_proceed_nested "
@@ -258,13 +288,14 @@ final class LockmanResultTests: XCTestCase {
258288
259289 // Test each case
260290 XCTAssertEqual (
261- processResult(.success),
291+ processResult ( . success( unlockToken : createTestUnlockToken ( ) ) ) ,
262292 " proceed_immediately "
263293 )
264294
265295 XCTAssertEqual (
266296 processResult (
267297 . successWithPrecedingCancellation(
298+ unlockToken: createTestUnlockToken ( info: testInfo) ,
268299 error: TestPrecedingError (
269300 message: " Nested test " ,
270301 cancelledInfo: testInfo
@@ -282,14 +313,15 @@ final class LockmanResultTests: XCTestCase {
282313
283314 func testLockmanResultDocumentationExamples( ) {
284315 // Test examples that match the documentation
285- let testInfo = TestLockmanInfo(strategyId : "ExampleStrategy ", actionId : "documentationExample ")
316+ let testInfo = TestLockmanInfo ( actionId : " documentationExample " , strategyId : " ExampleStrategy " )
286317
287318 // Example 1: Success case (most common)
288- let successResult = LockmanResult.success
319+ let unlockToken = createTestUnlockToken ( info: testInfo)
320+ let successResult = LockmanResult < TestBoundary , TestLockmanInfo > . success ( unlockToken: unlockToken)
289321 switch successResult {
290- case .success:
322+ case . success( let token ) :
291323 // Operation can proceed immediately without any additional cleanup
292- XCTAssertTrue(true) // This is the expected path
324+ XCTAssertNotNil ( token )
293325 default :
294326 XCTFail ( " Documentation example should succeed " )
295327 }
@@ -299,13 +331,17 @@ final class LockmanResultTests: XCTestCase {
299331 message: " Lower priority operation cancelled " ,
300332 cancelledInfo: testInfo
301333 )
302- let precedingResult = LockmanResult.successWithPrecedingCancellation(error: precedingError)
334+ let precedingResult = LockmanResult < TestBoundary , TestLockmanInfo > . successWithPrecedingCancellation (
335+ unlockToken: createTestUnlockToken ( info: testInfo) ,
336+ error: precedingError
337+ )
303338
304339 switch precedingResult {
305- case .successWithPrecedingCancellation(let error):
340+ case . successWithPrecedingCancellation( let token , let error) :
306341 // 1. Cancel the existing operation (usually via Effect cancellation)
307342 // 2. Immediately unlock the cancelled action to prevent resource leaks
308343 // 3. Proceed with the new operation
344+ XCTAssertNotNil ( token)
309345 XCTAssertNotNil ( error. lockmanInfo)
310346 XCTAssertEqual ( error. lockmanInfo. actionId, " documentationExample " )
311347 default :
@@ -314,7 +350,7 @@ final class LockmanResultTests: XCTestCase {
314350
315351 // Example 3: Cancel case (conflict situations)
316352 let cancelError = TestBasicError ( message: " Higher priority operation is already active " )
317- let cancelResult = LockmanResult.cancel(cancelError)
353+ let cancelResult = LockmanResult < TestBoundary , TestLockmanInfo > . cancel ( cancelError)
318354
319355 switch cancelResult {
320356 case . cancel( let error) :
@@ -352,10 +388,10 @@ final class LockmanResultTests: XCTestCase {
352388 var boundaryId : any LockmanBoundaryId { boundary }
353389 }
354390
355- let testInfo = TestLockmanInfo(actionId: "realErrorTest")
391+ let testInfo = TestLockmanInfo ( actionId: " realErrorTest " , strategyId : " TestSingleExecutionStrategy " )
356392
357393 // Test with conflict error
358- let conflictResult = LockmanResult.cancel(
394+ let conflictResult = LockmanResult < TestBoundary , TestLockmanInfo > . cancel (
359395 ConflictError (
360396 conflictingActionId: " existingAction " ,
361397 boundaryId: " mainBoundary "
@@ -374,17 +410,22 @@ final class LockmanResultTests: XCTestCase {
374410 }
375411
376412 // Test with priority error
377- let priorityResult = LockmanResult.successWithPrecedingCancellation(
413+ let priorityResult = LockmanResult < TestBoundary , TestLockmanInfo > . successWithPrecedingCancellation (
414+ unlockToken: createTestUnlockToken ( info: testInfo) ,
378415 error: PriorityError (
379416 cancelledInfo: testInfo,
380- boundary: "testBoundary" ,
417+ boundary: TestBoundaryId . test ,
381418 newPriority: 10 ,
382419 oldPriority: 5
383420 )
384421 )
385422
386423 switch priorityResult {
387- case .successWithPrecedingCancellation(let error):
424+ case . successWithPrecedingCancellation( let token, let error) :
425+ // Test unlock token
426+ XCTAssertNotNil ( token)
427+
428+ // Test priority error
388429 if let priorityError = error as? PriorityError {
389430 XCTAssertEqual ( priorityError. newPriority, 10 )
390431 XCTAssertEqual ( priorityError. oldPriority, 5 )
0 commit comments