diff options
author | Joel Fischer <joeljfischer@gmail.com> | 2018-04-24 17:55:07 -0400 |
---|---|---|
committer | Joel Fischer <joeljfischer@gmail.com> | 2018-04-24 17:55:07 -0400 |
commit | b4c244afb1b2aceb1b5610685874fb85a976a31d (patch) | |
tree | 1f963f616a8048797ef46ce9648e9ea6dccbaa7c | |
parent | ebd6c03927f4115edfe54aa1c24149a008a17b03 (diff) | |
download | sdl_ios-b4c244afb1b2aceb1b5610685874fb85a976a31d.tar.gz |
Add unit tests
* Fix sending artwork menus when no artworks were allowed
* Fix sending menu items when titles matched
* Fix voice command manager does not need a file manager reference
-rw-r--r-- | SmartDeviceLink-iOS.xcodeproj/project.pbxproj | 22 | ||||
-rw-r--r-- | SmartDeviceLink/SDLMenuManager.m | 3 | ||||
-rw-r--r-- | SmartDeviceLink/SDLScreenManager.m | 2 | ||||
-rw-r--r-- | SmartDeviceLink/SDLVoiceCommandManager.h | 2 | ||||
-rw-r--r-- | SmartDeviceLink/SDLVoiceCommandManager.m | 4 | ||||
-rw-r--r-- | SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m | 199 | ||||
-rw-r--r-- | SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m | 44 | ||||
-rw-r--r-- | SmartDeviceLinkTests/DevAPISpecs/SDLVoiceCommandSpec.m | 124 | ||||
-rw-r--r-- | SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m | 26 |
9 files changed, 395 insertions, 31 deletions
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj index 4a28c01ce..19fccee2f 100644 --- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj +++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj @@ -1059,6 +1059,8 @@ 5DEF69661FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DEF69651FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.m */; }; 5DF40B22208E761A00DD6FDA /* SDLVoiceCommandManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DF40B20208E761A00DD6FDA /* SDLVoiceCommandManager.h */; }; 5DF40B23208E761A00DD6FDA /* SDLVoiceCommandManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DF40B21208E761A00DD6FDA /* SDLVoiceCommandManager.m */; }; + 5DF40B26208FA7DE00DD6FDA /* SDLMenuManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DF40B25208FA7DE00DD6FDA /* SDLMenuManagerSpec.m */; }; + 5DF40B28208FDA9700DD6FDA /* SDLVoiceCommandSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DF40B27208FDA9700DD6FDA /* SDLVoiceCommandSpec.m */; }; 5DFFB9151BD7C89700DB3F04 /* SDLConnectionManagerType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */; }; 880E8C2920697FEE00CF86C2 /* SDLSystemCapabilityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 880E8C2720697FEE00CF86C2 /* SDLSystemCapabilityManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 880E8C2A20697FEE00CF86C2 /* SDLSystemCapabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 880E8C2820697FEE00CF86C2 /* SDLSystemCapabilityManager.m */; }; @@ -2336,6 +2338,8 @@ 5DF2BB9C1B94E38A00CE5994 /* SDLURLSessionSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLURLSessionSpec.m; path = "UtilitiesSpecs/HTTP Connection/SDLURLSessionSpec.m"; sourceTree = "<group>"; }; 5DF40B20208E761A00DD6FDA /* SDLVoiceCommandManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLVoiceCommandManager.h; sourceTree = "<group>"; }; 5DF40B21208E761A00DD6FDA /* SDLVoiceCommandManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLVoiceCommandManager.m; sourceTree = "<group>"; }; + 5DF40B25208FA7DE00DD6FDA /* SDLMenuManagerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLMenuManagerSpec.m; path = DevAPISpecs/SDLMenuManagerSpec.m; sourceTree = "<group>"; }; + 5DF40B27208FDA9700DD6FDA /* SDLVoiceCommandSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLVoiceCommandSpec.m; path = DevAPISpecs/SDLVoiceCommandSpec.m; sourceTree = "<group>"; }; 5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLConnectionManagerType.h; sourceTree = "<group>"; }; 880E8C2720697FEE00CF86C2 /* SDLSystemCapabilityManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLSystemCapabilityManager.h; sourceTree = "<group>"; }; 880E8C2820697FEE00CF86C2 /* SDLSystemCapabilityManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSystemCapabilityManager.m; sourceTree = "<group>"; }; @@ -4396,14 +4400,15 @@ name = "Focus / Haptic"; sourceTree = "<group>"; }; - 5DAD5F8120507DE40025624C /* Show */ = { + 5DAD5F8120507DE40025624C /* Screen */ = { isa = PBXGroup; children = ( + 5DF40B24208FA7C500DD6FDA /* Menu */, 5DAD5F8220507DED0025624C /* Soft Button */, 5DAD5F8320507DF30025624C /* Text and Graphic */, 5DAD5F8420507E1F0025624C /* SDLScreenManagerSpec.m */, ); - name = Show; + name = Screen; sourceTree = "<group>"; }; 5DAD5F8220507DED0025624C /* Soft Button */ = { @@ -4571,7 +4576,7 @@ 5DBAE0A81D35886E00CE00BF /* Managers */ = { isa = PBXGroup; children = ( - 5DAD5F8120507DE40025624C /* Show */, + 5DAD5F8120507DE40025624C /* Screen */, DA8966ED1E5693D100413EAB /* Streaming */, 5D1654541D3E753100554D93 /* Lifecycle */, 5D76E31A1D3805E600647CFA /* LockScreen */, @@ -4721,6 +4726,15 @@ name = Mocks; sourceTree = "<group>"; }; + 5DF40B24208FA7C500DD6FDA /* Menu */ = { + isa = PBXGroup; + children = ( + 5DF40B25208FA7DE00DD6FDA /* SDLMenuManagerSpec.m */, + 5DF40B27208FDA9700DD6FDA /* SDLVoiceCommandSpec.m */, + ); + name = Menu; + sourceTree = "<group>"; + }; 886D313C206A94BA001185B4 /* System Capabilities */ = { isa = PBXGroup; children = ( @@ -6179,6 +6193,7 @@ 162E83971A9BDE8B00906325 /* SDLVehicleTypeSpec.m in Sources */, 1680B1131A9CD7AD00DBD79E /* SDLProtocolHeaderSpec.m in Sources */, 162E82D01A9BDE8A00906325 /* SDLButtonEventModeSpec.m in Sources */, + 5DF40B26208FA7DE00DD6FDA /* SDLMenuManagerSpec.m in Sources */, 162E83781A9BDE8B00906325 /* SDLDeviceInfoSpec.m in Sources */, 162E83391A9BDE8B00906325 /* SDLSetAppIconSpec.m in Sources */, 162E83011A9BDE8B00906325 /* SDLTimerModeSpec.m in Sources */, @@ -6217,6 +6232,7 @@ 162E82CF1A9BDE8A00906325 /* SDLBitsPerSampleSpec.m in Sources */, 162E831E1A9BDE8B00906325 /* SDLOnTBTClientStateSpec.m in Sources */, 162E83351A9BDE8B00906325 /* SDLReadDIDSpec.m in Sources */, + 5DF40B28208FDA9700DD6FDA /* SDLVoiceCommandSpec.m in Sources */, 162E836F1A9BDE8B00906325 /* SDLUnsubscribeVehicleDataResponseSpec.m in Sources */, 162E82DB1A9BDE8B00906325 /* SDLECallConfirmationStatusSpec.m in Sources */, 162E82D81A9BDE8A00906325 /* SDLDimensionSpec.m in Sources */, diff --git a/SmartDeviceLink/SDLMenuManager.m b/SmartDeviceLink/SDLMenuManager.m index 8ad3e1ca1..24bdf0025 100644 --- a/SmartDeviceLink/SDLMenuManager.m +++ b/SmartDeviceLink/SDLMenuManager.m @@ -153,7 +153,7 @@ UInt32 const MenuCellIdMin = 0; NSArray<SDLRPCRequest *> *mainMenuCommands = nil; NSArray<SDLRPCRequest *> *subMenuCommands = nil; - if ([self sdl_findAllArtworksToBeUploadedFromCells:self.menuCells].count > 0) { + if ([self sdl_findAllArtworksToBeUploadedFromCells:self.menuCells].count > 0 || ![self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameCommandIcon]) { // Send artwork-less menu mainMenuCommands = [self sdl_mainMenuCommandsForCells:self.menuCells withArtwork:NO]; subMenuCommands = [self sdl_subMenuCommandsForCells:self.menuCells withArtwork:NO]; @@ -215,6 +215,7 @@ UInt32 const MenuCellIdMin = 0; } if (titleCheckSet.count != menuCells.count) { SDLLogE(@"Not all cell titles are unique. The menu will not be set."); + return; } // Set the ids diff --git a/SmartDeviceLink/SDLScreenManager.m b/SmartDeviceLink/SDLScreenManager.m index ee43dda61..f0de151d2 100644 --- a/SmartDeviceLink/SDLScreenManager.m +++ b/SmartDeviceLink/SDLScreenManager.m @@ -40,7 +40,7 @@ NS_ASSUME_NONNULL_BEGIN _textAndGraphicManager = [[SDLTextAndGraphicManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager]; _softButtonManager = [[SDLSoftButtonManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager]; _menuManager = [[SDLMenuManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager]; - _voiceCommandMenuManager = [[SDLVoiceCommandManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager]; + _voiceCommandMenuManager = [[SDLVoiceCommandManager alloc] initWithConnectionManager:connectionManager]; return self; } diff --git a/SmartDeviceLink/SDLVoiceCommandManager.h b/SmartDeviceLink/SDLVoiceCommandManager.h index e248a4dd1..bf8d13fb9 100644 --- a/SmartDeviceLink/SDLVoiceCommandManager.h +++ b/SmartDeviceLink/SDLVoiceCommandManager.h @@ -24,7 +24,7 @@ typedef void(^SDLMenuUpdateCompletionHandler)(NSError *__nullable error); @interface SDLVoiceCommandManager : NSObject -- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager; +- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager; @property (copy, nonatomic) NSArray<SDLVoiceCommand *> *voiceCommands; diff --git a/SmartDeviceLink/SDLVoiceCommandManager.m b/SmartDeviceLink/SDLVoiceCommandManager.m index 161f7787b..1f7100f4a 100644 --- a/SmartDeviceLink/SDLVoiceCommandManager.m +++ b/SmartDeviceLink/SDLVoiceCommandManager.m @@ -32,7 +32,6 @@ NS_ASSUME_NONNULL_BEGIN @interface SDLVoiceCommandManager() @property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager; -@property (weak, nonatomic) SDLFileManager *fileManager; @property (copy, nonatomic, nullable) SDLHMILevel currentLevel; @@ -63,12 +62,11 @@ UInt32 const VoiceCommandIdMin = 1900000000; return self; } -- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager { +- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager { self = [self init]; if (!self) { return nil; } _connectionManager = connectionManager; - _fileManager = fileManager; return self; } diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m new file mode 100644 index 000000000..81fcd3113 --- /dev/null +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m @@ -0,0 +1,199 @@ +#import <Quick/Quick.h> +#import <Nimble/Nimble.h> +#import <OCMock/OCMock.h> + +#import "SDLAddCommand.h" +#import "SDLAddSubMenu.h" +#import "SDLDeleteCommand.h" +#import "SDLDisplayCapabilities.h" +#import "SDLFileManager.h" +#import "SDLHMILevel.h" +#import "SDLImage.h" +#import "SDLImageField.h" +#import "SDLImageFieldName.h" +#import "SDLMenuCell.h" +#import "SDLMenuManager.h" +#import "TestConnectionManager.h" + +@interface SDLMenuCell() + +@property (assign, nonatomic) UInt32 parentCellId; +@property (assign, nonatomic) UInt32 cellId; + +@end + +@interface SDLMenuManager() + +@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager; +@property (weak, nonatomic) SDLFileManager *fileManager; + +@property (copy, nonatomic, nullable) SDLHMILevel currentLevel; +@property (strong, nonatomic, nullable) SDLDisplayCapabilities *displayCapabilities; + +@property (strong, nonatomic, nullable) NSArray<SDLRPCRequest *> *inProgressUpdate; +@property (assign, nonatomic) BOOL hasQueuedUpdate; +@property (assign, nonatomic) BOOL waitingOnHMILevelUpdate; + +@property (assign, nonatomic) UInt32 lastMenuId; +@property (copy, nonatomic) NSArray<SDLMenuCell *> *oldMenuCells; + +@end + +QuickSpecBegin(SDLMenuManagerSpec) + +describe(@"menu manager", ^{ + __block SDLMenuManager *testManager = nil; + __block TestConnectionManager *mockConnectionManager = nil; + __block SDLFileManager *mockFileManager = nil; + + __block SDLArtwork *testArtwork = [[SDLArtwork alloc] initWithData:[@"Test data" dataUsingEncoding:NSUTF8StringEncoding] name:@"some artwork name" fileExtension:@"png" persistent:NO]; + + __block SDLMenuCell *textOnlyCell = [[SDLMenuCell alloc] initWithTitle:@"Test 1" icon:nil voiceCommands:nil handler:^{}]; + __block SDLMenuCell *textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" icon:testArtwork voiceCommands:nil handler:^{}]; + __block SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Test 3" subCells:@[textOnlyCell, textAndImageCell]]; + + beforeEach(^{ + mockConnectionManager = [[TestConnectionManager alloc] init]; + mockFileManager = OCMClassMock([SDLFileManager class]); + testManager = [[SDLMenuManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager]; + }); + + it(@"should instantiate correctly", ^{ + expect(testManager.menuCells).to(beEmpty()); + expect(testManager.connectionManager).to(equal(mockConnectionManager)); + expect(testManager.fileManager).to(equal(mockFileManager)); + expect(testManager.currentLevel).to(beNil()); + expect(testManager.displayCapabilities).to(beNil()); + expect(testManager.inProgressUpdate).to(beNil()); + expect(testManager.hasQueuedUpdate).to(beFalse()); + expect(testManager.waitingOnHMILevelUpdate).to(beFalse()); + expect(testManager.lastMenuId).to(equal(0)); + expect(testManager.oldMenuCells).to(beEmpty()); + }); + + describe(@"updating menu cells before HMI is ready", ^{ + context(@"when in HMI NONE", ^{ + beforeEach(^{ + testManager.currentLevel = SDLHMILevelNone; + }); + + it(@"should not update", ^{ + testManager.menuCells = @[textOnlyCell]; + + expect(testManager.inProgressUpdate).to(beNil()); + }); + }); + + context(@"when no HMI level has been received", ^{ + beforeEach(^{ + testManager.currentLevel = nil; + }); + + it(@"should not update", ^{ + testManager.menuCells = @[textOnlyCell]; + + expect(testManager.inProgressUpdate).to(beNil()); + }); + }); + }); + + describe(@"updating menu cell", ^{ + beforeEach(^{ + testManager.currentLevel = SDLHMILevelFull; + + testManager.displayCapabilities = [[SDLDisplayCapabilities alloc] init]; + SDLImageField *commandIconField = [[SDLImageField alloc] init]; + commandIconField.name = SDLImageFieldNameCommandIcon; + testManager.displayCapabilities.imageFields = @[commandIconField]; + testManager.displayCapabilities.graphicSupported = @YES; + }); + + it(@"should fail with a duplicate title", ^{ + testManager.menuCells = @[textOnlyCell, textOnlyCell]; + + expect(testManager.menuCells).to(beEmpty()); + }); + + it(@"should properly update a text cell", ^{ + testManager.menuCells = @[textOnlyCell]; + + NSPredicate *deleteCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLDeleteCommand class]]; + NSArray *deletes = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:deleteCommandPredicate]; + expect(deletes).to(beEmpty()); + + NSPredicate *addCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLAddCommand class]]; + NSArray *add = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:addCommandPredicate]; + expect(add).toNot(beEmpty()); + }); + + describe(@"updating with an image", ^{ + context(@"when the image is already on the head unit", ^{ + beforeEach(^{ + OCMStub([mockFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(YES); + }); + + it(@"should properly update an image cell", ^{ + testManager.menuCells = @[textAndImageCell]; + + NSPredicate *addCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLAddCommand class]]; + NSArray *add = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:addCommandPredicate]; + SDLAddCommand *sentCommand = add.firstObject; + + expect(add).to(haveCount(1)); + expect(sentCommand.cmdIcon.value).to(equal(testArtwork.name)); + }); + }); + + context(@"when the image is not on the head unit", ^{ + beforeEach(^{ + OCMStub([mockFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(NO); + }); + + it(@"should immediately attempt to update without the image", ^{ + testManager.menuCells = @[textAndImageCell]; + + NSPredicate *addCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLAddCommand class]]; + NSArray *add = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:addCommandPredicate]; + SDLAddCommand *sentCommand = add.firstObject; + + expect(add).to(haveCount(1)); + expect(sentCommand.cmdIcon.value).to(beNil()); + }); + }); + }); + + it(@"should properly update with subcells", ^{ + testManager.menuCells = @[submenuCell]; + + NSPredicate *addCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLAddCommand class]]; + NSArray *adds = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:addCommandPredicate]; + + NSPredicate *submenuCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLAddSubMenu class]]; + NSArray *submenus = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:submenuCommandPredicate]; + + expect(adds).to(haveCount(2)); + expect(submenus).to(haveCount(1)); + }); + + context(@"when a menu already exists", ^{ + beforeEach(^{ + testManager.menuCells = @[textOnlyCell]; + }); + + it(@"should send deletes first", ^{ + testManager.menuCells = @[textAndImageCell]; + + NSPredicate *deleteCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLDeleteCommand class]]; + NSArray *deletes = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:deleteCommandPredicate]; + + NSPredicate *addCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLAddCommand class]]; + NSArray *adds = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:addCommandPredicate]; + + expect(deletes).to(haveCount(1)); + expect(adds).to(haveCount(1)); + }); + }); + }); +}); + +QuickSpecEnd diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m index cb29f3433..bc42d0866 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m @@ -66,37 +66,37 @@ describe(@"text and graphic manager", ^{ expect(testManager.textField4Type).to(beNil()); }); - context(@"when in HMI NONE", ^{ + describe(@"setting setters", ^{ beforeEach(^{ - testManager.currentLevel = SDLHMILevelNone; + testManager.currentLevel = SDLHMILevelFull; }); - it(@"should not set text field 1", ^{ - testManager.textField1 = testString; + context(@"when in HMI NONE", ^{ + beforeEach(^{ + testManager.currentLevel = SDLHMILevelNone; + }); - expect(testManager.textField1).to(equal(testString)); - expect(testManager.inProgressUpdate).to(beNil()); - expect(testManager.isDirty).to(beFalse()); - }); - }); + it(@"should not set text field 1", ^{ + testManager.textField1 = testString; - context(@"when no HMI level has been received", ^{ - beforeEach(^{ - testManager.currentLevel = nil; + expect(testManager.textField1).to(equal(testString)); + expect(testManager.inProgressUpdate).to(beNil()); + expect(testManager.isDirty).to(beFalse()); + }); }); - it(@"should not set text field 1", ^{ - testManager.textField1 = testString; + context(@"when no HMI level has been received", ^{ + beforeEach(^{ + testManager.currentLevel = nil; + }); - expect(testManager.textField1).to(equal(testString)); - expect(testManager.inProgressUpdate).to(beNil()); - expect(testManager.isDirty).to(beFalse()); - }); - }); + it(@"should not set text field 1", ^{ + testManager.textField1 = testString; - describe(@"setting setters", ^{ - beforeEach(^{ - testManager.currentLevel = SDLHMILevelFull; + expect(testManager.textField1).to(equal(testString)); + expect(testManager.inProgressUpdate).to(beNil()); + expect(testManager.isDirty).to(beFalse()); + }); }); context(@"while batching", ^{ diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLVoiceCommandSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLVoiceCommandSpec.m new file mode 100644 index 000000000..305387d8d --- /dev/null +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLVoiceCommandSpec.m @@ -0,0 +1,124 @@ +#import <Quick/Quick.h> +#import <Nimble/Nimble.h> +#import <OCMock/OCMock.h> + +#import "SDLAddCommand.h" +#import "SDLDeleteCommand.h" +#import "SDLFileManager.h" +#import "SDLHMILevel.h" +#import "SDLVoiceCommand.h" +#import "SDLVoiceCommandManager.h" +#import "TestConnectionManager.h" + +@interface SDLVoiceCommand() + +@property (assign, nonatomic) UInt32 commandId; + +@end + +@interface SDLVoiceCommandManager() + +@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager; +@property (weak, nonatomic) SDLFileManager *fileManager; + +@property (copy, nonatomic, nullable) SDLHMILevel currentLevel; + +@property (strong, nonatomic, nullable) NSArray<SDLRPCRequest *> *inProgressUpdate; +@property (assign, nonatomic) BOOL hasQueuedUpdate; +@property (assign, nonatomic) BOOL waitingOnHMILevelUpdate; + +@property (assign, nonatomic) UInt32 lastVoiceCommandId; +@property (copy, nonatomic) NSArray<SDLVoiceCommand *> *oldVoiceCommands; + +@end + +UInt32 const VoiceCommandIdMin = 1900000000; + +QuickSpecBegin(SDLVoiceCommandSpec) + +describe(@"voice command manager", ^{ + __block SDLVoiceCommandManager *testManager = nil; + __block TestConnectionManager *mockConnectionManager = nil; + + __block SDLVoiceCommand *testVoiceCommand = [[SDLVoiceCommand alloc] initWithVoiceCommands:@[@"Test 1"] handler:^{}]; + __block SDLVoiceCommand *testVoiceCommand2 = [[SDLVoiceCommand alloc] initWithVoiceCommands:@[@"Test 2"] handler:^{}]; + + beforeEach(^{ + mockConnectionManager = [[TestConnectionManager alloc] init]; + testManager = [[SDLVoiceCommandManager alloc] initWithConnectionManager:mockConnectionManager]; + }); + + it(@"should instantiate correctly", ^{ + expect(testManager.voiceCommands).to(beEmpty()); + expect(testManager.connectionManager).to(equal(mockConnectionManager)); + expect(testManager.currentLevel).to(beNil()); + expect(testManager.inProgressUpdate).to(beNil()); + expect(testManager.hasQueuedUpdate).to(beFalse()); + expect(testManager.waitingOnHMILevelUpdate).to(beFalse()); + expect(testManager.lastVoiceCommandId).to(equal(VoiceCommandIdMin)); + expect(testManager.oldVoiceCommands).to(beEmpty()); + }); + + describe(@"updating voice commands before HMI is ready", ^{ + context(@"when in HMI NONE", ^{ + beforeEach(^{ + testManager.currentLevel = SDLHMILevelNone; + }); + + it(@"should not update", ^{ + testManager.voiceCommands = @[testVoiceCommand]; + expect(testManager.inProgressUpdate).to(beNil()); + }); + }); + + context(@"when no HMI level has been received", ^{ + beforeEach(^{ + testManager.currentLevel = nil; + }); + + it(@"should not update", ^{ + testManager.voiceCommands = @[testVoiceCommand]; + expect(testManager.inProgressUpdate).to(beNil()); + }); + }); + }); + + describe(@"updating voice commands", ^{ + beforeEach(^{ + testManager.currentLevel = SDLHMILevelFull; + }); + + it(@"should properly update a command", ^{ + testManager.voiceCommands = @[testVoiceCommand]; + + NSPredicate *deleteCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLDeleteCommand class]]; + NSArray *deletes = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:deleteCommandPredicate]; + expect(deletes).to(beEmpty()); + + NSPredicate *addCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLAddCommand class]]; + NSArray *add = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:addCommandPredicate]; + expect(add).toNot(beEmpty()); + }); + + context(@"when a menu already exists", ^{ + beforeEach(^{ + testManager.voiceCommands = @[testVoiceCommand]; + }); + + it(@"should send deletes first", ^{ + testManager.voiceCommands = @[testVoiceCommand2]; + + NSPredicate *deleteCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLDeleteCommand class]]; + NSArray *deletes = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:deleteCommandPredicate]; + + NSPredicate *addCommandPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [SDLAddCommand class]]; + NSArray *adds = [[mockConnectionManager.receivedRequests copy] filteredArrayUsingPredicate:addCommandPredicate]; + + expect(deletes).to(haveCount(1)); + expect(adds).to(haveCount(2)); + }); + }); + }); +}); + +QuickSpecEnd diff --git a/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m b/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m index adb494fb6..ba0c29930 100644 --- a/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m +++ b/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m @@ -35,6 +35,32 @@ NS_ASSUME_NONNULL_BEGIN [self sendConnectionRequest:request withResponseHandler:handler]; } +- (void)sendRequests:(nonnull NSArray<SDLRPCRequest *> *)requests progressHandler:(nullable SDLMultipleAsyncRequestProgressHandler)progressHandler completionHandler:(nullable SDLMultipleRequestCompletionHandler)completionHandler { + [requests enumerateObjectsUsingBlock:^(SDLRPCRequest * _Nonnull request, NSUInteger idx, BOOL * _Nonnull stop) { + [self sendConnectionRequest:request withResponseHandler:nil]; + + if (progressHandler != nil) { + progressHandler(request, nil, nil, (double)idx / (double)requests.count); + } + }]; + + if (completionHandler != nil) { + completionHandler(YES); + } +} + +- (void)sendSequentialRequests:(nonnull NSArray<SDLRPCRequest *> *)requests progressHandler:(nullable SDLMultipleSequentialRequestProgressHandler)progressHandler completionHandler:(nullable SDLMultipleRequestCompletionHandler)completionHandler { + [requests enumerateObjectsUsingBlock:^(SDLRPCRequest * _Nonnull request, NSUInteger idx, BOOL * _Nonnull stop) { + [self sendConnectionRequest:request withResponseHandler:nil]; + progressHandler(request, nil, nil, (double)idx / (double)requests.count); + }]; + + if (completionHandler != nil) { + completionHandler(YES); + } +} + + - (void)respondToLastRequestWithResponse:(__kindof SDLRPCResponse *)response { [self respondToLastRequestWithResponse:response error:nil]; } |