summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2018-04-24 17:55:07 -0400
committerJoel Fischer <joeljfischer@gmail.com>2018-04-24 17:55:07 -0400
commitb4c244afb1b2aceb1b5610685874fb85a976a31d (patch)
tree1f963f616a8048797ef46ce9648e9ea6dccbaa7c
parentebd6c03927f4115edfe54aa1c24149a008a17b03 (diff)
downloadsdl_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.pbxproj22
-rw-r--r--SmartDeviceLink/SDLMenuManager.m3
-rw-r--r--SmartDeviceLink/SDLScreenManager.m2
-rw-r--r--SmartDeviceLink/SDLVoiceCommandManager.h2
-rw-r--r--SmartDeviceLink/SDLVoiceCommandManager.m4
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m199
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m44
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLVoiceCommandSpec.m124
-rw-r--r--SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m26
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];
}