diff options
author | Joel Fischer <joeljfischer@gmail.com> | 2021-09-24 08:53:59 -0400 |
---|---|---|
committer | Joel Fischer <joeljfischer@gmail.com> | 2021-09-24 08:53:59 -0400 |
commit | 60104522aad1c45cdd55fa0c5b73e4b369e79582 (patch) | |
tree | ef051bd14ff9f9c6a10c12378fffb7df19c0002e /SmartDeviceLinkTests/DevAPISpecs | |
parent | 7ef29ccad916ad794aa7983817a4aa3a9fc59a5e (diff) | |
parent | 4c1fe3f7b15c11763adc88b2078b609df068e031 (diff) | |
download | sdl_ios-60104522aad1c45cdd55fa0c5b73e4b369e79582.tar.gz |
Merge branch 'develop' into feature/issue-1898-menu-manager-refactor
# Conflicts:
# SmartDeviceLink-iOS.xcodeproj/project.pbxproj
# SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink-Example-Swift.xcscheme
Diffstat (limited to 'SmartDeviceLinkTests/DevAPISpecs')
7 files changed, 1677 insertions, 1639 deletions
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m index 265dad6e4..f811192a4 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m @@ -17,20 +17,17 @@ describe(@"check choice VR optional operation", ^{ __block SDLCheckChoiceVROptionalOperation *testOp = nil; __block BOOL resultVROptional = NO; - __block BOOL hasCalledOperationCompletionHandler = NO; __block NSError *resultError = nil; beforeEach(^{ resultVROptional = NO; - hasCalledOperationCompletionHandler = NO; + resultError = nil; testConnectionManager = [[TestConnectionManager alloc] init]; - testOp = [[SDLCheckChoiceVROptionalOperation alloc] initWithConnectionManager:testConnectionManager]; - testOp.completionBlock = ^{ - hasCalledOperationCompletionHandler = YES; - resultVROptional = testOp.vrOptional; - resultError = testOp.error; - }; + testOp = [[SDLCheckChoiceVROptionalOperation alloc] initWithConnectionManager:testConnectionManager completionHandler:^(BOOL isVROptional, NSError * _Nullable error) { + resultVROptional = isVROptional; + resultError = error; + }]; }); it(@"should have priority of 'very high'", ^{ @@ -80,7 +77,6 @@ describe(@"check choice VR optional operation", ^{ }); it(@"should have called the completion handler with proper data and finish", ^{ - expect(hasCalledOperationCompletionHandler).toEventually(beTrue()); expect(resultVROptional).to(beTrue()); expect(resultError).to(beNil()); expect(@(testOp.finished)).to(equal(@YES)); @@ -99,8 +95,6 @@ describe(@"check choice VR optional operation", ^{ }); it(@"should have sent out a new request", ^{ - expect(hasCalledOperationCompletionHandler).to(beFalse()); - expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLCreateInteractionChoiceSet class])); SDLCreateInteractionChoiceSet *receivedRequest = testConnectionManager.receivedRequests.lastObject; @@ -132,7 +126,6 @@ describe(@"check choice VR optional operation", ^{ }); it(@"should have called the completion handler with proper data and finish", ^{ - expect(hasCalledOperationCompletionHandler).toEventually(beTrue()); expect(resultVROptional).to(beFalse()); expect(resultError).to(beNil()); expect(@(testOp.finished)).to(equal(@YES)); @@ -151,7 +144,6 @@ describe(@"check choice VR optional operation", ^{ }); it(@"should return a failure", ^{ - expect(hasCalledOperationCompletionHandler).toEventually(beTrue()); expect(resultVROptional).to(beFalse()); expect(resultError).toNot(beNil()); }); diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m index 30c97f00a..815b1a0b9 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m @@ -9,8 +9,7 @@ #import "SDLDeleteChoicesOperation.h" #import "SDLError.h" #import "SDLGlobals.h" -#import "SDLPreloadChoicesOperation.h" -#import "SDLPresentChoiceSetOperation.h" +#import "SDLPreloadPresentChoicesOperation.h" #import "SDLPresentKeyboardOperation.h" #import "SDLRPCNotificationNotification.h" #import "SDLStateMachine.h" @@ -19,22 +18,18 @@ #import "TestConnectionManager.h" -@interface SDLPreloadChoicesOperation() - -@property (copy, nonatomic, nullable) NSError *internalError; -@property (strong, nonatomic, nullable) NSMutableArray<NSNumber *> *failedChoiceUploadIDs; - -@end - @interface SDLChoiceCell() @property (assign, nonatomic) UInt16 choiceId; @end -@interface SDLPresentChoiceSetOperation() +@interface SDLPreloadPresentChoicesOperation() +@property (strong, nonatomic) NSMutableSet<SDLChoiceCell *> *cellsToUpload; @property (copy, nonatomic, nullable) NSError *internalError; +@property (copy, nonatomic) SDLUploadChoicesCompletionHandler preloadCompletionHandler; + @property (assign, nonatomic) UInt16 cancelId; @property (strong, nonatomic, readwrite, nullable) SDLChoiceCell *selectedCell; @property (strong, nonatomic, readwrite, nullable) SDLTriggerSource selectedTriggerSource; @@ -42,9 +37,17 @@ @end +@interface SDLDeleteChoicesOperation() + +@property (copy, nonatomic) SDLDeleteChoicesCompletionHandler deleteCompletionHandler; + +@end + @interface SDLCheckChoiceVROptionalOperation() +@property (assign, nonatomic, getter=isVROptional) BOOL vrOptional; @property (copy, nonatomic, nullable) NSError *internalError; +@property (copy, nonatomic) SDLCheckChoiceVROptionalCompletionHandler vrOptionalCompletionHandler; @end @@ -52,17 +55,14 @@ @property (strong, nonatomic, readonly) SDLStateMachine *stateMachine; @property (strong, nonatomic) NSOperationQueue *transactionQueue; +@property (copy, nonatomic) dispatch_queue_t readWriteQueue; @property (assign, nonatomic) UInt16 nextCancelId; @property (copy, nonatomic, nullable) SDLHMILevel currentHMILevel; @property (copy, nonatomic, nullable) SDLSystemContext currentSystemContext; @property (copy, nonatomic, nullable) SDLWindowCapability *currentWindowCapability; -@property (strong, nonatomic) NSMutableSet<SDLChoiceCell *> *preloadedMutableChoices; -@property (strong, nonatomic, readonly) NSSet<SDLChoiceCell *> *pendingPreloadChoices; -@property (strong, nonatomic) NSMutableSet<SDLChoiceCell *> *pendingMutablePreloadChoices; -@property (strong, nonatomic, nullable) SDLChoiceSet *pendingPresentationSet; -@property (strong, nonatomic, nullable) SDLAsynchronousOperation *pendingPresentOperation; +@property (copy, nonatomic, readwrite) NSSet<SDLChoiceCell *> *preloadedChoices; @property (assign, nonatomic, getter=isVROptional) BOOL vrOptional; @@ -83,7 +83,13 @@ describe(@"choice set manager tests", ^{ __block SDLWindowCapability *enabledWindowCapability = nil; __block SDLWindowCapability *disabledWindowCapability = nil; - __block SDLWindowCapability *primaryTextOnlyCapability = nil; + + __block SDLChoiceSet *testChoiceSet = nil; + __block SDLChoiceSet *testFailedChoiceSet = nil; + __block NSString *testTitle = @"test title"; + __block id<SDLChoiceSetDelegate> choiceDelegate = nil; + __block id<SDLKeyboardDelegate> keyboardDelegate = nil; + __block SDLInteractionMode testMode = SDLInteractionModeBoth; __block SDLChoiceCell *testCell1 = nil; __block SDLChoiceCell *testCell2 = nil; @@ -91,9 +97,13 @@ describe(@"choice set manager tests", ^{ __block SDLChoiceCell *testCell4 = nil; __block SDLChoiceCell *testCell1Duplicate = nil; __block SDLChoiceCell *testCell1Similar = nil; - __block SDLVersion *choiceSetUniquenessActiveVersion = nil; __block SDLArtwork *testArtwork = nil; + __block SDLTriggerSource resultTriggerSource = SDLTriggerSourceMenu; + __block SDLChoiceCell *resultChoiceCell = nil; + __block NSUInteger resultChoiceRow = NSUIntegerMax; + __block NSError *resultError = nil; + beforeEach(^{ testConnectionManager = [[TestConnectionManager alloc] init]; testFileManager = OCMClassMock([SDLFileManager class]); @@ -121,11 +131,16 @@ describe(@"choice set manager tests", ^{ ]; disabledWindowCapability = [[SDLWindowCapability alloc] init]; disabledWindowCapability.textFields = @[]; - primaryTextOnlyCapability = [[SDLWindowCapability alloc] init]; - primaryTextOnlyCapability.textFields = @[ - [[SDLTextField alloc] initWithName:SDLTextFieldNameMenuName characterSet:SDLCharacterSetUtf8 width:500 rows:1], - ]; - choiceSetUniquenessActiveVersion = [[SDLVersion alloc] initWithMajor:7 minor:1 patch:0]; + + keyboardDelegate = OCMProtocolMock(@protocol(SDLKeyboardDelegate)); + choiceDelegate = OCMProtocolMock(@protocol(SDLChoiceSetDelegate)); + testChoiceSet = [[SDLChoiceSet alloc] initWithTitle:testTitle delegate:choiceDelegate choices:@[testCell1, testCell2, testCell3]]; + testFailedChoiceSet = [[SDLChoiceSet alloc] initWithTitle:testTitle delegate:choiceDelegate choices:@[testCell1, testCell2, testCell3, testCell4]]; + + resultTriggerSource = SDLTriggerSourceMenu; + resultChoiceCell = nil; + resultChoiceRow = NSUIntegerMax; + resultError = nil; }); it(@"should be in the correct startup state", ^{ @@ -212,12 +227,10 @@ describe(@"choice set manager tests", ^{ describe(@"after the bad vr optional response", ^{ beforeEach(^{ SDLCheckChoiceVROptionalOperation *vrOptionalOp = testManager.transactionQueue.operations.lastObject; - vrOptionalOp.vrOptional = NO; - vrOptionalOp.internalError = [NSError errorWithDomain:@"test" code:0 userInfo:nil]; - vrOptionalOp.completionBlock(); + vrOptionalOp.vrOptionalCompletionHandler(NO, [NSError errorWithDomain:@"test" code:0 userInfo:nil]); }); - it(@"should be ready", ^{ + it(@"should be in startup error", ^{ expect(testManager.currentState).to(equal(SDLChoiceManagerStateStartupError)); }); }); @@ -225,8 +238,7 @@ describe(@"choice set manager tests", ^{ describe(@"after the vr optional response", ^{ beforeEach(^{ SDLCheckChoiceVROptionalOperation *vrOptionalOp = testManager.transactionQueue.operations.lastObject; - vrOptionalOp.vrOptional = YES; - vrOptionalOp.completionBlock(); + vrOptionalOp.vrOptionalCompletionHandler(YES, nil); }); it(@"should be ready", ^{ @@ -243,9 +255,7 @@ describe(@"choice set manager tests", ^{ expect(testManager.currentState).to(equal(SDLChoiceManagerStateShutdown)); expect(testManager.vrOptional).to(beTrue()); expect(testManager.currentHMILevel).to(equal(SDLHMILevelNone)); - expect(testManager.pendingPresentationSet).to(beNil()); - expect(testManager.preloadedMutableChoices).to(beEmpty()); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); + expect(testManager.preloadedChoices).to(beEmpty()); }); }); }); @@ -258,664 +268,128 @@ describe(@"choice set manager tests", ^{ describe(@"preloading choices", ^{ context(@"when some choices are already uploaded", ^{ beforeEach(^{ - testManager.preloadedMutableChoices = [NSMutableSet setWithArray:@[testCell1]]; - + testManager.preloadedChoices = [NSSet setWithArray:@[testCell1]]; [testManager preloadChoices:@[testCell1, testCell2, testCell3] withCompletionHandler:^(NSError * _Nullable error) { }]; }); it(@"should properly start the preload", ^{ - expect(testManager.pendingPreloadChoices).toNot(contain(testCell1)); - expect(testManager.pendingPreloadChoices).to(contain(testCell2)); - expect(testManager.pendingPreloadChoices).to(contain(testCell3)); - expect(testManager.transactionQueue.operations.firstObject).to(beAnInstanceOf([SDLPreloadChoicesOperation class])); + expect(testManager.transactionQueue.operations[0]).to(beAnInstanceOf([SDLPreloadPresentChoicesOperation class])); - SDLPreloadChoicesOperation *testOp = testManager.transactionQueue.operations.firstObject; - [testOp finishOperation]; + SDLPreloadPresentChoicesOperation *testOp = testManager.transactionQueue.operations[0]; + testOp.preloadCompletionHandler([NSSet setWithArray:@[testCell1, testCell2, testCell3]], nil); expect(testManager.preloadedChoices).to(contain(testCell1)); expect(testManager.preloadedChoices).to(contain(testCell2)); expect(testManager.preloadedChoices).to(contain(testCell3)); - expect(testManager.pendingPreloadChoices).to(haveCount(0)); - }); - }); - - context(@"when some choices are already uploaded with duplicate titles version >= 7.1.0", ^{ - beforeEach(^{ - [SDLGlobals sharedGlobals].rpcVersion = choiceSetUniquenessActiveVersion; - }); - - context(@"if there are duplicate cells once you strip unused cell properties", ^{ - beforeEach(^{ - testManager.currentWindowCapability = primaryTextOnlyCapability; - [testManager preloadChoices:@[testCell1, testCell1Similar] withCompletionHandler:^(NSError * _Nullable error) { }]; - }); - - it(@"should update the choiceCells' unique title", ^{ - SDLPreloadChoicesOperation *testOp = testManager.transactionQueue.operations.firstObject; - [testOp finishOperation]; - NSArray <SDLChoiceCell *> *testArrays = testManager.preloadedChoices.allObjects; - for (SDLChoiceCell *choiceCell in testArrays) { - if (choiceCell.secondaryText) { - expect(choiceCell.uniqueText).to(equal("test1 (2)")); - } else { - expect(choiceCell.uniqueText).to(equal("test1")); - } - } - expect(testManager.preloadedChoices).to(haveCount(2)); - expect(testManager.preloadedChoices).to(contain(testCell1)); - expect(testManager.preloadedChoices).to(contain(testCell1Duplicate)); - }); - }); - - context(@"if all cell properties are used", ^{ - beforeEach(^{ - testManager.currentWindowCapability = enabledWindowCapability; - [testManager preloadChoices:@[testCell1, testCell1Similar] withCompletionHandler:^(NSError * _Nullable error) { }]; - }); - - it(@"should not update the choiceCells' unique title", ^{ - SDLPreloadChoicesOperation *testOp = testManager.transactionQueue.operations.firstObject; - [testOp finishOperation]; - NSArray <SDLChoiceCell *> *testArrays = testManager.preloadedChoices.allObjects; - for (SDLChoiceCell *choiceCell in testArrays) { - expect(choiceCell.uniqueText).to(equal("test1")); - } - expect(testManager.preloadedChoices).to(haveCount(2)); - expect(testManager.preloadedChoices).to(contain(testCell1)); - expect(testManager.preloadedChoices).to(contain(testCell1Duplicate)); - }); - }); - }); - - context(@"when some choices are already uploaded with duplicate titles version <= 7.1.0", ^{ - beforeEach(^{ - [SDLGlobals sharedGlobals].rpcVersion = [[SDLVersion alloc] initWithMajor:7 minor:0 patch:0]; - [testManager preloadChoices:@[testCell1, testCell1Similar] withCompletionHandler:^(NSError * _Nullable error) { }]; - }); - - it(@"append a number to the unique text for choice set cells", ^{ - SDLPreloadChoicesOperation *testOp = testManager.transactionQueue.operations.firstObject; - [testOp finishOperation]; - NSArray <SDLChoiceCell *> *testArrays = testManager.preloadedChoices.allObjects; - for (SDLChoiceCell *choiceCell in testArrays) { - if (choiceCell.secondaryText) { - expect(choiceCell.uniqueText).to(equal("test1 (2)")); - } else { - expect(choiceCell.uniqueText).to(equal("test1")); - } - } - expect(testManager.preloadedChoices).to(haveCount(2)); - expect(testManager.preloadedChoices).to(contain(testCell1)); - expect(testManager.preloadedChoices).to(contain(testCell1Duplicate)); }); }); - context(@"when some choices are already pending", ^{ + context(@"when the manager shuts down during preloading", ^{ beforeEach(^{ - testManager.pendingMutablePreloadChoices = [NSMutableSet setWithArray:@[testCell1]]; - [testManager preloadChoices:@[testCell1, testCell2, testCell3] withCompletionHandler:^(NSError * _Nullable error) { + resultError = error; }]; }); - it(@"should properly start the preload", ^{ - expect(testManager.pendingPreloadChoices).to(contain(testCell1)); - expect(testManager.pendingPreloadChoices).to(contain(testCell2)); - expect(testManager.pendingPreloadChoices).to(contain(testCell3)); - expect(testManager.transactionQueue.operations.firstObject).to(beAnInstanceOf([SDLPreloadChoicesOperation class])); - - SDLPreloadChoicesOperation *testOp = testManager.transactionQueue.operations.firstObject; - [testOp finishOperation]; - - expect(testManager.preloadedChoices).toNot(contain(testCell1)); - expect(testManager.preloadedChoices).to(contain(testCell2)); - expect(testManager.preloadedChoices).to(contain(testCell3)); - expect(testManager.pendingPreloadChoices).to(haveCount(1)); - }); - }); - - context(@"when the manager shuts down during preloading", ^{ - beforeEach(^{ - testManager.pendingMutablePreloadChoices = [NSMutableSet setWithArray:@[testCell1]]; - - [testManager preloadChoices:@[testCell1, testCell2, testCell3] withCompletionHandler:^(NSError * _Nullable error) {}]; - }); - it(@"should leave the list of pending and uploaded choice items empty when the operation finishes", ^{ - expect(testManager.pendingPreloadChoices).to(contain(testCell1)); - expect(testManager.pendingPreloadChoices).to(contain(testCell2)); - expect(testManager.pendingPreloadChoices).to(contain(testCell3)); - expect(testManager.transactionQueue.operations.firstObject).to(beAnInstanceOf([SDLPreloadChoicesOperation class])); + expect(testManager.transactionQueue.operations.firstObject).to(beAnInstanceOf([SDLPreloadPresentChoicesOperation class])); [testManager.stateMachine setToState:SDLChoiceManagerStateShutdown fromOldState:nil callEnterTransition:NO]; - testManager.pendingMutablePreloadChoices = [NSMutableSet set]; - testManager.preloadedMutableChoices = [NSMutableSet set]; + testManager.preloadedChoices = [NSMutableSet set]; - SDLPreloadChoicesOperation *testOp = testManager.transactionQueue.operations.firstObject; + SDLPreloadPresentChoicesOperation *testOp = testManager.transactionQueue.operations.firstObject; [testOp finishOperation]; - expect(testManager.preloadedMutableChoices).to(beEmpty()); expect(testManager.preloadedChoices).to(beEmpty()); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - expect(testManager.pendingPreloadChoices).to(beEmpty()); }); }); }); describe(@"deleting choices", ^{ - context(@"used in a pending presentation", ^{ - __block SDLPresentChoiceSetOperation *pendingPresentOp = nil; - __block id<SDLChoiceSetDelegate> choiceDelegate = nil; - - beforeEach(^{ - choiceDelegate = OCMProtocolMock(@protocol(SDLChoiceSetDelegate)); - pendingPresentOp = OCMClassMock([SDLPresentChoiceSetOperation class]); - OCMStub(pendingPresentOp.choiceSet.choices).andReturn([NSSet setWithArray:@[testCell1]]); - testManager.pendingPresentOperation = pendingPresentOp; - testManager.pendingPresentationSet = [[SDLChoiceSet alloc] initWithTitle:@"Test" delegate:choiceDelegate choices:@[testCell1]]; - - testManager.preloadedMutableChoices = [NSMutableSet setWithObject:testCell1]; - - [testManager deleteChoices:@[testCell1, testCell2, testCell3]]; - }); - - it(@"should properly start the deletion", ^{ - expect(testManager.transactionQueue.operations.lastObject).to(beAnInstanceOf([SDLDeleteChoicesOperation class])); - expect(testManager.pendingPresentationSet).to(beNil()); - OCMVerify([pendingPresentOp cancel]); - OCMVerify([choiceDelegate choiceSet:[OCMArg any] didReceiveError:[OCMArg any]]); - - testManager.transactionQueue.operations.lastObject.completionBlock(); - expect(testManager.preloadedChoices).to(beEmpty()); - }); - }); - context(@"used in pending preloads", ^{ - __block SDLPreloadChoicesOperation *pendingPreloadOp = nil; - beforeEach(^{ - pendingPreloadOp = [[SDLPreloadChoicesOperation alloc] init]; - - [testManager.transactionQueue addOperation:pendingPreloadOp]; - - testManager.pendingMutablePreloadChoices = [NSMutableSet setWithObject:testCell1]; + [testManager preloadChoices:@[testCell1, testCell2, testCell3, testCell4] withCompletionHandler:^(NSError * _Nullable error) {}]; [testManager deleteChoices:@[testCell1, testCell2, testCell3]]; }); - it(@"should properly start the deletion", ^{ - expect(testManager.pendingPreloadChoices).to(beEmpty()); - expect(testManager.transactionQueue.operationCount).to(equal(1)); // No delete operation + it(@"should preload the choices, then delete them", ^{ + expect(testManager.transactionQueue.operationCount).to(equal(2)); + expect(testManager.transactionQueue.operations[0]).to(beAnInstanceOf(SDLPreloadPresentChoicesOperation.class)); + expect(testManager.transactionQueue.operations[1]).to(beAnInstanceOf(SDLDeleteChoicesOperation.class)); }); }); context(@"when the manager shuts down during deletion", ^{ - __block SDLPresentChoiceSetOperation *pendingPresentOp = nil; - __block id<SDLChoiceSetDelegate> choiceDelegate = nil; - beforeEach(^{ - choiceDelegate = OCMProtocolMock(@protocol(SDLChoiceSetDelegate)); - pendingPresentOp = OCMClassMock([SDLPresentChoiceSetOperation class]); - OCMStub(pendingPresentOp.choiceSet.choices).andReturn([NSSet setWithArray:@[testCell1]]); - testManager.pendingPresentOperation = pendingPresentOp; - testManager.pendingPresentationSet = [[SDLChoiceSet alloc] initWithTitle:@"Test" delegate:choiceDelegate choices:@[testCell1]]; - testManager.preloadedMutableChoices = [NSMutableSet setWithObject:testCell1]; + testManager.preloadedChoices = [NSSet setWithArray:@[testCell1, testCell2, testCell3]]; + [testManager deleteChoices:@[testCell1, testCell2]]; - [testManager deleteChoices:@[testCell1, testCell2, testCell3]]; + [SDLGlobals runSyncOnSerialSubQueue:testManager.readWriteQueue block:^{ + [testManager.stateMachine setToState:SDLChoiceManagerStateShutdown fromOldState:SDLChoiceManagerStateReady callEnterTransition:YES]; + }]; }); it(@"should leave the list of pending and uploaded choice items empty when the operation finishes", ^{ - expect(testManager.transactionQueue.operations.lastObject).to(beAnInstanceOf([SDLDeleteChoicesOperation class])); - expect(testManager.pendingPresentationSet).to(beNil()); - OCMVerify([pendingPresentOp cancel]); - OCMVerify([choiceDelegate choiceSet:[OCMArg any] didReceiveError:[OCMArg any]]); - - [testManager.stateMachine setToState:SDLChoiceManagerStateShutdown fromOldState:nil callEnterTransition:NO]; - testManager.pendingMutablePreloadChoices = [NSMutableSet set]; - testManager.preloadedMutableChoices = [NSMutableSet set]; - - testManager.transactionQueue.operations.lastObject.completionBlock(); - - expect(testManager.preloadedMutableChoices).to(beEmpty()); + expect(testManager.transactionQueue.operationCount).to(equal(0)); expect(testManager.preloadedChoices).to(beEmpty()); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - expect(testManager.pendingPreloadChoices).to(beEmpty()); }); }); }); describe(@"presenting a choice set", ^{ - __block SDLChoiceSet *testChoiceSet = nil; - __block SDLChoiceSet *testFailedChoiceSet = nil; - __block NSString *testTitle = @"test title"; - __block id<SDLChoiceSetDelegate> choiceDelegate = nil; - __block id<SDLKeyboardDelegate> keyboardDelegate = nil; - __block SDLInteractionMode testMode = SDLInteractionModeBoth; - __block SDLPresentKeyboardOperation *pendingPresentOp = nil; - __block id strickMockOperationQueue = nil; - __block SDLChoiceCell *testSelectedCell = nil; - __block NSError *testError = nil; - NSUInteger testSelectedCellRow = 1; - - beforeEach(^{ - keyboardDelegate = OCMProtocolMock(@protocol(SDLKeyboardDelegate)); - choiceDelegate = OCMProtocolMock(@protocol(SDLChoiceSetDelegate)); - testChoiceSet = [[SDLChoiceSet alloc] initWithTitle:testTitle delegate:choiceDelegate choices:@[testCell1, testCell2, testCell3]]; - testFailedChoiceSet = [[SDLChoiceSet alloc] initWithTitle:testTitle delegate:choiceDelegate choices:@[testCell1, testCell2, testCell3, testCell4]]; - testSelectedCell = testChoiceSet.choices[1]; - testError = [NSError sdl_choiceSetManager_failedToCreateMenuItems]; - - pendingPresentOp = OCMClassMock([SDLPresentKeyboardOperation class]); - testManager.pendingPresentOperation = pendingPresentOp; - testManager.pendingPresentationSet = [[SDLChoiceSet alloc] init]; - - strickMockOperationQueue = OCMStrictClassMock([NSOperationQueue class]); - [strickMockOperationQueue setExpectationOrderMatters:YES]; - testManager.transactionQueue = strickMockOperationQueue; - }); - - context(@"searchable", ^{ - it(@"should notify the choice delegate when a choice item is selected", ^{ - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingPresentationSet).to(equal(testChoiceSet)); - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - presentChoicesOperation.selectedCell = testSelectedCell; - presentChoicesOperation.selectedTriggerSource = testMode; - presentChoicesOperation.selectedCellRow = testSelectedCellRow; - presentChoicesOperation.internalError = nil; - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - OCMExpect([choiceDelegate choiceSet:testChoiceSet didSelectChoice:testSelectedCell withSource:testMode atRowIndex:testSelectedCellRow]); - - [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).to(beNil()); - expect(testManager.pendingPresentOperation).to(beNil()); - - expect(testManager.preloadedMutableChoices.count).to(equal(3)); - expect(testManager.preloadedMutableChoices).to(contain(testChoiceSet.choices[0])); - expect(testManager.preloadedMutableChoices).to(contain(testChoiceSet.choices[1])); - expect(testManager.preloadedMutableChoices).to(contain(testChoiceSet.choices[2])); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - }); - - it(@"should notify the choice delegate if an error occured during presentation", ^{ - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingPresentationSet).to(equal(testChoiceSet)); - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - presentChoicesOperation.internalError = testError; - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - OCMExpect([choiceDelegate choiceSet:[OCMArg any] didReceiveError:testError]); - - [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).to(beNil()); - expect(testManager.pendingPresentOperation).to(beNil()); - - expect(testManager.preloadedMutableChoices.count).to(equal(3)); - expect(testManager.preloadedMutableChoices).to(contain(testChoiceSet.choices[0])); - expect(testManager.preloadedMutableChoices).to(contain(testChoiceSet.choices[1])); - expect(testManager.preloadedMutableChoices).to(contain(testChoiceSet.choices[2])); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - }); - - it(@"should not add a choice item that fails to the list of preloaded choices", ^{ - NSMutableDictionary<SDLRPCRequest *, NSError *> *testErrors = [NSMutableDictionary dictionary]; - SDLCreateInteractionChoiceSet *failedChoiceSet = [[SDLCreateInteractionChoiceSet alloc] initWithId:0 choiceSet:@[[[SDLChoice alloc] initWithId:1 menuName:@"1" vrCommands:nil]]]; - testErrors[failedChoiceSet] = [NSError sdl_choiceSetManager_choiceUploadFailed:[NSDictionary dictionary]]; - NSError *testInternalError = [NSError sdl_choiceSetManager_choiceUploadFailed:testErrors]; - - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingMutablePreloadChoices.count).to(equal(4)); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[0])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[1])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[2])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[3])); - preloadChoicesOperation.internalError = testInternalError; - preloadChoicesOperation.failedChoiceUploadIDs = [[NSMutableArray alloc] initWithArray:(@[@1])]; - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMReject([strickMockOperationQueue addOperation:[OCMArg isKindOfClass:SDLPresentChoiceSetOperation.class]]); - OCMExpect([choiceDelegate choiceSet:[OCMArg any] didReceiveError:testInternalError]); - - [testManager presentChoiceSet:testFailedChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).toNot(beNil()); - expect(testManager.pendingPresentOperation).toNot(beNil()); - - expect(testManager.preloadedMutableChoices.count).to(equal(3)); - expect(testManager.preloadedMutableChoices).toNot(contain(testFailedChoiceSet.choices[0])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[1])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[2])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[3])); - - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - }); - - it(@"should not add any of choice items if they all fail to upload to the list of preloaded choices", ^{ - NSMutableDictionary<SDLRPCRequest *, NSError *> *testErrors = [NSMutableDictionary dictionary]; - SDLCreateInteractionChoiceSet *failedChoiceSet1 = [[SDLCreateInteractionChoiceSet alloc] initWithId:0 choiceSet:@[[[SDLChoice alloc] initWithId:1 menuName:@"1" vrCommands:nil]]]; - SDLCreateInteractionChoiceSet *failedChoiceSet2 = [[SDLCreateInteractionChoiceSet alloc] initWithId:0 choiceSet:@[[[SDLChoice alloc] initWithId:2 menuName:@"2" vrCommands:nil]]]; - SDLCreateInteractionChoiceSet *failedChoiceSet3 = [[SDLCreateInteractionChoiceSet alloc] initWithId:0 choiceSet:@[[[SDLChoice alloc] initWithId:3 menuName:@"3" vrCommands:nil]]]; - SDLCreateInteractionChoiceSet *failedChoiceSet4 = [[SDLCreateInteractionChoiceSet alloc] initWithId:0 choiceSet:@[[[SDLChoice alloc] initWithId:4 menuName:@"4" vrCommands:nil]]]; - testErrors[failedChoiceSet1] = [NSError sdl_choiceSetManager_choiceUploadFailed:[NSDictionary dictionary]]; - testErrors[failedChoiceSet2] = [NSError sdl_choiceSetManager_choiceUploadFailed:[NSDictionary dictionary]]; - testErrors[failedChoiceSet3] = [NSError sdl_choiceSetManager_choiceUploadFailed:[NSDictionary dictionary]]; - testErrors[failedChoiceSet4] = [NSError sdl_choiceSetManager_choiceUploadFailed:[NSDictionary dictionary]]; - NSError *testInternalError = [NSError sdl_choiceSetManager_choiceUploadFailed:testErrors]; - - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingMutablePreloadChoices.count).to(equal(4)); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[0])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[1])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[2])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[3])); - preloadChoicesOperation.internalError = testInternalError; - preloadChoicesOperation.failedChoiceUploadIDs = [[NSMutableArray alloc] initWithArray:(@[@1, @2, @3, @4])]; - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMReject([strickMockOperationQueue addOperation:[OCMArg isKindOfClass:SDLPresentChoiceSetOperation.class]]); - OCMExpect([choiceDelegate choiceSet:[OCMArg any] didReceiveError:testInternalError]); - - [testManager presentChoiceSet:testFailedChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 1.0); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).toNot(beNil()); - expect(testManager.pendingPresentOperation).toNot(beNil()); - - expect(testManager.preloadedMutableChoices).to(beEmpty()); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - }); - }); - - it(@"should skip preloading the choices if all choice items have already been uploaded", ^{ - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingMutablePreloadChoices.count).to(equal(3)); - expect(testManager.pendingMutablePreloadChoices).to(contain(testChoiceSet.choices[0])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testChoiceSet.choices[1])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testChoiceSet.choices[2])); - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - presentChoicesOperation.selectedCell = testSelectedCell; - presentChoicesOperation.selectedTriggerSource = testMode; - presentChoicesOperation.selectedCellRow = testSelectedCellRow; - presentChoicesOperation.internalError = nil; - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - OCMExpect([choiceDelegate choiceSet:testChoiceSet didSelectChoice:testSelectedCell withSource:testMode atRowIndex:testSelectedCellRow]); - - [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).to(beNil()); - expect(testManager.pendingPresentOperation).to(beNil()); - - expect(testManager.preloadedMutableChoices.count).to(equal(3)); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - - // Present the exact same choices again - OCMReject([strickMockOperationQueue addOperation:[OCMArg isKindOfClass:SDLPreloadChoicesOperation.class]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - presentChoicesOperation.selectedCell = testSelectedCell; - presentChoicesOperation.selectedTriggerSource = testMode; - presentChoicesOperation.selectedCellRow = testSelectedCellRow; - presentChoicesOperation.internalError = nil; - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - OCMExpect([choiceDelegate choiceSet:testChoiceSet didSelectChoice:testSelectedCell withSource:testMode atRowIndex:testSelectedCellRow]); - - [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - }); - - it(@"should upload choices that failed to upload in previous presentations", ^{ - NSMutableDictionary<SDLRPCRequest *, NSError *> *testErrors = [NSMutableDictionary dictionary]; - SDLCreateInteractionChoiceSet *failedChoiceSet = [[SDLCreateInteractionChoiceSet alloc] initWithId:0 choiceSet:@[[[SDLChoice alloc] initWithId:1 menuName:@"1" vrCommands:nil]]]; - testErrors[failedChoiceSet] = [NSError sdl_choiceSetManager_choiceUploadFailed:[NSDictionary dictionary]]; - NSError *testInternalError = [NSError sdl_choiceSetManager_choiceUploadFailed:testErrors]; - - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingMutablePreloadChoices.count).to(equal(4)); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[0])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[1])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[2])); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[3])); - expect(testManager.pendingPresentationSet).to(equal(testFailedChoiceSet)); - preloadChoicesOperation.internalError = testInternalError; - preloadChoicesOperation.failedChoiceUploadIDs = [[NSMutableArray alloc] initWithArray:(@[@1])]; - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([choiceDelegate choiceSet:[OCMArg any] didReceiveError:testInternalError]); - - [testManager presentChoiceSet:testFailedChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 1.0); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).toNot(beNil()); - expect(testManager.pendingPresentOperation).toNot(beNil()); - - expect(testManager.preloadedMutableChoices.count).to(equal(3)); - expect(testManager.preloadedMutableChoices).toNot(contain(testFailedChoiceSet.choices[0])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[1])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[2])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[3])); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - - // Present the exact same choices again - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingMutablePreloadChoices.count).to(equal(1)); - expect(testManager.pendingMutablePreloadChoices).to(contain(testFailedChoiceSet.choices[0])); - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - presentChoicesOperation.selectedCell = testSelectedCell; - presentChoicesOperation.selectedTriggerSource = testMode; - presentChoicesOperation.selectedCellRow = testSelectedCellRow; - presentChoicesOperation.internalError = nil; - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - OCMExpect([choiceDelegate choiceSet:testChoiceSet didSelectChoice:testSelectedCell withSource:testMode atRowIndex:testSelectedCellRow]); - - [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).to(beNil()); - expect(testManager.pendingPresentOperation).to(beNil()); - - expect(testManager.preloadedMutableChoices.count).to(equal(4)); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[0])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[1])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[2])); - expect(testManager.preloadedMutableChoices).to(contain(testFailedChoiceSet.choices[3])); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - }); - it(@"should not present choices if the manager shuts down after the choices are uploaded but before presentation", ^{ - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingPresentationSet).to(equal(testChoiceSet)); - [preloadChoicesOperation finishOperation]; - [testManager.stateMachine setToState:SDLChoiceManagerStateShutdown fromOldState:nil callEnterTransition:NO]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMReject([strickMockOperationQueue addOperation:[OCMArg isKindOfClass:SDLPresentChoiceSetOperation.class]]); - + OCMExpect([choiceDelegate choiceSet:[OCMArg any] didReceiveError:[OCMArg isNotNil]]); [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:nil]; - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); + SDLPreloadPresentChoicesOperation *preload = (SDLPreloadPresentChoicesOperation *)testManager.transactionQueue.operations[0]; + preload.loadedCells = [NSSet setWithArray:testChoiceSet.choices]; - expect(testManager.pendingPresentOperation).toEventually(beNil()); - expect(testManager.pendingPresentationSet).toEventually(beNil()); - }); - - context(@"non-searchable", ^{ - it(@"should notify the choice delegate when a choice item is selected", ^{ - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingPresentationSet).to(equal(testChoiceSet)); - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - presentChoicesOperation.selectedCell = testSelectedCell; - presentChoicesOperation.selectedTriggerSource = testMode; - presentChoicesOperation.selectedCellRow = testSelectedCellRow; - presentChoicesOperation.internalError = nil; - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - OCMExpect([choiceDelegate choiceSet:testChoiceSet didSelectChoice:testSelectedCell withSource:testMode atRowIndex:testSelectedCellRow]); - - [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:nil]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).to(beNil()); - expect(testManager.pendingPresentOperation).to(beNil()); - }); + [SDLGlobals runSyncOnSerialSubQueue:testManager.readWriteQueue block:^{ + [testManager.stateMachine setToState:SDLChoiceManagerStateShutdown fromOldState:SDLChoiceManagerStateReady callEnterTransition:YES]; + }]; + [preload finishOperation]; - it(@"should notify the choice delegate if an error occured during presentation", ^{ - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingPresentationSet).to(equal(testChoiceSet)); - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - presentChoicesOperation.internalError = testError; - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - OCMExpect([choiceDelegate choiceSet:[OCMArg any] didReceiveError:testError]); - - [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:nil]; - - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - OCMVerifyAllWithDelay(choiceDelegate, 0.5); - - expect(testManager.pendingPresentationSet).to(beNil()); - expect(testManager.pendingPresentOperation).to(beNil()); - }); + expect(testManager.preloadedChoices).to(beEmpty()); + expect(testManager.transactionQueue.operationCount).to(equal(0)); }); describe(@"when the manager shuts down during presentation", ^{ - __block SDLPresentChoiceSetOperation *presentChoicesOperation = nil; - it(@"should leave the list of pending and uploaded choice items empty when the operation finishes", ^{ - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - expect(testManager.pendingPresentationSet).to(equal(testChoiceSet)); - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - presentChoicesOperation.internalError = nil; - testManager.pendingMutablePreloadChoices = [NSMutableSet set]; - testManager.preloadedMutableChoices = [NSMutableSet set]; - - [testManager.stateMachine setToState:SDLChoiceManagerStateShutdown fromOldState:nil callEnterTransition:NO]; - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - [testManager presentChoiceSet:testChoiceSet mode:testMode withKeyboardDelegate:keyboardDelegate]; - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - expect(testManager.preloadedMutableChoices).to(beEmpty()); + SDLPreloadPresentChoicesOperation *preloadChoicesOperation = (SDLPreloadPresentChoicesOperation *)testManager.transactionQueue.operations.firstObject; + [testManager.stateMachine setToState:SDLChoiceManagerStateShutdown fromOldState:nil callEnterTransition:NO]; + [preloadChoicesOperation finishOperation]; + expect(testManager.preloadedChoices).to(beEmpty()); - expect(testManager.pendingMutablePreloadChoices).to(beEmpty()); - expect(testManager.pendingPreloadChoices).to(beEmpty()); }); }); - - afterEach(^{ - [strickMockOperationQueue stopMocking]; - }); }); describe(@"presenting a keyboard", ^{ - __block SDLPresentChoiceSetOperation *pendingPresentOp = nil; __block NSString *testInitialText = @"Test text"; __block id<SDLKeyboardDelegate> testKeyboardDelegate = nil; beforeEach(^{ testKeyboardDelegate = OCMProtocolMock(@protocol(SDLKeyboardDelegate)); - - pendingPresentOp = OCMClassMock([SDLPresentChoiceSetOperation class]); - testManager.pendingPresentOperation = pendingPresentOp; - testManager.pendingPresentationSet = [[SDLChoiceSet alloc] init]; }); it(@"should return a cancelID and should properly start the keyboard presentation with presentKeyboardWithInitialText:keyboardDelegate:", ^{ NSNumber *cancelID = [testManager presentKeyboardWithInitialText:testInitialText delegate:testKeyboardDelegate]; expect(cancelID).toNot(beNil()); - OCMVerify([pendingPresentOp cancel]); expect(testManager.transactionQueue.operations).to(haveCount(1)); - expect(testManager.pendingPresentOperation).to(beAnInstanceOf([SDLPresentKeyboardOperation class])); + expect( testManager.transactionQueue.operations[0]).to(beAnInstanceOf([SDLPresentKeyboardOperation class])); }); - it(@"should return nil and should not start the keyboard presentation if the the keyboard can not be sent to Core", ^{ + it(@"should return nil and should not start the keyboard presentation if the keyboard can not be sent to Core", ^{ [testManager.stateMachine setToState:SDLChoiceManagerStateCheckingVoiceOptional fromOldState:SDLChoiceManagerStateShutdown callEnterTransition:NO]; NSNumber *cancelID = [testManager presentKeyboardWithInitialText:testInitialText delegate:testKeyboardDelegate]; expect(cancelID).to(beNil()); - OCMReject([pendingPresentOp cancel]); expect(testManager.transactionQueue.operations).to(haveCount(0)); - expect(testManager.pendingPresentOperation).toNot(beAnInstanceOf([SDLPresentKeyboardOperation class])); }); }); @@ -923,7 +397,6 @@ describe(@"choice set manager tests", ^{ __block SDLChoiceSet *testChoiceSet = nil; __block SDLChoiceSet *testChoiceSet2 = nil; __block id<SDLChoiceSetDelegate> testChoiceDelegate = nil; - __block id strickMockOperationQueue = nil; beforeEach(^{ testChoiceDelegate = OCMProtocolMock(@protocol(SDLChoiceSetDelegate)); @@ -931,67 +404,29 @@ describe(@"choice set manager tests", ^{ testChoiceSet2 = [[SDLChoiceSet alloc] initWithTitle:@"choice set 2" delegate:testChoiceDelegate choices:@[testCell2]]; testManager = [[SDLChoiceSetManager alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager systemCapabilityManager:testSystemCapabilityManager]; [testManager.stateMachine setToState:SDLChoiceManagerStateReady fromOldState:SDLChoiceManagerStateCheckingVoiceOptional callEnterTransition:NO]; - strickMockOperationQueue = OCMStrictClassMock([NSOperationQueue class]); - testManager.transactionQueue = strickMockOperationQueue; }); it(@"should set the first cancelID correctly", ^{ - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - expect(@(presentChoicesOperation.cancelId)).to(equal(101)); - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); - [testManager presentChoiceSet:testChoiceSet mode:SDLInteractionModeBoth withKeyboardDelegate:nil]; - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); + SDLPreloadPresentChoicesOperation *preloadChoicesOperation = (SDLPreloadPresentChoicesOperation *)testManager.transactionQueue.operations[0]; + expect(@(preloadChoicesOperation.cancelId)).to(equal(101)); }); it(@"should reset the cancelID correctly once the max has been reached", ^{ - testManager.nextCancelId = 200; // set the max cancelID - - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - expect(@(presentChoicesOperation.cancelId)).to(equal(200)); - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); + testManager.nextCancelId = 200; [testManager presentChoiceSet:testChoiceSet mode:SDLInteractionModeBoth withKeyboardDelegate:nil]; - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPreloadChoicesOperation *preloadChoicesOperation = (SDLPreloadChoicesOperation *)value; - [preloadChoicesOperation finishOperation]; - return [value isKindOfClass:[SDLPreloadChoicesOperation class]]; - }]]); - OCMExpect([strickMockOperationQueue addOperation:[OCMArg checkWithBlock:^BOOL(id value) { - SDLPresentChoiceSetOperation *presentChoicesOperation = (SDLPresentChoiceSetOperation *)value; - expect(@(presentChoicesOperation.cancelId)).to(equal(101)); - presentChoicesOperation.completionBlock(); - return [value isKindOfClass:[SDLPresentChoiceSetOperation class]]; - }]]); + SDLPreloadPresentChoicesOperation *presentChoicesOperation = testManager.transactionQueue.operations[0]; + expect(@(presentChoicesOperation.cancelId)).to(equal(200)); [testManager presentChoiceSet:testChoiceSet2 mode:SDLInteractionModeBoth withKeyboardDelegate:nil]; - OCMVerifyAllWithDelay(strickMockOperationQueue, 0.5); - }); + [NSThread sleepForTimeInterval:0.5]; - afterEach(^{ - [strickMockOperationQueue stopMocking]; + SDLPreloadPresentChoicesOperation *presentChoicesOperation2 = (SDLPreloadPresentChoicesOperation *)testManager.transactionQueue.operations[1]; + expect(@(presentChoicesOperation2.cancelId)).to(equal(101)); }); }); diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLDeleteChoicesOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLDeleteChoicesOperationSpec.m index 2996da282..adf5632a6 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLDeleteChoicesOperationSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLDeleteChoicesOperationSpec.m @@ -14,20 +14,23 @@ describe(@"delete choices operation", ^{ __block TestConnectionManager *testConnectionManager = nil; __block SDLDeleteChoicesOperation *testOp = nil; __block NSSet<SDLChoiceCell *> *testCellsToDelete = nil; + __block NSSet<SDLChoiceCell *> *testLoadedCells = nil; - __block BOOL hasCalledOperationCompletionHandler = NO; __block NSError *resultError = nil; + __block NSSet<SDLChoiceCell *> *resultLoadedCells; beforeEach(^{ - hasCalledOperationCompletionHandler = NO; - testConnectionManager = [[TestConnectionManager alloc] init]; testCellsToDelete = [NSSet setWithArray:@[[[SDLChoiceCell alloc] initWithText:@"Text"], [[SDLChoiceCell alloc] initWithText:@"Text 2"]]]; - testOp = [[SDLDeleteChoicesOperation alloc] initWithConnectionManager:testConnectionManager cellsToDelete:testCellsToDelete]; - testOp.completionBlock = ^{ - hasCalledOperationCompletionHandler = YES; - resultError = testOp.error; - }; + testLoadedCells = testCellsToDelete; + + resultError = nil; + resultLoadedCells = nil; + + testOp = [[SDLDeleteChoicesOperation alloc] initWithConnectionManager:testConnectionManager cellsToDelete:testCellsToDelete loadedCells:testLoadedCells completionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultLoadedCells = updatedLoadedCells; + resultError = error; + }]; }); it(@"should have priority of 'normal'", ^{ @@ -56,7 +59,7 @@ describe(@"delete choices operation", ^{ }); it(@"should finish with success", ^{ - expect(hasCalledOperationCompletionHandler).toEventually(beTrue()); + expect(resultLoadedCells).toEventuallyNot(beNil()); expect(resultError).to(beNil()); }); }); @@ -66,8 +69,8 @@ describe(@"delete choices operation", ^{ [testConnectionManager respondToLastMultipleRequestsWithSuccess:NO]; }); - it(@"should finish with success", ^{ - expect(hasCalledOperationCompletionHandler).toEventually(beTrue()); + it(@"should finish with a failure", ^{ + expect(resultLoadedCells).toEventuallyNot(beNil()); expect(resultError).toNot(beNil()); }); }); diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadChoicesOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadChoicesOperationSpec.m deleted file mode 100644 index fc6fdfe00..000000000 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadChoicesOperationSpec.m +++ /dev/null @@ -1,417 +0,0 @@ -#import <Quick/Quick.h> -#import <Nimble/Nimble.h> -#import <OCMock/OCMock.h> - -#import "SDLPreloadChoicesOperation.h" - -#import "SDLChoice.h" -#import "SDLChoiceCell.h" -#import "SDLCreateInteractionChoiceSet.h" -#import "SDLDisplayType.h" -#import "SDLFileManager.h" -#import "SDLImageField.h" -#import "SDLImageFieldName.h" -#import "SDLTextField.h" -#import "SDLTextFieldName.h" -#import "SDLWindowCapability.h" -#import "TestConnectionManager.h" - -@interface SDLPreloadChoicesOperation() - -@property (strong, nonatomic, nullable) NSMutableArray<NSNumber *> *failedChoiceUploadIDs; - -@end - -@interface SDLChoiceCell() - -@property (assign, nonatomic) UInt16 choiceId; - -@end - -QuickSpecBegin(SDLPreloadChoicesOperationSpec) - -describe(@"a preload choices operation", ^{ - __block TestConnectionManager *testConnectionManager = nil; - __block SDLFileManager *testFileManager = nil; - __block SDLPreloadChoicesOperation *testOp = nil; - __block NSString *testDisplayName = @"SDL_GENERIC"; - - __block NSData *cellArtData = [@"testart" dataUsingEncoding:NSUTF8StringEncoding]; - __block NSData *cellArtData2 = [@"testart2" dataUsingEncoding:NSUTF8StringEncoding]; - - __block BOOL hasCalledOperationCompletionHandler = NO; - __block NSError *resultError = nil; - - beforeEach(^{ - resultError = nil; - hasCalledOperationCompletionHandler = NO; - - testConnectionManager = [[TestConnectionManager alloc] init]; - testFileManager = OCMClassMock([SDLFileManager class]); - }); - - it(@"should have a priority of 'normal'", ^{ - testOp = [[SDLPreloadChoicesOperation alloc] init]; - - expect(@(testOp.queuePriority)).to(equal(@(NSOperationQueuePriorityNormal))); - }); - - describe(@"running the operation", ^{ - __block SDLWindowCapability *windowCapability = nil; - beforeEach(^{ - windowCapability = [[SDLWindowCapability alloc] init]; - windowCapability.imageTypeSupported = @[SDLImageTypeStatic, SDLImageTypeDynamic]; - SDLTextField *primaryTextField = [[SDLTextField alloc] init]; - primaryTextField.name = SDLTextFieldNameMenuName; - windowCapability.textFields = @[primaryTextField]; - - OCMStub([testFileManager uploadArtworks:[OCMArg any] completionHandler:[OCMArg invokeBlock]]); - OCMStub([testFileManager fileNeedsUpload:[OCMArg isNotNil]]).andReturn(YES); - }); - - context(@"with artworks", ^{ - __block NSOrderedSet<SDLChoiceCell *> *cellsWithArtwork = nil; - __block NSOrderedSet<SDLChoiceCell *> *cellsWithStaticIcon = nil; - __block NSString *art1Name = @"Art1Name"; - __block NSString *art2Name = @"Art2Name"; - __block SDLArtwork *cell1Art2 = [[SDLArtwork alloc] initWithData:cellArtData2 name:art1Name fileExtension:@"png" persistent:NO]; - - beforeEach(^{ - SDLArtwork *cell1Art = [[SDLArtwork alloc] initWithData:cellArtData name:art1Name fileExtension:@"png" persistent:NO]; - SDLChoiceCell *cell1WithArt = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:cell1Art voiceCommands:nil]; - - SDLArtwork *cell2Art = [[SDLArtwork alloc] initWithData:cellArtData name:art2Name fileExtension:@"png" persistent:NO]; - SDLChoiceCell *cell2WithArtAndSecondary = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:cell2Art secondaryArtwork:cell2Art]; - - SDLArtwork *staticIconArt = [SDLArtwork artworkWithStaticIcon:SDLStaticIconNameDate]; - SDLChoiceCell *cellWithStaticIcon = [[SDLChoiceCell alloc] initWithText:@"Static Icon" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:staticIconArt secondaryArtwork:nil]; - - cellsWithArtwork = [[NSOrderedSet alloc] initWithArray:@[cell1WithArt, cell2WithArtAndSecondary]]; - cellsWithStaticIcon = [[NSOrderedSet alloc] initWithArray:@[cellWithStaticIcon]]; - }); - - context(@"if the menuName is not set", ^{ - it(@"should not send any requests", ^{ - SDLTextField *primaryTextField = [[SDLTextField alloc] init]; - primaryTextField.name = SDLTextFieldNameMenuName; - windowCapability.textFields = @[]; - - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(0)); - }); - }); - - context(@"only main text capabilities", ^{ - it(@"should skip to preloading cells", ^{ - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - expect(@(testOp.currentState)).to(equal(SDLPreloadChoicesOperationStatePreloadingChoices)); - }); - }); - - context(@"only main text and image capabilities", ^{ - beforeEach(^{ - SDLImageField *choiceField = [[SDLImageField alloc] init]; - choiceField.name = SDLImageFieldNameChoiceImage; - windowCapability.imageFields = @[choiceField]; - - OCMStub([testFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(NO); - - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - }); - - it(@"should upload some artworks", ^{ - OCMVerify([testFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id obj) { - NSArray<SDLArtwork *> *artworks = (NSArray<SDLArtwork *> *)obj; - return (artworks.count == 2); - }] completionHandler:[OCMArg any]]); - expect(@(testOp.currentState)).to(equal(SDLPreloadChoicesOperationStatePreloadingChoices)); - }); - }); - - context(@"main text and all image display capabilities", ^{ - beforeEach(^{ - SDLImageField *choiceField = [[SDLImageField alloc] init]; - choiceField.name = SDLImageFieldNameChoiceImage; - SDLImageField *choiceSecondaryField = [[SDLImageField alloc] init]; - choiceSecondaryField.name = SDLImageFieldNameChoiceSecondaryImage; - - windowCapability.imageFields = @[choiceField, choiceSecondaryField]; - }); - - context(@"when artworks are already on the system", ^{ - beforeEach(^{ - OCMStub([testFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(YES); - - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - }); - - it(@"should not upload artworks", ^{ - OCMReject([testFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id obj) { - NSArray<SDLArtwork *> *artworks = (NSArray<SDLArtwork *> *)obj; - return (artworks.count == 2); - }] completionHandler:[OCMArg any]]); - expect(@(testOp.currentState)).to(equal(SDLPreloadChoicesOperationStatePreloadingChoices)); - }); - - it(@"should properly overwrite artwork", ^{ - cell1Art2.overwrite = YES; - SDLChoiceCell *cell1WithArt = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:cell1Art2 voiceCommands:nil]; - - SDLArtwork *cell2Art = [[SDLArtwork alloc] initWithData:cellArtData name:art2Name fileExtension:@"png" persistent:NO]; - SDLChoiceCell *cell2WithArtAndSecondary = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:cell2Art secondaryArtwork:cell2Art]; - - SDLArtwork *staticIconArt = [SDLArtwork artworkWithStaticIcon:SDLStaticIconNameDate]; - SDLChoiceCell *cellWithStaticIcon = [[SDLChoiceCell alloc] initWithText:@"Static Icon" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:staticIconArt secondaryArtwork:nil]; - - cellsWithArtwork = [[NSOrderedSet alloc] initWithArray:@[cell1WithArt, cell2WithArtAndSecondary]]; - cellsWithStaticIcon = [[NSOrderedSet alloc] initWithArray:@[cellWithStaticIcon]]; - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - OCMExpect([testFileManager uploadArtworks:[OCMArg any] completionHandler:[OCMArg any]]); - OCMVerify([testFileManager uploadArtworks:[OCMArg any] completionHandler:[OCMArg any]]); - }); - }); - - context(@"when artworks are static icons", ^{ - beforeEach(^{ - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithStaticIcon updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - }); - - it(@"should skip uploading artwork", ^{ - OCMReject([testFileManager uploadArtwork:[OCMArg any] completionHandler:[OCMArg any]]); - }); - }); - - context(@"when artwork are not already on the system", ^{ - beforeEach(^{ - OCMStub([testFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(NO); - - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - }); - - it(@"should upload artworks", ^{ - OCMVerify([testFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id obj) { - NSArray<SDLArtwork *> *artworks = (NSArray<SDLArtwork *> *)obj; - return (artworks.count == 3); - }] completionHandler:[OCMArg any]]); - expect(@(testOp.currentState)).to(equal(SDLPreloadChoicesOperationStatePreloadingChoices)); - }); - }); - }); - }); - - context(@"without artworks", ^{ - __block NSOrderedSet<SDLChoiceCell *> *cellsWithoutArtwork = nil; - beforeEach(^{ - SDLChoiceCell *cellBasic = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:nil voiceCommands:nil]; - SDLChoiceCell *cellWithVR = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:nil tertiaryText:nil voiceCommands:@[@"Cell2"] artwork:nil secondaryArtwork:nil]; - SDLChoiceCell *cellWithAllText = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:@"Cell2" tertiaryText:@"Cell2" voiceCommands:nil artwork:nil secondaryArtwork:nil]; - cellsWithoutArtwork = [[NSOrderedSet alloc] initWithArray:@[cellBasic, cellWithVR, cellWithAllText]]; - }); - - it(@"should skip to preloading cells", ^{ - expect(@(testOp.currentState)).to(equal(SDLPreloadChoicesOperationStatePreloadingChoices)); - }); - - describe(@"assembling choices", ^{ - it(@"should be correct with no text and VR required", ^{ - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(3)); - expect(receivedRequests.lastObject.choiceSet.firstObject.menuName).toNot(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.secondaryText).to(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.tertiaryText).to(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.vrCommands).toNot(beNil()); - }); - - it(@"should be correct with only primary text", ^{ - SDLTextField *primaryTextField = [[SDLTextField alloc] init]; - primaryTextField.name = SDLTextFieldNameMenuName; - windowCapability.textFields = @[primaryTextField]; - - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(3)); - expect(receivedRequests.lastObject.choiceSet.firstObject.menuName).toNot(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.secondaryText).to(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.tertiaryText).to(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.vrCommands).toNot(beNil()); - }); - - it(@"should be correct with primary and secondary text", ^{ - SDLTextField *primaryTextField = [[SDLTextField alloc] init]; - primaryTextField.name = SDLTextFieldNameMenuName; - SDLTextField *secondaryTextField = [[SDLTextField alloc] init]; - secondaryTextField.name = SDLTextFieldNameSecondaryText; - windowCapability.textFields = @[primaryTextField, secondaryTextField]; - - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(3)); - expect(receivedRequests.lastObject.choiceSet.firstObject.menuName).toNot(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.secondaryText).toNot(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.tertiaryText).to(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.vrCommands).toNot(beNil()); - }); - - it(@"should be correct with all text", ^{ - SDLTextField *primaryTextField = [[SDLTextField alloc] init]; - primaryTextField.name = SDLTextFieldNameMenuName; - SDLTextField *secondaryTextField = [[SDLTextField alloc] init]; - secondaryTextField.name = SDLTextFieldNameSecondaryText; - SDLTextField *tertiaryTextField = [[SDLTextField alloc] init]; - tertiaryTextField.name = SDLTextFieldNameTertiaryText; - windowCapability.textFields = @[primaryTextField, secondaryTextField, tertiaryTextField]; - - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(3)); - expect(receivedRequests.lastObject.choiceSet.firstObject.menuName).toNot(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.secondaryText).toNot(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.tertiaryText).toNot(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.vrCommands).toNot(beNil()); - }); - - it(@"should be correct with VR optional", ^{ - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:YES cellsToPreload:cellsWithoutArtwork updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(3)); - expect(receivedRequests.lastObject.choiceSet.firstObject.menuName).toNot(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.secondaryText).to(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.tertiaryText).to(beNil()); - expect(receivedRequests.lastObject.choiceSet.firstObject.vrCommands).to(beNil()); - }); - }); - }); - - context(@"updating choices", ^{ - __block SDLChoiceCell *testCell1 = nil; - __block SDLChoiceCell *testCell2 = nil; - __block NSOrderedSet<SDLChoiceCell *> *testCells = nil; - - beforeEach(^{ - testCell1 = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:nil voiceCommands:nil]; - testCell2 = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:[SDLArtwork artworkWithStaticIcon:SDLStaticIconNameClock]]; - testCells = [[NSOrderedSet alloc] initWithArray:@[testCell1, testCell2]]; - }); - - describe(@"if a choice item is removed", ^{ - it(@"should be removed if the removal is attempted while the operation is pending", ^{ - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:testCells updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp removeChoicesFromUpload:[NSSet setWithArray:@[testCell1]]]; - [testOp start]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(1)); - expect(receivedRequests[0].choiceSet[0].menuName).to(equal(testCell2.text)); - }); - - it(@"should not be removed if the removal is attempted while operation is executing", ^{ - SDLTextField *primaryTextField = [[SDLTextField alloc] init]; - primaryTextField.name = SDLTextFieldNameMenuName; - windowCapability.textFields = @[primaryTextField]; - - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:testCells updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - [testOp removeChoicesFromUpload:[NSSet setWithArray:@[testCell1]]]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(2)); - expect(receivedRequests[0].choiceSet[0].menuName).to(equal(testCell1.text)); - expect(receivedRequests[1].choiceSet[0].menuName).to(equal(testCell2.text)); - }); - }); - }); - - describe(@"the module's response to choice uploads", ^{ - __block SDLChoiceCell *testCell1 = nil; - __block SDLChoiceCell *testCell2 = nil; - __block NSOrderedSet<SDLChoiceCell *> *testCells = nil; - __block SDLCreateInteractionChoiceSetResponse *testBadResponse = nil; - __block SDLCreateInteractionChoiceSetResponse *testGoodResponse = nil; - - beforeEach(^{ - testCell1 = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:nil voiceCommands:nil]; - testCell1.choiceId = 55; - testCell2 = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:[SDLArtwork artworkWithStaticIcon:SDLStaticIconNameClock]]; - testCell2.choiceId = 66; - testCells = [[NSOrderedSet alloc] initWithArray:@[testCell1, testCell2]]; - - testBadResponse = [[SDLCreateInteractionChoiceSetResponse alloc] init]; - testBadResponse.success = @NO; - testBadResponse.resultCode = SDLResultRejected; - - testGoodResponse = [[SDLCreateInteractionChoiceSetResponse alloc] init]; - testGoodResponse.success = @YES; - testGoodResponse.resultCode = SDLResultSuccess; - }); - - context(@"when a bad response comes back", ^{ - it(@"should add the choiceID of the failed choice item to the failedChoiceUploadIDs array", ^{ - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:testCells updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(2)); - expect(receivedRequests[0].choiceSet[0].menuName).to(equal(testCell1.text)); - expect(receivedRequests[1].choiceSet[0].menuName).to(equal(testCell2.text)); - - [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:0 error:nil]; - [testConnectionManager respondToRequestWithResponse:testBadResponse requestNumber:1 error:[NSError errorWithDomain:SDLErrorDomainChoiceSetManager code:SDLChoiceSetManagerErrorUploadFailed userInfo:nil]]; - - expect(testOp.failedChoiceUploadIDs.count).to(equal(1)); - expect(testOp.failedChoiceUploadIDs).to(contain(@(testCell2.choiceId))); - expect(testOp.failedChoiceUploadIDs).toNot(contain(@(testCell1.choiceId))); - }); - }); - - context(@"when only good responses comes back", ^{ - it(@"should leave the failedChoiceUploadIDs array empty", ^{ - testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:windowCapability isVROptional:NO cellsToPreload:testCells updateCompletionHandler:^(NSArray<NSNumber *> * _Nullable failedChoiceUploadIDs) {}]; - [testOp start]; - - NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; - - expect(receivedRequests).to(haveCount(2)); - expect(receivedRequests[0].choiceSet[0].menuName).to(equal(testCell1.text)); - expect(receivedRequests[1].choiceSet[0].menuName).to(equal(testCell2.text)); - - [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:0 error:nil]; - [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:1 error:nil]; - - expect(testOp.failedChoiceUploadIDs).to(beEmpty()); - }); - }); - }); - }); -}); - -QuickSpecEnd diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadPresentChoicesOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadPresentChoicesOperationSpec.m new file mode 100644 index 000000000..45e4b7efc --- /dev/null +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadPresentChoicesOperationSpec.m @@ -0,0 +1,1070 @@ +#import <Quick/Quick.h> +#import <Nimble/Nimble.h> +#import <OCMock/OCMock.h> + +#import <SmartDeviceLink/SmartDeviceLink.h> +#import "SDLError.h" +#import "SDLPreloadPresentChoicesOperation.h" + +#import "SDLGlobals.h" +#import "TestConnectionManager.h" + +@interface SDLPreloadPresentChoicesOperation() + +// Dependencies +@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager; +@property (weak, nonatomic) SDLFileManager *fileManager; +@property (strong, nonatomic) SDLWindowCapability *windowCapability; + +// Preload Dependencies +@property (strong, nonatomic) NSMutableOrderedSet<SDLChoiceCell *> *cellsToUpload; +@property (strong, nonatomic) NSString *displayName; +@property (assign, nonatomic, readwrite, getter=isVROptional) BOOL vrOptional; +@property (copy, nonatomic) SDLUploadChoicesCompletionHandler preloadCompletionHandler; + +// Present Dependencies +@property (strong, nonatomic) SDLChoiceSet *choiceSet; +@property (strong, nonatomic, nullable) SDLInteractionMode presentationMode; +@property (strong, nonatomic, nullable) SDLKeyboardProperties *originalKeyboardProperties; +@property (strong, nonatomic, nullable) SDLKeyboardProperties *customKeyboardProperties; +@property (weak, nonatomic, nullable) id<SDLKeyboardDelegate> keyboardDelegate; +@property (assign, nonatomic) UInt16 cancelId; + +// Internal operation properties +@property (strong, nonatomic) NSUUID *operationId; +@property (copy, nonatomic, nullable) NSError *internalError; + +// Mutable state +@property (strong, nonatomic) NSMutableSet<SDLChoiceCell *> *mutableLoadedCells; + +@end + +@interface SDLChoiceCell() + +@property (assign, nonatomic) UInt16 choiceId; +@property (assign, nonatomic) NSUInteger uniqueTextId; + +@end + +QuickSpecBegin(SDLPreloadPresentChoicesOperationSpec) + +describe(@"a preload choices operation", ^{ + __block TestConnectionManager *testConnectionManager = nil; + __block SDLFileManager *testFileManager = nil; + __block SDLPreloadPresentChoicesOperation *testOp = nil; + __block NSString *testDisplayName = @"SDL_GENERIC"; + __block SDLVersion *choiceSetUniquenessActiveVersion = [[SDLVersion alloc] initWithMajor:7 minor:1 patch:0]; + __block SDLVersion *choiceSetUniquenessInactiveVersion = [[SDLVersion alloc] initWithMajor:7 minor:0 patch:0]; + + __block SDLWindowCapability *enabledWindowCapability = nil; + __block SDLWindowCapability *disabledWindowCapability = nil; + __block SDLWindowCapability *primaryTextOnlyCapability = nil; + + __block NSSet<SDLChoiceCell *> *emptyLoadedCells = [NSSet set]; + __block NSArray<SDLChoiceCell *> *cellsWithArtwork = nil; + __block NSArray<SDLChoiceCell *> *cellsWithStaticIcon = nil; + __block NSArray<SDLChoiceCell *> *cellsWithoutArtwork = nil; + + __block NSData *cellArtData = [@"testart" dataUsingEncoding:NSUTF8StringEncoding]; + __block NSData *cellArtData2 = [@"testart2" dataUsingEncoding:NSUTF8StringEncoding]; + __block NSString *art1Name = @"Art1Name"; + __block NSString *art2Name = @"Art2Name"; + SDLArtwork *cell1Art = [[SDLArtwork alloc] initWithData:cellArtData name:art1Name fileExtension:@"png" persistent:NO]; + SDLArtwork *cell1Art2 = [[SDLArtwork alloc] initWithData:cellArtData2 name:art1Name fileExtension:@"png" persistent:NO]; + SDLArtwork *cell2Art = [[SDLArtwork alloc] initWithData:cellArtData name:art2Name fileExtension:@"png" persistent:NO]; + + __block SDLChoiceCell *cellBasic = nil; + __block SDLChoiceCell *cellBasicDuplicate = nil; + __block SDLChoiceCell *cellWithVR = nil; + __block SDLChoiceCell *cellWithAllText = nil; + + __block SDLCreateInteractionChoiceSetResponse *testBadResponse = nil; + __block SDLCreateInteractionChoiceSetResponse *testGoodResponse = nil; + + __block NSSet<SDLChoiceCell *> *resultChoices = nil; + __block NSError *resultPreloadError = nil; + + __block SDLChoiceSet *testChoiceSet = nil; + __block int testCancelID = 98; + __block SDLInteractionMode testInteractionMode = SDLInteractionModeBoth; + __block SDLKeyboardProperties *testKeyboardProperties = nil; + __block id<SDLKeyboardDelegate> testKeyboardDelegate = nil; + __block id<SDLChoiceSetDelegate> testChoiceDelegate = nil; + + beforeEach(^{ + resultPreloadError = nil; + resultChoices = nil; + + testConnectionManager = [[TestConnectionManager alloc] init]; + testFileManager = OCMClassMock([SDLFileManager class]); + OCMStub([testFileManager uploadArtworks:[OCMArg any] completionHandler:[OCMArg invokeBlock]]); + OCMStub([testFileManager fileNeedsUpload:[OCMArg isNotNil]]).andReturn(YES); + + enabledWindowCapability = [[SDLWindowCapability alloc] init]; + enabledWindowCapability.textFields = @[ + [[SDLTextField alloc] initWithName:SDLTextFieldNameMenuName characterSet:SDLCharacterSetUtf8 width:500 rows:1], + [[SDLTextField alloc] initWithName:SDLTextFieldNameSecondaryText characterSet:SDLCharacterSetUtf8 width:500 rows:1], + [[SDLTextField alloc] initWithName:SDLTextFieldNameTertiaryText characterSet:SDLCharacterSetUtf8 width:500 rows:1] + ]; + enabledWindowCapability.imageFields = @[ + [[SDLImageField alloc] initWithName:SDLImageFieldNameChoiceImage imageTypeSupported:@[SDLFileTypePNG] imageResolution:nil], + [[SDLImageField alloc] initWithName:SDLImageFieldNameChoiceSecondaryImage imageTypeSupported:@[SDLFileTypePNG] imageResolution:nil] + ]; + disabledWindowCapability = [[SDLWindowCapability alloc] init]; + disabledWindowCapability.textFields = @[]; + primaryTextOnlyCapability = [[SDLWindowCapability alloc] init]; + primaryTextOnlyCapability.textFields = @[ + [[SDLTextField alloc] initWithName:SDLTextFieldNameMenuName characterSet:SDLCharacterSetUtf8 width:500 rows:1], + ]; + + SDLChoiceCell *cell1WithArt = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:cell1Art voiceCommands:nil]; + cell1WithArt.choiceId = 1; + SDLChoiceCell *cell2WithArtAndSecondary = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:cell2Art secondaryArtwork:cell2Art]; + cell2WithArtAndSecondary.choiceId = 2; + + SDLArtwork *staticIconArt = [SDLArtwork artworkWithStaticIcon:SDLStaticIconNameDate]; + SDLChoiceCell *cellWithStaticIcon = [[SDLChoiceCell alloc] initWithText:@"Static Icon" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:staticIconArt secondaryArtwork:nil]; + cellWithStaticIcon.choiceId = 3; + + cellsWithArtwork = @[cell1WithArt, cell2WithArtAndSecondary]; + cellsWithStaticIcon = @[cellWithStaticIcon]; + + cellBasic = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:nil voiceCommands:nil]; + cellBasic.choiceId = 4; + cellBasicDuplicate = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:nil voiceCommands:nil]; + cellBasicDuplicate.choiceId = 5; + cellWithVR = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:nil tertiaryText:nil voiceCommands:@[@"Cell2"] artwork:nil secondaryArtwork:nil]; + cellWithVR.choiceId = 6; + cellWithAllText = [[SDLChoiceCell alloc] initWithText:@"Cell2" secondaryText:@"Cell2" tertiaryText:@"Cell2" voiceCommands:nil artwork:nil secondaryArtwork:nil]; + cellWithAllText.choiceId = 7; + cellsWithoutArtwork = @[cellBasic, cellWithVR, cellWithAllText]; + + testBadResponse = [[SDLCreateInteractionChoiceSetResponse alloc] init]; + testBadResponse.success = @NO; + testBadResponse.resultCode = SDLResultRejected; + + testGoodResponse = [[SDLCreateInteractionChoiceSetResponse alloc] init]; + testGoodResponse.success = @YES; + testGoodResponse.resultCode = SDLResultSuccess; + + testChoiceDelegate = OCMProtocolMock(@protocol(SDLChoiceSetDelegate)); + testKeyboardDelegate = OCMProtocolMock(@protocol(SDLKeyboardDelegate)); + OCMStub([testKeyboardDelegate customKeyboardConfiguration]).andReturn(nil); + testKeyboardProperties = [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageArSa keyboardLayout:SDLKeyboardLayoutAZERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil maskInputCharacters:nil customKeys:nil]; + testChoiceSet = [[SDLChoiceSet alloc] initWithTitle:@"Choice Set" delegate:testChoiceDelegate layout:SDLChoiceSetLayoutTiles timeout:8.0 initialPromptString:@"Initial Prompt" timeoutPromptString:@"Timeout Prompt" helpPromptString:@"Help Prompt" vrHelpList:nil choices:cellsWithoutArtwork]; + }); + + it(@"should have a priority of 'normal'", ^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] init]; + + expect(@(testOp.queuePriority)).to(equal(@(NSOperationQueuePriorityNormal))); + }); + + context(@"running a preload only operation", ^{ + describe(@"updating cells for uniqueness", ^{ + beforeEach(^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:enabledWindowCapability isVROptional:YES cellsToPreload:@[cellWithVR] loadedCells:[NSSet setWithArray:@[cellWithAllText]] preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) {}]; + }); + + context(@"when some choices are already uploaded with duplicate titles version >= 7.1.0", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = choiceSetUniquenessActiveVersion; + }); + + context(@"if there are duplicate cells once you strip unused cell properties", ^{ + beforeEach(^{ + SDLChoiceCell *loadedCell1 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Loaded 1" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + SDLChoiceCell *loadedCell2 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Loaded 2" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + loadedCell2.uniqueTextId = 3; + SDLChoiceCell *loadedCell3 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Loaded 3" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + loadedCell3.uniqueTextId = 5; + + SDLChoiceCell *cellToUpload1 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 1" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + SDLChoiceCell *cellToUpload2 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 2" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + SDLChoiceCell *cellToUpload3 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 3" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + SDLChoiceCell *cellToUpload4 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 4" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + + testOp.windowCapability = primaryTextOnlyCapability; + testOp.loadedCells = [NSSet setWithArray:@[loadedCell1, loadedCell2, loadedCell3]]; + testOp.cellsToUpload = [NSMutableOrderedSet orderedSetWithArray:@[cellToUpload1, cellToUpload2, cellToUpload3, cellToUpload4]]; + [testOp start]; + }); + + it(@"should properly assign unique text", ^{ + expect(testOp.cellsToUpload[0].uniqueText).to(equal(@"Cell 2 (2)")); + expect(testOp.cellsToUpload[1].uniqueText).to(equal(@"Cell 2 (4)")); + expect(testOp.cellsToUpload[2].uniqueText).to(equal(@"Cell 2 (6)")); + expect(testOp.cellsToUpload[3].uniqueText).to(equal(@"Cell 2 (7)")); + expect(testOp.cellsToUpload[0].secondaryText).toNot(beNil()); + }); + }); + + context(@"if all cell properties are used", ^{ + beforeEach(^{ + testOp.windowCapability = enabledWindowCapability; + [testOp start]; + }); + + it(@"should not update the choiceCells' unique title", ^{ + expect(testOp.cellsToUpload[0].uniqueText).to(equal("Cell2")); + expect(testOp.cellsToUpload.count).to(equal(1)); + }); + }); + }); + + context(@"when some choices are already uploaded with duplicate titles version <= 7.1.0", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = choiceSetUniquenessInactiveVersion; + }); + + context(@"if all cell properties are used", ^{ + beforeEach(^{ + testOp.windowCapability = enabledWindowCapability; + [testOp start]; + }); + + it(@"should update the choiceCells' unique title", ^{ + expect(testOp.cellsToUpload[0].uniqueText).to(equal("Cell2 (2)")); + expect(testOp.cellsToUpload.count).to(equal(1)); + }); + }); + }); + }); + + context(@"with artworks", ^{ + context(@"only primary text allowed", ^{ + it(@"should skip loading artworks to preloading cells", ^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:primaryTextOnlyCapability isVROptional:YES cellsToPreload:cellsWithArtwork loadedCells:emptyLoadedCells preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultPreloadError = error; + resultChoices = updatedLoadedCells; + }]; + [testOp start]; + + for (SDLRPCRequest *request in testConnectionManager.receivedRequests) { + expect(request).toNot(beAnInstanceOf(SDLPutFile.class)); + } + expect(testConnectionManager.receivedRequests).to(haveCount(2)); + }); + }); + + context(@"all text and image display capabilities", ^{ + beforeEach(^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:enabledWindowCapability isVROptional:YES cellsToPreload:cellsWithArtwork loadedCells:emptyLoadedCells preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultPreloadError = error; + resultChoices = updatedLoadedCells; + }]; + }); + + context(@"when artworks are already on the system", ^{ + beforeEach(^{ + OCMStub([testFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(YES); + }); + + it(@"should not upload artworks", ^{ + OCMReject([testFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id obj) { + NSArray<SDLArtwork *> *artworks = (NSArray<SDLArtwork *> *)obj; + return (artworks.count == 2); + }] completionHandler:[OCMArg any]]); + + [testOp start]; + + OCMVerifyAll(testFileManager); + }); + + it(@"should properly overwrite artwork", ^{ + cell1Art2.overwrite = YES; + SDLChoiceCell *cellOverwriteArt = [[SDLChoiceCell alloc] initWithText:@"Cell1" artwork:cell1Art2 voiceCommands:nil]; + + testOp.cellsToUpload = [NSMutableOrderedSet orderedSetWithArray:@[cellOverwriteArt]]; + [testOp start]; + + OCMVerify([testFileManager uploadArtworks:[OCMArg isNotNil] completionHandler:[OCMArg any]]); + }); + }); + + context(@"when artworks are static icons", ^{ + beforeEach(^{ + testOp.cellsToUpload = [NSMutableOrderedSet orderedSetWithArray:cellsWithStaticIcon]; + [testOp start]; + }); + + it(@"should skip uploading artwork", ^{ + OCMReject([testFileManager uploadArtwork:[OCMArg any] completionHandler:[OCMArg any]]); + }); + }); + + fcontext(@"when artworks are not already on the system", ^{ + beforeEach(^{ + OCMStub([testFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(NO); + }); + + context(@"when there's more than one of the same artwork", ^{ + beforeEach(^{ + testOp.cellsToUpload = [NSMutableOrderedSet orderedSetWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1" artwork:cell1Art voiceCommands:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 2" artwork:cell1Art voiceCommands:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 3" artwork:cell1Art voiceCommands:nil], + ]]; + testOp.loadedCells = [NSSet set]; + }); + + it(@"should only attempt to upload one of each art", ^{ + [testOp start]; + OCMVerify([testFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id obj) { + NSArray<SDLArtwork *> *artworks = (NSArray<SDLArtwork *> *)obj; + return (artworks.count == 1); + }] completionHandler:[OCMArg any]]); + }); + }); + + context(@"when uploading unique art", ^{ + beforeEach(^{ + testOp.cellsToUpload = [NSMutableOrderedSet orderedSetWithArray:cellsWithArtwork]; + testOp.loadedCells = [NSSet set]; + }); + + it(@"should upload artworks", ^{ + [testOp start]; + OCMVerify([testFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id obj) { + NSArray<SDLArtwork *> *artworks = (NSArray<SDLArtwork *> *)obj; + return (artworks.count == 2); + }] completionHandler:[OCMArg any]]); + }); + }); + }); + }); + }); + + context(@"without artworks", ^{ + describe(@"only main text capabilities", ^{ + it(@"should skip loading artworks to preloading cells", ^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:primaryTextOnlyCapability isVROptional:YES cellsToPreload:cellsWithArtwork loadedCells:emptyLoadedCells preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultPreloadError = error; + resultChoices = updatedLoadedCells; + }]; + [testOp start]; + + for (SDLRPCRequest *request in testConnectionManager.receivedRequests) { + expect(request).toNot(beAnInstanceOf(SDLPutFile.class)); + } + expect(testConnectionManager.receivedRequests).to(haveCount(2)); + }); + }); + + describe(@"assembling choices", ^{ + beforeEach(^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:enabledWindowCapability isVROptional:YES cellsToPreload:cellsWithoutArtwork loadedCells:emptyLoadedCells preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultChoices = updatedLoadedCells; + resultPreloadError = error; + }]; + }); + + it(@"should skip preloading the choices if all choice items have already been uploaded", ^{ + testOp.loadedCells = [NSSet setWithArray:cellsWithoutArtwork]; + [testOp start]; + + expect(testConnectionManager.receivedRequests).to(haveCount(0)); + }); + + it(@"should not send any requests if all items are disabled", ^{ + testOp.windowCapability = disabledWindowCapability; + [testOp start]; + + expect(testConnectionManager.receivedRequests).to(haveCount(0)); + }); + + it(@"should be correct with only primary text", ^{ + testOp.windowCapability = primaryTextOnlyCapability; + [testOp start]; + + NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; + + expect(receivedRequests).to(haveCount(3)); + + SDLChoice *representativeItem = receivedRequests.lastObject.choiceSet.firstObject; + expect(representativeItem.menuName).toNot(beNil()); + expect(representativeItem.secondaryText).to(beNil()); + expect(representativeItem.tertiaryText).to(beNil()); + }); + + it(@"should be correct with all text", ^{ + SDLWindowCapability *allTextCapability = [enabledWindowCapability copy]; + allTextCapability.imageFields = @[]; + testOp.windowCapability = allTextCapability; + [testOp start]; + + NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; + + expect(receivedRequests).to(haveCount(3)); + + SDLChoice *representativeItem = receivedRequests.lastObject.choiceSet.firstObject; + expect(representativeItem.menuName).toNot(beNil()); + expect(representativeItem.secondaryText).toNot(beNil()); + expect(representativeItem.tertiaryText).toNot(beNil()); + }); + + it(@"should be correct with VR required", ^{ + testOp.vrOptional = NO; + [testOp start]; + + NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; + + expect(receivedRequests).to(haveCount(3)); + + // The last item has no VR + SDLChoice *representativeItem = receivedRequests.lastObject.choiceSet.firstObject; + expect(representativeItem.vrCommands).toNot(beNil()); + }); + + it(@"should be correct with VR Optional", ^{ + testOp.vrOptional = YES; + [testOp start]; + + NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; + + expect(receivedRequests).to(haveCount(3)); + + // The middle item is the one with VR + SDLChoice *representativeItem = receivedRequests.lastObject.choiceSet.firstObject; + expect(representativeItem.vrCommands).to(beNil()); + }); + }); + }); + + describe(@"the module's response to choice uploads", ^{ + context(@"when a bad response comes back", ^{ + beforeEach(^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:primaryTextOnlyCapability isVROptional:YES cellsToPreload:cellsWithoutArtwork loadedCells:emptyLoadedCells preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultChoices = updatedLoadedCells; + resultPreloadError = error; + }]; + }); + + it(@"should not add the item to the list of loaded cells", ^{ + [testOp start]; + + NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; + + expect(receivedRequests).to(haveCount(3)); + expect(receivedRequests[0].choiceSet[0].menuName).to(equal(cellsWithoutArtwork[0].uniqueText)); + expect(receivedRequests[1].choiceSet[0].menuName).to(equal(cellsWithoutArtwork[1].uniqueText)); + expect(receivedRequests[2].choiceSet[0].menuName).to(equal(cellsWithoutArtwork[2].uniqueText)); + + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:0 error:nil]; + [testConnectionManager respondToRequestWithResponse:testBadResponse requestNumber:1 error:[NSError errorWithDomain:SDLErrorDomainChoiceSetManager code:SDLChoiceSetManagerErrorUploadFailed userInfo:nil]]; + [testConnectionManager respondToLastMultipleRequestsWithSuccess:NO]; + + expect(testOp.loadedCells).to(haveCount(1)); + expect(testOp.loadedCells).to(contain(cellsWithoutArtwork[0])); + expect(testOp.loadedCells).toNot(contain(cellsWithoutArtwork[1])); + expect(testOp.error).toNot(beNil()); + expect(resultChoices).toNot(beNil()); + expect(resultPreloadError).toNot(beNil()); + }); + }); + + context(@"when only good responses comes back", ^{ + beforeEach(^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:testDisplayName windowCapability:primaryTextOnlyCapability isVROptional:YES cellsToPreload:cellsWithoutArtwork loadedCells:emptyLoadedCells preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultChoices = updatedLoadedCells; + resultPreloadError = error; + }]; + }); + + it(@"should add all the items to the list of loaded cells", ^{ + [testOp start]; + + NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests; + + expect(receivedRequests).to(haveCount(3)); + expect(receivedRequests[0].choiceSet[0].menuName).to(equal(cellsWithoutArtwork[0].uniqueText)); + expect(receivedRequests[1].choiceSet[0].menuName).to(equal(cellsWithoutArtwork[1].uniqueText)); + expect(receivedRequests[2].choiceSet[0].menuName).to(equal(cellsWithoutArtwork[2].uniqueText)); + + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:0 error:nil]; + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:1 error:nil]; + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:2 error:nil]; + [testConnectionManager respondToLastMultipleRequestsWithSuccess:YES]; + + expect(testOp.loadedCells).to(haveCount(3)); + expect(testOp.loadedCells).to(contain(cellsWithoutArtwork[0])); + expect(testOp.loadedCells).to(contain(cellsWithoutArtwork[1])); + expect(testOp.loadedCells).to(contain(cellsWithoutArtwork[2])); + expect(resultPreloadError).to(beNil()); + expect(resultChoices).to(haveCount(3)); + }); + }); + }); + }); + + context(@"running a preload and present operation", ^{ + beforeEach(^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:testKeyboardProperties keyboardDelegate:testKeyboardDelegate cancelID:testCancelID displayName:testDisplayName windowCapability:enabledWindowCapability isVROptional:YES loadedCells:emptyLoadedCells preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultChoices = updatedLoadedCells; + resultPreloadError = error; + }]; + }); + + describe(@"updating cells for uniqueness", ^{ + beforeEach(^{ + testOp = [[SDLPreloadPresentChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager choiceSet:[[SDLChoiceSet alloc] initWithTitle:@"Test Choice Set" delegate:testChoiceDelegate choices:@[cellWithVR]] mode:testInteractionMode keyboardProperties:testKeyboardProperties keyboardDelegate:testKeyboardDelegate cancelID:testCancelID displayName:testDisplayName windowCapability:enabledWindowCapability isVROptional:YES loadedCells:[NSSet setWithArray:@[cellWithAllText]] preloadCompletionHandler:^(NSSet<SDLChoiceCell *> * _Nonnull updatedLoadedCells, NSError * _Nullable error) { + resultChoices = updatedLoadedCells; + resultPreloadError = error; + }]; + }); + + context(@"when some choices are already uploaded with duplicate titles version >= 7.1.0", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = choiceSetUniquenessActiveVersion; + }); + + context(@"if there are duplicate cells once you strip unused cell properties", ^{ + beforeEach(^{ + SDLChoiceCell *loadedCell1 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Loaded 1" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + SDLChoiceCell *loadedCell2 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Loaded 2" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + loadedCell2.uniqueTextId = 3; + SDLChoiceCell *loadedCell3 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Loaded 3" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + loadedCell3.uniqueTextId = 5; + + SDLChoiceCell *cellToUpload1 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 1" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + SDLChoiceCell *cellToUpload2 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 2" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + SDLChoiceCell *cellToUpload3 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 3" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + SDLChoiceCell *cellToUpload4 = [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 4" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil]; + + testOp.windowCapability = primaryTextOnlyCapability; + testOp.loadedCells = [NSSet setWithArray:@[loadedCell1, loadedCell2, loadedCell3]]; + testOp.choiceSet.choices = @[cellToUpload1, cellToUpload2, cellToUpload3, cellToUpload4]; + testOp.cellsToUpload = [[NSMutableOrderedSet alloc] initWithArray:@[cellToUpload1, cellToUpload2, cellToUpload3, cellToUpload4]]; + [testOp start]; + }); + + it(@"should properly assign unique text", ^{ + expect(testOp.cellsToUpload[0].uniqueText).to(equal(@"Cell 2 (2)")); + expect(testOp.cellsToUpload[1].uniqueText).to(equal(@"Cell 2 (4)")); + expect(testOp.cellsToUpload[2].uniqueText).to(equal(@"Cell 2 (6)")); + expect(testOp.cellsToUpload[3].uniqueText).to(equal(@"Cell 2 (7)")); + expect(testOp.cellsToUpload[0].secondaryText).toNot(beNil()); + expect(testOp.choiceSet.choices[0].uniqueText).to(equal(@"Cell 2 (2)")); + }); + }); + + context(@"if all cell properties are used", ^{ + beforeEach(^{ + testOp.windowCapability = enabledWindowCapability; + [testOp start]; + }); + + it(@"should not update the choiceCells' unique title", ^{ + expect(testOp.cellsToUpload[0].uniqueText).to(equal(@"Cell2")); + expect(testOp.cellsToUpload.count).to(equal(1)); + expect(testOp.choiceSet.choices[0].uniqueText).to(equal(@"Cell2")); + }); + }); + }); + + context(@"when some choices are already uploaded with duplicate titles version <= 7.1.0", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = choiceSetUniquenessInactiveVersion; + }); + + context(@"if all cell properties are used", ^{ + beforeEach(^{ + testOp.windowCapability = enabledWindowCapability; + [testOp start]; + }); + + it(@"should update the choiceCells' unique title", ^{ + expect(testOp.cellsToUpload[0].uniqueText).to(equal("Cell2 (2)")); + expect(testOp.cellsToUpload.count).to(equal(1)); + expect(testOp.choiceSet.choices[0].uniqueText).to(equal(@"Cell2 (2)")); + }); + }); + }); + }); + + describe(@"running a non-searchable choice set operation", ^{ + beforeEach(^{ + testOp.keyboardDelegate = nil; + [testOp start]; + + // Move us past the preload + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:0 error:nil]; + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:1 error:nil]; + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:2 error:nil]; + [testConnectionManager respondToLastMultipleRequestsWithSuccess:YES]; + }); + + it(@"should not update global keyboard properties", ^{ + for (SDLRPCRequest *req in testConnectionManager.receivedRequests) { + expect(req).toNot(beAnInstanceOf([SDLSetGlobalProperties class])); + } + }); + + it(@"should send the perform interaction", ^{ + SDLPerformInteraction *request = testConnectionManager.receivedRequests.lastObject; + expect(request).to(beAnInstanceOf([SDLPerformInteraction class])); + + expect(request.initialText).to(equal(testChoiceSet.title)); + expect(request.initialPrompt).to(equal(testChoiceSet.initialPrompt)); + expect(request.interactionMode).to(equal(testInteractionMode)); + expect(request.interactionLayout).to(equal(SDLLayoutModeIconOnly)); + expect(request.timeoutPrompt).to(equal(testChoiceSet.timeoutPrompt)); + expect(request.helpPrompt).to(equal(testChoiceSet.helpPrompt)); + expect(request.timeout).to(equal(testChoiceSet.timeout * 1000)); + expect(request.vrHelp).to(beNil()); + expect(request.interactionChoiceSetIDList).to(equal(@[@(cellsWithoutArtwork[0].choiceId), @(cellsWithoutArtwork[1].choiceId), @(cellsWithoutArtwork[2].choiceId)])); + expect(request.cancelID).to(equal(testCancelID)); + }); + + describe(@"after a perform interaction response", ^{ + __block UInt16 responseChoiceId = UINT16_MAX; + __block SDLTriggerSource responseTriggerSource = SDLTriggerSourceMenu; + + beforeEach(^{ + SDLPerformInteractionResponse *response = [[SDLPerformInteractionResponse alloc] init]; + response.success = @YES; + response.choiceID = @(responseChoiceId); + response.triggerSource = responseTriggerSource; + + [testConnectionManager respondToLastRequestWithResponse:response]; + }); + + it(@"should not reset the keyboard properties and should be finished", ^{ + expect(testConnectionManager.receivedRequests.lastObject).toNot(beAnInstanceOf([SDLSetGlobalProperties class])); + expect(testOp.isFinished).to(beTrue()); + }); + }); + }); + + describe(@"running a searchable choice set operation", ^{ + beforeEach(^{ + [testOp start]; + + // Move us past the preload + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:0 error:nil]; + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:1 error:nil]; + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:2 error:nil]; + [testConnectionManager respondToLastMultipleRequestsWithSuccess:YES]; + }); + + it(@"should ask for custom properties", ^{ + OCMVerify([testKeyboardDelegate customKeyboardConfiguration]); + + expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); + }); + + describe(@"presenting the keyboard", ^{ + beforeEach(^{ + SDLSetGlobalPropertiesResponse *response = [[SDLSetGlobalPropertiesResponse alloc] init]; + response.success = @YES; + [testConnectionManager respondToLastRequestWithResponse:response]; + }); + + it(@"should send the perform interaction", ^{ + expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLPerformInteraction class])); + SDLPerformInteraction *request = testConnectionManager.receivedRequests.lastObject; + expect(request.initialText).to(equal(testChoiceSet.title)); + expect(request.initialPrompt).to(equal(testChoiceSet.initialPrompt)); + expect(request.interactionMode).to(equal(testInteractionMode)); + expect(request.interactionLayout).to(equal(SDLLayoutModeIconWithSearch)); + expect(request.timeoutPrompt).to(equal(testChoiceSet.timeoutPrompt)); + expect(request.helpPrompt).to(equal(testChoiceSet.helpPrompt)); + expect(request.timeout).to(equal(testChoiceSet.timeout * 1000)); + expect(request.vrHelp).to(beNil()); + expect(request.interactionChoiceSetIDList).to(equal(@[@(testChoiceSet.choices[0].choiceId), @(testChoiceSet.choices[1].choiceId), @(testChoiceSet.choices[2].choiceId)])); + expect(request.cancelID).to(equal(testCancelID)); + }); + + it(@"should respond to submitted notifications", ^{ + NSString *inputData = @"Test"; + SDLRPCNotificationNotification *notification = nil; + + // Submit notification + SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; + input.event = SDLKeyboardEventSubmitted; + input.data = inputData; + notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; + + [[NSNotificationCenter defaultCenter] postNotification:notification]; + + OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventSubmitted]; + }] text:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(NSString *)obj isEqualToString:inputData]; + }]]); + + OCMVerify([testKeyboardDelegate userDidSubmitInput:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(NSString *)obj isEqualToString:inputData]; + }] withEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventSubmitted]; + }]]); + }); + + it(@"should respond to voice request notifications", ^{ + SDLRPCNotificationNotification *notification = nil; + + // Submit notification + SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; + input.event = SDLKeyboardEventVoice; + notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; + + [[NSNotificationCenter defaultCenter] postNotification:notification]; + + OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventVoice]; + }] text:[OCMArg isNil]]); + + OCMVerify([testKeyboardDelegate userDidSubmitInput:[OCMArg isNil] withEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventVoice]; + }]]); + }); + + it(@"should respond to abort notifications", ^{ + SDLRPCNotificationNotification *notification = nil; + + // Submit notification + SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; + input.event = SDLKeyboardEventAborted; + notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; + + [[NSNotificationCenter defaultCenter] postNotification:notification]; + + OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventAborted]; + }] text:[OCMArg isNil]]); + + OCMVerify([testKeyboardDelegate keyboardDidAbortWithReason:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventAborted]; + }]]); + }); + + it(@"should respond to enabled keyboard event", ^{ + SDLRPCNotificationNotification *notification = nil; + + // Submit notification + SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; + input.event = SDLKeyboardEventInputKeyMaskEnabled; + notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; + + [[NSNotificationCenter defaultCenter] postNotification:notification]; + + OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled]; + }] text:[OCMArg isNil]]); + + OCMVerify([testKeyboardDelegate keyboardDidUpdateInputMask:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled]; + }]]); + }); + + it(@"should respond to cancellation notifications", ^{ + SDLRPCNotificationNotification *notification = nil; + + // Submit notification + SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; + input.event = SDLKeyboardEventCancelled; + notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; + + [[NSNotificationCenter defaultCenter] postNotification:notification]; + + OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventCancelled]; + }] text:[OCMArg isNil]]); + + OCMVerify([testKeyboardDelegate keyboardDidAbortWithReason:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventCancelled]; + }]]); + }); + + it(@"should respond to text input notification with autocomplete", ^{ + NSString *inputData = @"Test"; + SDLRPCNotificationNotification *notification = nil; + + OCMStub([testKeyboardDelegate updateAutocompleteWithInput:[OCMArg any] autoCompleteResultsHandler:([OCMArg invokeBlockWithArgs:@[inputData], nil])]); + + // Submit notification + SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; + input.event = SDLKeyboardEventKeypress; + input.data = inputData; + notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; + + [[NSNotificationCenter defaultCenter] postNotification:notification]; + + OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventKeypress]; + }] text:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(NSString *)obj isEqualToString:inputData]; + }]]); + + OCMVerify([testKeyboardDelegate updateAutocompleteWithInput:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(NSString *)obj isEqualToString:inputData]; + }] autoCompleteResultsHandler:[OCMArg any]]); + + expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); + + SDLSetGlobalProperties *setProperties = testConnectionManager.receivedRequests.lastObject; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + expect(setProperties.keyboardProperties.autoCompleteText).to(equal(inputData)); +#pragma clang diagnostic pop + }); + + it(@"should respond to text input notification with character set", ^{ + NSString *inputData = @"Test"; + SDLRPCNotificationNotification *notification = nil; + + OCMStub([testKeyboardDelegate updateCharacterSetWithInput:[OCMArg any] completionHandler:([OCMArg invokeBlockWithArgs:@[inputData], nil])]); + + // Submit notification + SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; + input.event = SDLKeyboardEventKeypress; + input.data = inputData; + notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; + + [[NSNotificationCenter defaultCenter] postNotification:notification]; + + OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventKeypress]; + }] text:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(NSString *)obj isEqualToString:inputData]; + }]]); + + OCMVerify([testKeyboardDelegate updateCharacterSetWithInput:[OCMArg checkWithBlock:^BOOL(id obj) { + return [(NSString *)obj isEqualToString:inputData]; + }] completionHandler:[OCMArg any]]); + + expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); + + SDLSetGlobalProperties *setProperties = testConnectionManager.receivedRequests.lastObject; + expect(setProperties.keyboardProperties.limitedCharacterList).to(equal(@[inputData])); + }); + + describe(@"after a perform interaction response", ^{ + beforeEach(^{ + SDLPerformInteractionResponse *response = [[SDLPerformInteractionResponse alloc] init]; + response.success = @YES; + response.choiceID = @65535; + response.triggerSource = SDLTriggerSourceVoiceRecognition; + + [testConnectionManager respondToLastRequestWithResponse:response]; + }); + + it(@"should reset the keyboard properties", ^{ + expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); + }); + + describe(@"after the reset response", ^{ + __block SDLSetGlobalPropertiesResponse *response = [[SDLSetGlobalPropertiesResponse alloc] init]; + beforeEach(^{ + response.success = @YES; + }); + + it(@"should be finished", ^{ + OCMExpect([testChoiceDelegate choiceSet:[OCMArg isEqual:testChoiceSet] didSelectChoice:[OCMArg isNotNil] withSource:[OCMArg isEqual:SDLTriggerSourceVoiceRecognition] atRowIndex:0]); + OCMReject([testChoiceDelegate choiceSet:[OCMArg any] didReceiveError:[OCMArg any]]); + + [testConnectionManager respondToLastRequestWithResponse:response]; + + expect(testOp.isFinished).to(beTrue()); + }); + }); + }); + }); + }); + + describe(@"canceling the choice set", ^{ + context(@"if the head unit supports the `CancelInteraction` RPC", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithMajor:6 minor:0 patch:0]; + }); + + context(@"if the operation is executing", ^{ + beforeEach(^{ + [testOp start]; + }); + + context(@"before the present is sent", ^{ + it(@"should cancel without a CancelInteraction", ^{ + expect(testOp.isExecuting).to(beTrue()); + expect(testOp.isFinished).to(beFalse()); + expect(testOp.isCancelled).to(beFalse()); + + [testChoiceSet cancel]; + + expect(testConnectionManager.receivedRequests.lastObject).toNot(beAnInstanceOf([SDLCancelInteraction class])); + + expect(testOp.isExecuting).to(beTrue()); + expect(testOp.isFinished).to(beFalse()); + expect(testOp.isCancelled).to(beTrue()); + }); + }); + + context(@"if the present is in progress", ^{ + beforeEach(^{ + // Move us past the preload + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:0 error:nil]; + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:1 error:nil]; + [testConnectionManager respondToRequestWithResponse:testGoodResponse requestNumber:2 error:nil]; + [testConnectionManager respondToLastMultipleRequestsWithSuccess:YES]; + + // Move us past the SetGlobalProperties + SDLSetGlobalPropertiesResponse *sgpr = [[SDLSetGlobalPropertiesResponse alloc] init]; + sgpr.success = @YES; + sgpr.resultCode = SDLResultSuccess; + [testConnectionManager respondToLastRequestWithResponse:sgpr]; + }); + + it(@"should attempt to send a cancel interaction", ^{ + expect(testOp.isExecuting).to(beTrue()); + expect(testOp.isFinished).to(beFalse()); + expect(testOp.isCancelled).to(beFalse()); + + [testChoiceSet cancel]; + + SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; + expect(lastRequest).to(beAnInstanceOf([SDLCancelInteraction class])); + expect(lastRequest.cancelID).to(equal(testCancelID)); + expect(lastRequest.functionID).to(equal([SDLFunctionID.sharedInstance functionIdForName:SDLRPCFunctionNamePerformInteraction])); + }); + + context(@"If the cancel interaction was successful", ^{ + __block SDLCancelInteractionResponse *testCancelInteractionResponse = [[SDLCancelInteractionResponse alloc] init]; + beforeEach(^{ + testCancelInteractionResponse.success = @YES; + testCancelInteractionResponse.resultCode = SDLResultSuccess; + [testChoiceSet cancel]; + }); + + it(@"should finish with an error", ^{ + // Respond to the cancel interaction, then the perform interaction + [testConnectionManager respondToLastRequestWithResponse:testCancelInteractionResponse]; + + SDLPerformInteractionResponse *pir = [[SDLPerformInteractionResponse alloc] init]; + pir.success = @NO; + pir.resultCode = SDLResultAborted; + [testConnectionManager respondToRequestWithResponse:pir requestNumber:4 error:[NSError sdl_choiceSetManager_cancelled]]; + + // Try to reset the keyboard + expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); + + SDLSetGlobalPropertiesResponse *sgpr = [[SDLSetGlobalPropertiesResponse alloc] init]; + sgpr.success = @YES; + sgpr.resultCode = SDLResultSuccess; + [testConnectionManager respondToLastRequestWithResponse:sgpr]; + + OCMReject([testChoiceDelegate choiceSet:[OCMArg isNotNil] didSelectChoice:[OCMArg isNotNil] withSource:[OCMArg any] atRowIndex:0]); + OCMVerify([testChoiceDelegate choiceSet:[OCMArg isEqual:testChoiceSet] didReceiveError:[OCMArg isNotNil]]); + }); + }); + + context(@"If the cancel interaction was not successful", ^{ + __block NSError *testError = [NSError sdl_lifecycle_notConnectedError]; + __block SDLCancelInteractionResponse *testCancelInteractionResponse = [[SDLCancelInteractionResponse alloc] init]; + + beforeEach(^{ + testCancelInteractionResponse.success = @NO; + }); + + it(@"should error", ^{ + OCMExpect([testChoiceDelegate choiceSet:[OCMArg any] didReceiveError:[OCMArg any]]); + OCMReject([testChoiceDelegate choiceSet:[OCMArg isEqual:testChoiceSet] didSelectChoice:[OCMArg isNotNil] withSource:[OCMArg isEqual:SDLTriggerSourceVoiceRecognition] atRowIndex:0]); + [testConnectionManager respondToLastRequestWithResponse:testCancelInteractionResponse error:testError]; + }); + }); + }); + }); + + context(@"if the operation has already finished", ^{ + it(@"should not attempt to send a cancel interaction", ^{ + [testOp finishOperation]; + + expect(testOp.isExecuting).to(beFalse()); + expect(testOp.isFinished).to(beTrue()); + expect(testOp.isCancelled).to(beFalse()); + + [testChoiceSet cancel]; + + SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; + expect(lastRequest).to(beNil()); + }); + }); + + context(@"if the operation has not started", ^{ + beforeEach(^{ + expect(testOp.isExecuting).to(beFalse()); + expect(testOp.isFinished).to(beFalse()); + expect(testOp.isCancelled).to(beFalse()); + + [testChoiceSet cancel]; + }); + + it(@"should not attempt to send a cancel interaction", ^{ + expect(testOp.isExecuting).to(beFalse()); + expect(testOp.isFinished).to(beFalse()); + expect(testOp.isCancelled).to(beTrue()); + + SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; + expect(lastRequest).to(beNil()); + }); + + context(@"once the operation has started", ^{ + beforeEach(^{ + [testOp start]; + }); + + it(@"immediately finish", ^{ + expect(testConnectionManager.receivedRequests).to(haveCount(0)); + expect(testOp.isExecuting).to(beFalse()); + expect(testOp.isFinished).to(beTrue()); + expect(testOp.isCancelled).to(beTrue()); + }); + + it(@"should finish", ^{ + expect(testOp.isExecuting).toEventually(beFalse()); + expect(testOp.isFinished).toEventually(beTrue()); + expect(testOp.isCancelled).toEventually(beTrue()); + }); + }); + }); + }); + + context(@"Head unit does not support the `CancelInteraction` RPC", ^{ + beforeEach(^{ + SDLVersion *unsupportedVersion = [SDLVersion versionWithMajor:5 minor:1 patch:0]; + id globalMock = OCMPartialMock([SDLGlobals sharedGlobals]); + OCMStub([globalMock rpcVersion]).andReturn(unsupportedVersion); + }); + + it(@"should not attempt to send a cancel interaction if the operation is executing", ^{ + [testOp start]; + + expect(testOp.isExecuting).to(beTrue()); + expect(testOp.isFinished).to(beFalse()); + expect(testOp.isCancelled).to(beFalse()); + + [testChoiceSet cancel]; + + SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; + expect(lastRequest).toNot(beAnInstanceOf([SDLCancelInteraction class])); + }); + + it(@"should cancel the operation if it has not yet been run", ^{ + expect(testOp.isExecuting).to(beFalse()); + expect(testOp.isFinished).to(beFalse()); + expect(testOp.isCancelled).to(beFalse()); + + [testChoiceSet cancel]; + + SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; + expect(lastRequest).to(beNil()); + + expect(testOp.isExecuting).to(beFalse()); + expect(testOp.isFinished).to(beFalse()); + expect(testOp.isCancelled).to(beTrue()); + }); + }); + }); + }); +}); + +QuickSpecEnd diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadPresentChoicesOperationUtilitiesSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadPresentChoicesOperationUtilitiesSpec.m new file mode 100644 index 000000000..b09d7a3e2 --- /dev/null +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadPresentChoicesOperationUtilitiesSpec.m @@ -0,0 +1,504 @@ +// +// SDLPreloadPresentChoiceSetOperationUtilitiesSpec.m +// SmartDeviceLinkTests +// +// Created by Joel Fischer on 8/27/21. +// Copyright © 2021 smartdevicelink. All rights reserved. +// + +#import <Quick/Quick.h> +#import <Nimble/Nimble.h> +#import <OCMock/OCMock.h> + +#import "SDLPreloadPresentChoicesOperationUtilities.h" + +#import "SDLChoiceCell.h" +#import "SDLChoiceSet.h" +#import "SDLGlobals.h" +#import "SDLImageField+ScreenManagerExtensions.h" +#import "SDLTextField+ScreenManagerExtensions.h" +#import "SDLVersion.h" +#import "SDLWindowCapability+ScreenManagerExtensions.h" + +@interface SDLChoiceCell() + +@property (assign, nonatomic) UInt16 choiceId; + +@end + +@interface SDLPreloadPresentChoicesOperationUtilitiesSpec : QuickSpec @end +@implementation SDLPreloadPresentChoicesOperationUtilitiesSpec + +- (NSOrderedSet<SDLChoiceCell *> *)sdl_cellsToLoadWithCount:(UInt16)count { + NSMutableOrderedSet<SDLChoiceCell *> *mutableCells = [NSMutableOrderedSet orderedSetWithCapacity:count]; + for (NSUInteger i = 1; i <= count; i++) { + [mutableCells addObject:[[SDLChoiceCell alloc] initWithText:[NSString stringWithFormat:@"Cell %lu", i]]]; + } + + return mutableCells.copy; +} + +- (NSSet<SDLChoiceCell *> *)sdl_loadedCellsWithStartNum:(UInt16)startNum endNum:(UInt16)endNum { + NSMutableSet<SDLChoiceCell *> *mutableCells = [NSMutableSet setWithCapacity:(endNum - startNum)]; + for (NSUInteger i = startNum; i <= endNum; i++) { + SDLChoiceCell *cell = [[SDLChoiceCell alloc] initWithText:[NSString stringWithFormat:@"Loaded Cell %lu", i]]; + cell.choiceId = (UInt16)i; + + [mutableCells addObject:cell]; + } + + return mutableCells.copy; +} + +- (void)spec { + __block NSOrderedSet<SDLChoiceCell *> *testCellsToLoad = nil; + __block NSSet<SDLChoiceCell *> *testLoadedCells = nil; + + describe(@"assigning ids", ^{ + context(@"when we're on the first loop of assigning ids", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.reachedMaxId = NO; + SDLPreloadPresentChoicesOperationUtilities.choiceId = 1; + }); + + context(@"when there's no ids already set", ^{ + beforeEach(^{ + testLoadedCells = [NSSet set]; + testCellsToLoad = [self sdl_cellsToLoadWithCount:50]; + }); + + it(@"should set ids starting at 0", ^{ + [SDLPreloadPresentChoicesOperationUtilities assignIdsToCells:testCellsToLoad loadedCells:testLoadedCells]; + expect(testCellsToLoad.count).to(equal(50)); + for (NSUInteger i = 0; i < testCellsToLoad.count; i++) { + expect((NSUInteger)testCellsToLoad[i].choiceId).to(equal(i + 1)); + } + }); + }); + + context(@"when ids are already set", ^{ + context(@"when not reaching the max value", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.choiceId = 100; + + testLoadedCells = [NSSet set]; + testCellsToLoad = [self sdl_cellsToLoadWithCount:50]; + }); + + it(@"should set ids starting at the next id", ^{ + [SDLPreloadPresentChoicesOperationUtilities assignIdsToCells:testCellsToLoad loadedCells:testLoadedCells]; + expect(testCellsToLoad.count).to(equal(50)); + for (NSUInteger i = 0; i < testCellsToLoad.count; i++) { + expect((NSUInteger)testCellsToLoad[i].choiceId).to(equal(i + 100)); + } + expect(SDLPreloadPresentChoicesOperationUtilities.reachedMaxId).to(beFalse()); + }); + }); + + context(@"when reaching the max value", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.choiceId = 65500; + + testLoadedCells = [self sdl_loadedCellsWithStartNum:0 endNum:65499]; + testCellsToLoad = [self sdl_cellsToLoadWithCount:35]; + }); + + it(@"should set the reachedMaxId BOOL and not loop back over yet", ^{ + [SDLPreloadPresentChoicesOperationUtilities assignIdsToCells:testCellsToLoad loadedCells:testLoadedCells]; + expect(testCellsToLoad.count).to(equal(35)); + for (NSUInteger i = 0; i < testCellsToLoad.count; i++) { + expect((NSUInteger)testCellsToLoad[i].choiceId).to(equal(i + 65500)); + } + expect(SDLPreloadPresentChoicesOperationUtilities.reachedMaxId).to(beFalse()); + }); + }); + }); + }); + + context(@"on subsequent loops of assigning ids", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.reachedMaxId = YES; + SDLPreloadPresentChoicesOperationUtilities.choiceId = 1; + }); + + context(@"when loadedCells is not full", ^{ + context(@"when loaded cells are contiguous at the beginning", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.choiceId = 99; + + testLoadedCells = [self sdl_loadedCellsWithStartNum:0 endNum:99]; + testCellsToLoad = [self sdl_cellsToLoadWithCount:35]; + }); + + it(@"should assign ids after those", ^{ + [SDLPreloadPresentChoicesOperationUtilities assignIdsToCells:testCellsToLoad loadedCells:testLoadedCells]; + expect(testCellsToLoad.count).to(equal(35)); + for (NSUInteger i = 0; i < testCellsToLoad.count; i++) { + expect((NSUInteger)testCellsToLoad[i].choiceId).to(equal(i + 100)); + } + expect(SDLPreloadPresentChoicesOperationUtilities.reachedMaxId).to(beTrue()); + }); + }); + + context(@"when those items are contiguous in the middle so that assigning cells overlap", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.choiceId = 10; + + testLoadedCells = [self sdl_loadedCellsWithStartNum:3 endNum:10]; + testCellsToLoad = [self sdl_cellsToLoadWithCount:13]; + }); + + it(@"should start assigning from the last used id", ^{ + [SDLPreloadPresentChoicesOperationUtilities assignIdsToCells:testCellsToLoad loadedCells:testLoadedCells]; + expect(testCellsToLoad.count).to(equal(13)); + for (NSUInteger i = 0; i < testCellsToLoad.count; i++) { + expect((NSUInteger)testCellsToLoad[i].choiceId).to(equal(i + 11)); + } + expect(SDLPreloadPresentChoicesOperationUtilities.reachedMaxId).to(beTrue()); + }); + }); + + context(@"when there are items scattered and overlapping setting cells", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.choiceId = 10; + + testLoadedCells = [self sdl_loadedCellsWithStartNum:3 endNum:10]; + NSSet<SDLChoiceCell *> *secondLoadedCells = [self sdl_loadedCellsWithStartNum:50 endNum:55]; + testLoadedCells = [testLoadedCells setByAddingObjectsFromSet:secondLoadedCells]; + + testCellsToLoad = [self sdl_cellsToLoadWithCount:10]; + }); + + it(@"start from the last used id", ^{ + [SDLPreloadPresentChoicesOperationUtilities assignIdsToCells:testCellsToLoad loadedCells:testLoadedCells]; + expect(testCellsToLoad.count).to(equal(10)); + for (NSUInteger i = 0; i < testCellsToLoad.count; i++) { + expect((NSUInteger)testCellsToLoad[i].choiceId).to(equal(i + 56)); + } + expect(SDLPreloadPresentChoicesOperationUtilities.reachedMaxId).to(beTrue()); + }); + }); + + context(@"when not enough open ids are available", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.choiceId = 10; + + testLoadedCells = [self sdl_loadedCellsWithStartNum:3 endNum:10]; + NSSet<SDLChoiceCell *> *secondLoadedCells = [self sdl_loadedCellsWithStartNum:12 endNum:65533]; + testLoadedCells = [testLoadedCells setByAddingObjectsFromSet:secondLoadedCells]; + + testCellsToLoad = [self sdl_cellsToLoadWithCount:10]; + }); + it(@"should assign what it can and the rest should be UINT16_MAX", ^{ + [SDLPreloadPresentChoicesOperationUtilities assignIdsToCells:testCellsToLoad loadedCells:testLoadedCells]; + expect(testCellsToLoad.count).to(equal(10)); + + expect((NSUInteger)testCellsToLoad[0].choiceId).to(equal(65534)); + expect((NSUInteger)testCellsToLoad[1].choiceId).to(equal(65535)); + expect((NSUInteger)testCellsToLoad[2].choiceId).to(equal(0)); + expect((NSUInteger)testCellsToLoad[3].choiceId).to(equal(1)); + expect((NSUInteger)testCellsToLoad[4].choiceId).to(equal(2)); + expect((NSUInteger)testCellsToLoad[5].choiceId).to(equal(11)); + expect((NSUInteger)testCellsToLoad[6].choiceId).to(equal(65535)); + expect((NSUInteger)testCellsToLoad[7].choiceId).to(equal(65535)); + expect((NSUInteger)testCellsToLoad[8].choiceId).to(equal(65535)); + expect((NSUInteger)testCellsToLoad[9].choiceId).to(equal(65535)); + + expect(SDLPreloadPresentChoicesOperationUtilities.reachedMaxId).to(beTrue()); + }); + }); + }); + + context(@"when loadedCells is full", ^{ + beforeEach(^{ + SDLPreloadPresentChoicesOperationUtilities.choiceId = 65535; + + testLoadedCells = [self sdl_loadedCellsWithStartNum:0 endNum:65535]; + testCellsToLoad = [self sdl_cellsToLoadWithCount:10]; + }); + + it(@"should set all ids to UINT16_MAX", ^{ + [SDLPreloadPresentChoicesOperationUtilities assignIdsToCells:testCellsToLoad loadedCells:testLoadedCells]; + expect(testCellsToLoad.count).to(equal(10)); + for (NSUInteger i = 0; i < testCellsToLoad.count; i++) { + expect((NSUInteger)testCellsToLoad[i].choiceId).to(equal(65535)); + } + expect(SDLPreloadPresentChoicesOperationUtilities.reachedMaxId).to(beTrue()); + }); + }); + }); + }); + + describe(@"making cells unique", ^{ + __block SDLWindowCapability *enabledWindowCapability = nil; + __block SDLWindowCapability *primaryTextOnlyCapability = nil; + + beforeEach(^{ + enabledWindowCapability = [[SDLWindowCapability alloc] init]; + enabledWindowCapability.textFields = @[ + [[SDLTextField alloc] initWithName:SDLTextFieldNameMenuName characterSet:SDLCharacterSetUtf8 width:500 rows:1], + [[SDLTextField alloc] initWithName:SDLTextFieldNameSecondaryText characterSet:SDLCharacterSetUtf8 width:500 rows:1], + [[SDLTextField alloc] initWithName:SDLTextFieldNameTertiaryText characterSet:SDLCharacterSetUtf8 width:500 rows:1] + ]; + enabledWindowCapability.imageFields = @[ + [[SDLImageField alloc] initWithName:SDLImageFieldNameChoiceImage imageTypeSupported:@[SDLFileTypePNG] imageResolution:nil], + [[SDLImageField alloc] initWithName:SDLImageFieldNameChoiceSecondaryImage imageTypeSupported:@[SDLFileTypePNG] imageResolution:nil] + ]; + primaryTextOnlyCapability = [[SDLWindowCapability alloc] init]; + primaryTextOnlyCapability.textFields = @[ + [[SDLTextField alloc] initWithName:SDLTextFieldNameMenuName characterSet:SDLCharacterSetUtf8 width:500 rows:1], + ]; + + testLoadedCells = [NSSet set]; + }); + + context(@"at RPC v7.1", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithMajor:7 minor:1 patch:0]; + }); + + context(@"when cells are unique except when stripped", ^{ + beforeEach(^{ + testCellsToLoad = [NSOrderedSet orderedSetWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique 1" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique 2" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique 3" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 1" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil] + ]]; + }); + + context(@"with full window capability", ^{ + beforeEach(^{ + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:enabledWindowCapability]; + }); + + it(@"should not set unique titles", ^{ + expect(testCellsToLoad[0].uniqueText).to(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).to(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).to(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + + context(@"with primary text only capability", ^{ + beforeEach(^{ + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:primaryTextOnlyCapability]; + }); + + it(@"should set unique titles", ^{ + expect(testCellsToLoad[0].uniqueText).to(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).toNot(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).toNot(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + }); + + context(@"when cells are unique", ^{ + beforeEach(^{ + testCellsToLoad = [NSOrderedSet orderedSetWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 3" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 4" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil] + ]]; + + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:enabledWindowCapability]; + }); + + it(@"should not set unique titles", ^{ + expect(testCellsToLoad[0].uniqueText).to(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).to(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).to(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + + context(@"when loaded cells match the cells when stripped", ^{ + beforeEach(^{ + testLoadedCells = [NSSet setWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1"], + [[SDLChoiceCell alloc] initWithText:@"Cell 2"], + [[SDLChoiceCell alloc] initWithText:@"Cell 3"], + ]]; + + testCellsToLoad = [NSOrderedSet orderedSetWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique 2" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 4" secondaryText:@"Unique" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil] + ]]; + }); + + context(@"with full window capability", ^{ + beforeEach(^{ + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:enabledWindowCapability]; + }); + + it(@"should not make unique text", ^{ + expect(testCellsToLoad[0].uniqueText).to(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).to(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).to(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + + context(@"with primary text only capability", ^{ + beforeEach(^{ + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:primaryTextOnlyCapability]; + }); + + it(@"should not make unique text", ^{ + expect(testCellsToLoad[0].uniqueText).toNot(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).toNot(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).toNot(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + }); + }); + + context(@"below RPC v7.1", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithMajor:7 minor:0 patch:0]; + }); + + context(@"when cells are unique except when stripped", ^{ + beforeEach(^{ + testCellsToLoad = [NSOrderedSet orderedSetWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique 1" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique 2" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique 3" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique 1" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil] + ]]; + + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:enabledWindowCapability]; + }); + + it(@"should set unique titles except the first and last", ^{ + expect(testCellsToLoad[0].uniqueText).to(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).toNot(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).toNot(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + + context(@"when cells are unique", ^{ + beforeEach(^{ + testCellsToLoad = [NSOrderedSet orderedSetWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 3" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 4" secondaryText:nil tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil] + ]]; + + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:enabledWindowCapability]; + }); + + it(@"should not set unique titles", ^{ + expect(testCellsToLoad[0].uniqueText).to(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).to(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).to(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + + context(@"when loaded cells match the cells when stripped", ^{ + beforeEach(^{ + testLoadedCells = [NSSet setWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1"], + [[SDLChoiceCell alloc] initWithText:@"Cell 2"], + [[SDLChoiceCell alloc] initWithText:@"Cell 3"], + ]]; + + testCellsToLoad = [NSOrderedSet orderedSetWithArray:@[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 2" secondaryText:@"Unique" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 1" secondaryText:@"Unique 2" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil], + [[SDLChoiceCell alloc] initWithText:@"Cell 4" secondaryText:@"Unique" tertiaryText:nil voiceCommands:nil artwork:nil secondaryArtwork:nil] + ]]; + }); + + context(@"with full window capability", ^{ + beforeEach(^{ + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:enabledWindowCapability]; + }); + + it(@"should make unique text", ^{ + expect(testCellsToLoad[0].uniqueText).toNot(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).toNot(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).toNot(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + + context(@"with primary text only capability", ^{ + beforeEach(^{ + [SDLPreloadPresentChoicesOperationUtilities makeCellsToUploadUnique:testCellsToLoad.mutableCopy basedOnLoadedCells:testLoadedCells.mutableCopy windowCapability:primaryTextOnlyCapability]; + }); + + it(@"should not make unique text", ^{ + expect(testCellsToLoad[0].uniqueText).toNot(equal(testCellsToLoad[0].text)); + expect(testCellsToLoad[1].uniqueText).toNot(equal(testCellsToLoad[1].text)); + expect(testCellsToLoad[2].uniqueText).toNot(equal(testCellsToLoad[2].text)); + expect(testCellsToLoad[3].uniqueText).to(equal(testCellsToLoad[3].text)); + }); + }); + }); + }); + }); + + describe(@"updating a choice set based on loaded cells and cells to upload", ^{ + __block SDLChoiceSet *testChoiceSet = nil; + __block NSArray<SDLChoiceCell *> *basicChoiceCells = nil; + __block NSMutableArray<SDLChoiceCell *> *testLoadedCellsArray = nil; + + beforeEach(^{ + basicChoiceCells = @[ + [[SDLChoiceCell alloc] initWithText:@"Cell 1"], + [[SDLChoiceCell alloc] initWithText:@"Cell 2"], + [[SDLChoiceCell alloc] initWithText:@"Cell 3"], + ]; + + // Has all three cells with no ids + testChoiceSet = [[SDLChoiceSet alloc] init]; + testChoiceSet.choices = basicChoiceCells; + + // Has all three cells with different ids + testCellsToLoad = [NSOrderedSet orderedSetWithArray:basicChoiceCells range:NSMakeRange(0, 3) copyItems:YES]; + for (NSUInteger i = 0; i < testCellsToLoad.count; i++) { + testCellsToLoad[i].choiceId = i; + } + + // Loaded cells has first two items with different ids + testLoadedCellsArray = [[NSMutableArray alloc] initWithArray:basicChoiceCells copyItems:YES]; + [testLoadedCellsArray removeLastObject]; + for (NSUInteger i = 0; i < testLoadedCellsArray.count; i++) { + testLoadedCellsArray[i].choiceId = i + 10; + } + testLoadedCells = [NSSet setWithArray:testLoadedCellsArray]; + }); + + context(@"when there are no loaded cells", ^{ + it(@"should have all cells the same as cells to upload", ^{ + [SDLPreloadPresentChoicesOperationUtilities updateChoiceSet:testChoiceSet withLoadedCells:[NSSet set] cellsToUpload:testCellsToLoad.set]; + + for (NSUInteger i = 0; i < testChoiceSet.choices.count; i++) { + expect((NSUInteger)testChoiceSet.choices[i].choiceId).to(equal(testCellsToLoad[i].choiceId)); + } + }); + }); + + context(@"when some loaded cells match", ^{ + it(@"should use the loaded cells when possible", ^{ + [SDLPreloadPresentChoicesOperationUtilities updateChoiceSet:testChoiceSet withLoadedCells:testLoadedCells cellsToUpload:testCellsToLoad.set]; + + expect((NSUInteger)testChoiceSet.choices[0].choiceId).to(equal(testLoadedCellsArray[0].choiceId)); + expect((NSUInteger)testChoiceSet.choices[1].choiceId).to(equal(testLoadedCellsArray[1].choiceId)); + expect((NSUInteger)testChoiceSet.choices[2].choiceId).to(equal(testCellsToLoad[2].choiceId)); + }); + }); + }); +} + +@end diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m deleted file mode 100644 index f918c6909..000000000 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m +++ /dev/null @@ -1,549 +0,0 @@ -#import <Quick/Quick.h> -#import <Nimble/Nimble.h> -#import <OCMock/OCMock.h> - -#import "SDLPresentChoiceSetOperation.h" - -#import "SDLCancelInteraction.h" -#import "SDLCancelInteractionResponse.h" -#import "SDLChoiceCell.h" -#import "SDLChoiceSet.h" -#import "SDLChoiceSetDelegate.h" -#import "SDLError.h" -#import "SDLFunctionID.h" -#import "SDLKeyboardDelegate.h" -#import "SDLOnKeyboardInput.h" -#import "SDLKeyboardProperties.h" -#import "SDLPerformInteraction.h" -#import "SDLPerformInteractionResponse.h" -#import "SDLRPCNotificationNotification.h" -#import "SDLGlobals.h" -#import "SDLSetGlobalProperties.h" -#import "SDLSetGlobalPropertiesResponse.h" -#import "SDLVersion.h" -#import "TestConnectionManager.h" - -@interface SDLChoiceSet() - -@property (nullable, copy, nonatomic) SDLChoiceSetCanceledHandler canceledHandler; - -@end - -QuickSpecBegin(SDLPresentChoiceSetOperationSpec) - -describe(@"present choice operation", ^{ - __block TestConnectionManager *testConnectionManager = nil; - __block SDLPresentChoiceSetOperation *testOp = nil; - - __block SDLInteractionMode testInteractionMode = SDLInteractionModeBoth; - __block SDLChoiceSet *testChoiceSet = nil; - __block id<SDLChoiceSetDelegate> testChoiceDelegate = nil; - __block NSArray<SDLChoiceCell *> *testChoices = nil; - __block int testCancelID = 98; - - __block id<SDLKeyboardDelegate> testKeyboardDelegate = nil; - __block SDLKeyboardProperties *testKeyboardProperties = nil; - - __block BOOL hasCalledOperationCompletionHandler = NO; - __block NSError *resultError = nil; - __block SDLWindowCapability *windowCapability = nil; - - beforeEach(^{ - resultError = nil; - hasCalledOperationCompletionHandler = NO; - - testConnectionManager = [[TestConnectionManager alloc] init]; - - testChoiceDelegate = OCMProtocolMock(@protocol(SDLChoiceSetDelegate)); - SDLChoiceCell *cell1 = [[SDLChoiceCell alloc] initWithText:@"Cell 1"]; - testChoices = @[cell1]; - testChoiceSet = [[SDLChoiceSet alloc] initWithTitle:@"Test Title" delegate:testChoiceDelegate layout:SDLChoiceSetLayoutTiles timeout:13 initialPromptString:@"Test initial prompt" timeoutPromptString:@"Test timeout prompt" helpPromptString:@"Test help prompt" vrHelpList:nil choices:testChoices]; - - windowCapability = [[SDLWindowCapability alloc] init]; - testKeyboardDelegate = OCMProtocolMock(@protocol(SDLKeyboardDelegate)); - OCMStub([testKeyboardDelegate customKeyboardConfiguration]).andReturn(nil); - testKeyboardProperties = [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageArSa keyboardLayout:SDLKeyboardLayoutAZERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil maskInputCharacters:nil customKeys:nil]; - }); - - it(@"should have a priority of 'normal'", ^{ - testOp = [[SDLPresentChoiceSetOperation alloc] init]; - - expect(@(testOp.queuePriority)).to(equal(@(NSOperationQueuePriorityNormal))); - }); - - describe(@"running a non-searchable choice set operation", ^{ - beforeEach(^{ - testOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:nil keyboardDelegate:nil cancelID:testCancelID windowCapability:windowCapability]; - testOp.completionBlock = ^{ - hasCalledOperationCompletionHandler = YES; - }; - [testOp start]; - }); - - it(@"should not update global keyboard properties", ^{ - expect(testConnectionManager.receivedRequests.lastObject).toNot(beAnInstanceOf([SDLSetGlobalProperties class])); - }); - - describe(@"presenting the choice set", ^{ - it(@"should send the perform interaction", ^{ - expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLPerformInteraction class])); - SDLPerformInteraction *request = testConnectionManager.receivedRequests.lastObject; - expect(request.initialText).to(equal(testChoiceSet.title)); - expect(request.initialPrompt).to(equal(testChoiceSet.initialPrompt)); - expect(request.interactionMode).to(equal(testInteractionMode)); - expect(request.interactionLayout).to(equal(SDLLayoutModeIconOnly)); - expect(request.timeoutPrompt).to(equal(testChoiceSet.timeoutPrompt)); - expect(request.helpPrompt).to(equal(testChoiceSet.helpPrompt)); - expect(request.timeout).to(equal(testChoiceSet.timeout * 1000)); - expect(request.vrHelp).to(beNil()); - expect(request.interactionChoiceSetIDList).to(equal(@[@65535])); - expect(request.cancelID).to(equal(testCancelID)); - }); - - describe(@"after a perform interaction response", ^{ - __block UInt16 responseChoiceId = UINT16_MAX; - __block SDLTriggerSource responseTriggerSource = SDLTriggerSourceMenu; - - beforeEach(^{ - SDLPerformInteractionResponse *response = [[SDLPerformInteractionResponse alloc] init]; - response.success = @YES; - response.choiceID = @(responseChoiceId); - response.triggerSource = responseTriggerSource; - - [testConnectionManager respondToLastRequestWithResponse:response]; - }); - - it(@"should not reset the keyboard properties and should be finished", ^{ - expect(testConnectionManager.receivedRequests.lastObject).toNot(beAnInstanceOf([SDLSetGlobalProperties class])); - expect(hasCalledOperationCompletionHandler).toEventually(beTrue()); - expect(testOp.isFinished).to(beTrue()); - expect(testOp.selectedCell).to(equal(testChoices.firstObject)); - expect(testOp.selectedTriggerSource).to(equal(responseTriggerSource)); - }); - }); - }); - - describe(@"Canceling the choice set", ^{ - __block SDLPresentChoiceSetOperation *testCancelOp = nil; - - beforeEach(^{ - testCancelOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:nil keyboardDelegate:nil cancelID:testCancelID windowCapability:windowCapability]; - testCancelOp.completionBlock = ^{ - hasCalledOperationCompletionHandler = YES; - }; - }); - - context(@"Head unit supports the `CancelInteration` RPC", ^{ - beforeEach(^{ - SDLVersion *supportedVersion = [SDLVersion versionWithMajor:6 minor:0 patch:0]; - id globalMock = OCMPartialMock([SDLGlobals sharedGlobals]); - OCMStub([globalMock rpcVersion]).andReturn(supportedVersion); - }); - - context(@"If the operation is executing", ^{ - beforeEach(^{ - [testCancelOp start]; - - expect(testCancelOp.isExecuting).to(beTrue()); - expect(testCancelOp.isFinished).to(beFalse()); - expect(testCancelOp.isCancelled).to(beFalse()); - - [testChoiceSet cancel]; - }); - - it(@"should attempt to send a cancel interaction", ^{ - SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; - expect(lastRequest).to(beAnInstanceOf([SDLCancelInteraction class])); - expect(lastRequest.cancelID).to(equal(testCancelID)); - expect(lastRequest.functionID).to(equal([SDLFunctionID.sharedInstance functionIdForName:SDLRPCFunctionNamePerformInteraction])); - }); - - context(@"If the cancel interaction was successful", ^{ - beforeEach(^{ - SDLCancelInteractionResponse *testCancelInteractionResponse = [[SDLCancelInteractionResponse alloc] init]; - testCancelInteractionResponse.success = @YES; - [testConnectionManager respondToLastRequestWithResponse:testCancelInteractionResponse]; - }); - - it(@"should not error", ^{ - expect(testCancelOp.error).to(beNil()); - }); - - it(@"should not finish", ^{ - expect(hasCalledOperationCompletionHandler).to(beFalse()); - expect(testCancelOp.isExecuting).to(beTrue()); - expect(testCancelOp.isFinished).to(beFalse()); - expect(testCancelOp.isCancelled).to(beFalse()); - }); - }); - - context(@"If the cancel interaction was not successful", ^{ - __block NSError *testError = [NSError sdl_lifecycle_notConnectedError]; - - beforeEach(^{ - SDLCancelInteractionResponse *testCancelInteractionResponse = [[SDLCancelInteractionResponse alloc] init]; - testCancelInteractionResponse.success = @NO; - [testConnectionManager respondToLastRequestWithResponse:testCancelInteractionResponse error:testError]; - }); - - it(@"should error", ^{ - expect(testCancelOp.error).to(equal(testError)); - }); - - it(@"should not finish", ^{ - expect(hasCalledOperationCompletionHandler).to(beFalse()); - expect(testCancelOp.isExecuting).to(beTrue()); - expect(testCancelOp.isFinished).to(beFalse()); - expect(testCancelOp.isCancelled).to(beFalse()); - }); - }); - }); - - context(@"If the operation has already finished", ^{ - beforeEach(^{ - [testCancelOp finishOperation]; - - expect(testCancelOp.isExecuting).to(beFalse()); - expect(testCancelOp.isFinished).to(beTrue()); - expect(testCancelOp.isCancelled).to(beFalse()); - - [testChoiceSet cancel]; - }); - - it(@"should not attempt to send a cancel interaction", ^{ - SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; - expect(lastRequest).toNot(beAnInstanceOf([SDLCancelInteraction class])); - }); - }); - - context(@"If the started operation has been canceled", ^{ - beforeEach(^{ - [testCancelOp start]; - [testCancelOp cancel]; - - expect(testCancelOp.isExecuting).to(beTrue()); - expect(testCancelOp.isFinished).to(beFalse()); - expect(testCancelOp.isCancelled).to(beTrue()); - - [testChoiceSet cancel]; - }); - - it(@"should not attempt to send a cancel interaction", ^{ - SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; - expect(lastRequest).toNot(beAnInstanceOf([SDLCancelInteraction class])); - }); - - it(@"should not finish", ^{ - expect(hasCalledOperationCompletionHandler).toEventually(beFalse()); - expect(testCancelOp.isExecuting).toEventually(beTrue()); - expect(testCancelOp.isFinished).toEventually(beFalse()); - expect(testCancelOp.isCancelled).toEventually(beTrue()); - }); - }); - - context(@"If the operation has not started", ^{ - beforeEach(^{ - expect(testCancelOp.isExecuting).to(beFalse()); - expect(testCancelOp.isFinished).to(beFalse()); - expect(testCancelOp.isCancelled).to(beFalse()); - - [testChoiceSet cancel]; - }); - - it(@"should not attempt to send a cancel interaction", ^{ - SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; - expect(lastRequest).toNot(beAnInstanceOf([SDLCancelInteraction class])); - }); - - context(@"Once the operation has started", ^{ - beforeEach(^{ - [testCancelOp start]; - }); - - it(@"should not attempt to send a cancel interaction", ^{ - SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; - expect(lastRequest).toNot(beAnInstanceOf([SDLCancelInteraction class])); - }); - - it(@"should finish", ^{ - expect(hasCalledOperationCompletionHandler).toEventually(beTrue()); - expect(testCancelOp.isExecuting).toEventually(beFalse()); - expect(testCancelOp.isFinished).toEventually(beTrue()); - expect(testCancelOp.isCancelled).toEventually(beTrue()); - }); - }); - }); - }); - - context(@"Head unit does not support the `CancelInteration` RPC", ^{ - beforeEach(^{ - SDLVersion *unsupportedVersion = [SDLVersion versionWithMajor:5 minor:1 patch:0]; - id globalMock = OCMPartialMock([SDLGlobals sharedGlobals]); - OCMStub([globalMock rpcVersion]).andReturn(unsupportedVersion); - }); - - it(@"should not attempt to send a cancel interaction if the operation is executing", ^{ - [testCancelOp start]; - - expect(testCancelOp.isExecuting).to(beTrue()); - expect(testCancelOp.isFinished).to(beFalse()); - expect(testCancelOp.isCancelled).to(beFalse()); - - [testChoiceSet cancel]; - - SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; - expect(lastRequest).toNot(beAnInstanceOf([SDLCancelInteraction class])); - }); - - it(@"should cancel the operation if it has not yet been run", ^{ - expect(testCancelOp.isExecuting).to(beFalse()); - expect(testCancelOp.isFinished).to(beFalse()); - expect(testCancelOp.isCancelled).to(beFalse()); - - [testChoiceSet cancel]; - - SDLCancelInteraction *lastRequest = testConnectionManager.receivedRequests.lastObject; - expect(lastRequest).toNot(beAnInstanceOf([SDLCancelInteraction class])); - - expect(testCancelOp.isExecuting).to(beFalse()); - expect(testCancelOp.isFinished).to(beFalse()); - expect(testCancelOp.isCancelled).to(beTrue()); - }); - }); - }); - }); - - describe(@"running a searchable choice set operation", ^{ - beforeEach(^{ - testOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:testKeyboardProperties keyboardDelegate:testKeyboardDelegate cancelID:testCancelID windowCapability:windowCapability]; - - testOp.completionBlock = ^{ - hasCalledOperationCompletionHandler = YES; - }; - [testOp start]; - }); - - it(@"should ask for custom properties", ^{ - OCMVerify([testKeyboardDelegate customKeyboardConfiguration]); - }); - - it(@"should update global keyboard properties", ^{ - expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); - }); - - describe(@"presenting the keyboard", ^{ - beforeEach(^{ - SDLSetGlobalPropertiesResponse *response = [[SDLSetGlobalPropertiesResponse alloc] init]; - response.success = @YES; - [testConnectionManager respondToLastRequestWithResponse:response]; - }); - - it(@"should send the perform interaction", ^{ - expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLPerformInteraction class])); - SDLPerformInteraction *request = testConnectionManager.receivedRequests.lastObject; - expect(request.initialText).to(equal(testChoiceSet.title)); - expect(request.initialPrompt).to(equal(testChoiceSet.initialPrompt)); - expect(request.interactionMode).to(equal(testInteractionMode)); - expect(request.interactionLayout).to(equal(SDLLayoutModeIconWithSearch)); - expect(request.timeoutPrompt).to(equal(testChoiceSet.timeoutPrompt)); - expect(request.helpPrompt).to(equal(testChoiceSet.helpPrompt)); - expect(request.timeout).to(equal(testChoiceSet.timeout * 1000)); - expect(request.vrHelp).to(beNil()); - expect(request.interactionChoiceSetIDList).to(equal(@[@65535])); - expect(request.cancelID).to(equal(testCancelID)); - }); - - it(@"should respond to submitted notifications", ^{ - NSString *inputData = @"Test"; - SDLRPCNotificationNotification *notification = nil; - - // Submit notification - SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; - input.event = SDLKeyboardEventSubmitted; - input.data = inputData; - notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; - - [[NSNotificationCenter defaultCenter] postNotification:notification]; - - OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventSubmitted]; - }] text:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(NSString *)obj isEqualToString:inputData]; - }]]); - - OCMVerify([testKeyboardDelegate userDidSubmitInput:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(NSString *)obj isEqualToString:inputData]; - }] withEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventSubmitted]; - }]]); - }); - - it(@"should respond to voice request notifications", ^{ - SDLRPCNotificationNotification *notification = nil; - - // Submit notification - SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; - input.event = SDLKeyboardEventVoice; - notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; - - [[NSNotificationCenter defaultCenter] postNotification:notification]; - - OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventVoice]; - }] text:[OCMArg isNil]]); - - OCMVerify([testKeyboardDelegate userDidSubmitInput:[OCMArg isNil] withEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventVoice]; - }]]); - }); - - it(@"should respond to abort notifications", ^{ - SDLRPCNotificationNotification *notification = nil; - - // Submit notification - SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; - input.event = SDLKeyboardEventAborted; - notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; - - [[NSNotificationCenter defaultCenter] postNotification:notification]; - - OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventAborted]; - }] text:[OCMArg isNil]]); - - OCMVerify([testKeyboardDelegate keyboardDidAbortWithReason:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventAborted]; - }]]); - }); - - it(@"should respond to enabled keyboard event", ^{ - SDLRPCNotificationNotification *notification = nil; - - // Submit notification - SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; - input.event = SDLKeyboardEventInputKeyMaskEnabled; - notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; - - [[NSNotificationCenter defaultCenter] postNotification:notification]; - - OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled]; - }] text:[OCMArg isNil]]); - - OCMVerify([testKeyboardDelegate keyboardDidUpdateInputMask:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled]; - }]]); - }); - - it(@"should respond to cancellation notifications", ^{ - SDLRPCNotificationNotification *notification = nil; - - // Submit notification - SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; - input.event = SDLKeyboardEventCancelled; - notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; - - [[NSNotificationCenter defaultCenter] postNotification:notification]; - - OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventCancelled]; - }] text:[OCMArg isNil]]); - - OCMVerify([testKeyboardDelegate keyboardDidAbortWithReason:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventCancelled]; - }]]); - }); - - it(@"should respond to text input notification with autocomplete", ^{ - NSString *inputData = @"Test"; - SDLRPCNotificationNotification *notification = nil; - - OCMStub([testKeyboardDelegate updateAutocompleteWithInput:[OCMArg any] autoCompleteResultsHandler:([OCMArg invokeBlockWithArgs:@[inputData], nil])]); - - // Submit notification - SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; - input.event = SDLKeyboardEventKeypress; - input.data = inputData; - notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; - - [[NSNotificationCenter defaultCenter] postNotification:notification]; - - OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventKeypress]; - }] text:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(NSString *)obj isEqualToString:inputData]; - }]]); - - OCMVerify([testKeyboardDelegate updateAutocompleteWithInput:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(NSString *)obj isEqualToString:inputData]; - }] autoCompleteResultsHandler:[OCMArg any]]); - - expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); - - SDLSetGlobalProperties *setProperties = testConnectionManager.receivedRequests.lastObject; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - expect(setProperties.keyboardProperties.autoCompleteText).to(equal(inputData)); -#pragma clang diagnostic pop - }); - - it(@"should respond to text input notification with character set", ^{ - NSString *inputData = @"Test"; - SDLRPCNotificationNotification *notification = nil; - - OCMStub([testKeyboardDelegate updateCharacterSetWithInput:[OCMArg any] completionHandler:([OCMArg invokeBlockWithArgs:@[inputData], nil])]); - - // Submit notification - SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init]; - input.event = SDLKeyboardEventKeypress; - input.data = inputData; - notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input]; - - [[NSNotificationCenter defaultCenter] postNotification:notification]; - - OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventKeypress]; - }] text:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(NSString *)obj isEqualToString:inputData]; - }]]); - - OCMVerify([testKeyboardDelegate updateCharacterSetWithInput:[OCMArg checkWithBlock:^BOOL(id obj) { - return [(NSString *)obj isEqualToString:inputData]; - }] completionHandler:[OCMArg any]]); - - expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); - - SDLSetGlobalProperties *setProperties = testConnectionManager.receivedRequests.lastObject; - expect(setProperties.keyboardProperties.limitedCharacterList).to(equal(@[inputData])); - }); - - describe(@"after a perform interaction response", ^{ - beforeEach(^{ - SDLPerformInteractionResponse *response = [[SDLPerformInteractionResponse alloc] init]; - response.success = @YES; - - [testConnectionManager respondToLastRequestWithResponse:response]; - }); - - it(@"should reset the keyboard properties", ^{ - expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLSetGlobalProperties class])); - }); - - describe(@"after the reset response", ^{ - beforeEach(^{ - SDLSetGlobalPropertiesResponse *response = [[SDLSetGlobalPropertiesResponse alloc] init]; - response.success = @YES; - [testConnectionManager respondToLastRequestWithResponse:response]; - }); - - it(@"should be finished", ^{ - expect(hasCalledOperationCompletionHandler).toEventually(beTrue()); - expect(testOp.isFinished).toEventually(beTrue()); - }); - }); - }); - }); - }); -}); - -QuickSpecEnd |