summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlapinskijw <jlapinski.dev@gmail.com>2020-06-03 10:37:10 -0400
committerlapinskijw <jlapinski.dev@gmail.com>2020-06-03 10:37:10 -0400
commita70ea4e2f03f8765cb542df35a155345745ae1c1 (patch)
treea46e7ba93392b7cc32ad90cb82eed73f895a9f46
parent43084914c4b15a2fe95aea9548d650a4edcca2d9 (diff)
downloadsdl_ios-a70ea4e2f03f8765cb542df35a155345745ae1c1.tar.gz
pausing working on tests to address 1661
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLPermissionsManagerSpec.m419
1 files changed, 418 insertions, 1 deletions
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPermissionsManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPermissionsManagerSpec.m
index eaf657595..1c05a2f37 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLPermissionsManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLPermissionsManagerSpec.m
@@ -270,7 +270,424 @@ describe(@"SDLPermissionsManager", ^{
});
});
- describe(@"adding and using observers", ^{
+ fdescribe(@"adding and using observers", ^{
+ describe(@"adding new observers with struct method", ^{
+ context(@"when no data is present", ^{
+ __block BOOL testObserverCalled = NO;
+ __block SDLPermissionGroupStatus testObserverStatus = SDLPermissionGroupStatusUnknown;
+ __block NSDictionary<SDLPermissionRPCName,NSNumber *> *testObserverChangeDict = nil;
+
+ beforeEach(^{
+ testObserverCalled = NO;
+ testObserverStatus = SDLPermissionGroupStatusUnknown;
+ testObserverChangeDict = nil;
+
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameAllAllowed, testRPCNameAllDisallowed] groupType:SDLPermissionGroupTypeAny withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber *> * _Nonnull change, SDLPermissionGroupStatus status) {
+ testObserverChangeDict = change;
+ testObserverStatus = status;
+ testObserverCalled = YES;
+ }];
+ });
+
+ it(@"should not return permission statuses", ^{
+ expect(@(testObserverCalled)).to(equal(@NO));
+ expect(@(testObserverStatus)).to(equal(@(SDLPermissionGroupStatusUnknown)));
+ expect(testObserverChangeDict[testRPCNameAllAllowed]).to(beNil());
+ expect(testObserverChangeDict[testRPCNameAllDisallowed]).to(beNil());
+ });
+ });
+
+ context(@"when data is already present", ^{
+ __block NSInteger numberOfTimesObserverCalled = 0;
+ __block NSDictionary<SDLPermissionRPCName,NSNumber *> *testObserverBlockChangedDict = nil;
+ __block SDLPermissionGroupStatus testObserverReturnStatus = SDLPermissionGroupStatusUnknown;
+
+ context(@"to match an ANY observer", ^{
+ beforeEach(^{
+ // Reset vars
+ numberOfTimesObserverCalled = 0;
+
+ // Post the notification before setting the observer to make sure data is already present
+ // HMI Full & Limited allowed
+ [[NSNotificationCenter defaultCenter] postNotification:limitedHMINotification];
+ [[NSNotificationCenter defaultCenter] postNotification:testPermissionsNotification];
+
+ // This should be called twice, once for each RPC being observed. It should be called immediately since data should already be present
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameAllAllowed, testRPCNameAllDisallowed] groupType:SDLPermissionGroupTypeAny withHandler:^(NSDictionary<SDLPermissionRPCName, NSNumber *> * _Nonnull changedDict, SDLPermissionGroupStatus status) {
+ numberOfTimesObserverCalled++;
+ testObserverBlockChangedDict = changedDict;
+ testObserverReturnStatus = status;
+ }];
+ });
+
+ it(@"should call the observer with proper status", ^{
+ expect(@(numberOfTimesObserverCalled)).to(equal(0));
+ expect(testObserverBlockChangedDict[testRPCNameAllAllowed]).to(beNil());
+ expect(testObserverBlockChangedDict[testRPCNameAllDisallowed]).to(beNil());
+ expect(testObserverBlockChangedDict.allKeys).to(beNil());
+ expect(@(testObserverReturnStatus)).to(equal(@(SDLPermissionGroupStatusUnknown)));
+ });
+ });
+
+ context(@"to match an all allowed observer", ^{
+ beforeEach(^{
+ // Reset vars
+ numberOfTimesObserverCalled = 0;
+
+ // Post the notification before setting the observer to make sure data is already present
+ // HMI Full & Limited allowed, hmi level LIMITED
+ [[NSNotificationCenter defaultCenter] postNotification:limitedHMINotification];
+ [[NSNotificationCenter defaultCenter] postNotification:testPermissionsNotification];
+
+ // This should be called twice, once for each RPC being observed. It should be called immediately since data should already be present
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameAllAllowed, testRPCNameFullLimitedAllowed] groupType:SDLPermissionGroupTypeAllAllowed withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber *> * _Nonnull change, SDLPermissionGroupStatus status) {
+ numberOfTimesObserverCalled++;
+ testObserverBlockChangedDict = change;
+ testObserverReturnStatus = status;
+ }];
+ });
+
+ it(@"should call the observer with proper status", ^{
+ expect(@(numberOfTimesObserverCalled)).to(equal(@0));
+ expect(testObserverBlockChangedDict[testRPCNameAllAllowed]).to(beNil());
+ expect(testObserverBlockChangedDict[testRPCNameFullLimitedAllowed]).to(beNil());
+ expect(testObserverBlockChangedDict.allKeys).to(beNil());
+ expect(@(testObserverReturnStatus)).to(equal(@(SDLPermissionGroupStatusUnknown)));
+ });
+ });
+
+ context(@"that does not match an all allowed observer", ^{
+ beforeEach(^{
+ // Reset vars
+ numberOfTimesObserverCalled = 0;
+
+ // Post the notification before setting the observer to make sure data is already present
+ // HMI Full & Limited allowed, hmi level NONE
+ [[NSNotificationCenter defaultCenter] postNotification:noneHMINotification];
+ [[NSNotificationCenter defaultCenter] postNotification:testPermissionsNotification];
+
+ // This should be called twice, once for each RPC being observed. It should be called immediately since data should already be present
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameAllDisallowed, testRPCNameFullLimitedAllowed] groupType:SDLPermissionGroupTypeAllAllowed withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber *> * _Nonnull change, SDLPermissionGroupStatus status) {
+ numberOfTimesObserverCalled++;
+ testObserverReturnStatus = status;
+ }];
+ });
+
+ it(@"should call the observer with status Disallowed", ^{
+ expect(@(numberOfTimesObserverCalled)).to(equal(@0));
+ expect(@(testObserverReturnStatus)).to(equal(@(SDLPermissionGroupStatusUnknown)));
+ });
+ });
+ });
+
+
+ context(@"updating an observer with new permission data", ^{
+ __block NSInteger numberOfTimesObserverCalled = 0;
+
+ __block SDLOnPermissionsChange *testPermissionChangeUpdate = nil;
+ __block SDLPermissionItem *testPermissionUpdated = nil;
+ __block NSMutableArray<NSDictionary<SDLPermissionRPCName,NSNumber*> *> *changeDicts = nil;
+ __block NSMutableArray<NSNumber<SDLUInt> *> *testStatuses = nil;
+
+ context(@"to match an ANY observer", ^{
+ beforeEach(^{
+ // Reset vars
+ numberOfTimesObserverCalled = 0;
+ changeDicts = [NSMutableArray array];
+ testStatuses = [NSMutableArray array];
+
+ // Post the notification before setting the observer to make sure data is already present
+ // HMI Full & Limited allowed, hmi level LIMITED
+ [[NSNotificationCenter defaultCenter] postNotification:limitedHMINotification];
+ [[NSNotificationCenter defaultCenter] postNotification:testPermissionsNotification];
+
+ // Set an observer that should be called when new data is sent
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameAllAllowed, testRPCNameAllDisallowed] groupType:SDLPermissionGroupTypeAny withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber *> * _Nonnull changedDict, SDLPermissionGroupStatus status) {
+ numberOfTimesObserverCalled++;
+ [changeDicts addObject:changedDict];
+ }];
+
+ // Create a permission update disallowing our current HMI level for the observed permission
+ SDLParameterPermissions *testParameterPermissions = [[SDLParameterPermissions alloc] init];
+ SDLHMIPermissions *testHMIPermissionsUpdated = [[SDLHMIPermissions alloc] init];
+ testHMIPermissionsUpdated.allowed = @[SDLHMILevelBackground, SDLHMILevelFull];
+ testHMIPermissionsUpdated.userDisallowed = @[SDLHMILevelLimited, SDLHMILevelNone];
+
+ testPermissionUpdated = [[SDLPermissionItem alloc] init];
+ testPermissionUpdated.rpcName = testRPCNameAllAllowed;
+ testPermissionUpdated.hmiPermissions = testHMIPermissionsUpdated;
+ testPermissionUpdated.parameterPermissions = testParameterPermissions;
+
+ testPermissionChangeUpdate = [[SDLOnPermissionsChange alloc] init];
+ testPermissionChangeUpdate.permissionItem = [NSArray arrayWithObject:testPermissionUpdated];
+
+ // Send the permission update
+ SDLRPCNotificationNotification *updatedNotification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangePermissionsNotification object:nil rpcNotification:testPermissionChangeUpdate];
+ [[NSNotificationCenter defaultCenter] postNotification:updatedNotification];
+ });
+
+ it(@"should call the observer once", ^{
+ expect(@(numberOfTimesObserverCalled)).to(equal(@1));
+ });
+
+ // Since we are not sending the immediate callback, there will only be one change dict
+ // values in the change dict will be no, since we are disallowing the RPC
+// it(@"should have proper data in the first change dict", ^{
+// expect(changeDicts[0].allKeys).to(contain(testRPCNameAllAllowed));
+// expect(changeDicts[0].allKeys).to(contain(testRPCNameAllDisallowed));
+//
+// NSNumber<SDLBool> *allAllowed = changeDicts[0][testRPCNameAllAllowed];
+// expect(allAllowed).to(equal(@NO));
+//
+// NSNumber<SDLBool> *allDisallowed = changeDicts[0][testRPCNameAllDisallowed];
+// expect(allDisallowed).to(equal(@NO));
+// });
+
+ it(@"should have the proper data in the first change dict", ^{
+ expect(changeDicts[0].allKeys).to(contain(testRPCNameAllAllowed));
+ expect(changeDicts[0].allKeys).to(contain(testRPCNameAllDisallowed));
+
+ NSNumber<SDLBool> *allAllowed = changeDicts[1][testRPCNameAllAllowed];
+ expect(allAllowed).to(equal(@NO));
+
+ NSNumber<SDLBool> *allDisallowed = changeDicts[1][testRPCNameAllDisallowed];
+ expect(allDisallowed).to(equal(@NO));
+ });
+
+ describe(@"when the permission has not changed", ^{
+ __block SDLOnPermissionsChange *testPermissionChangeUpdateNoChange = nil;
+ __block SDLPermissionItem *testPermissionUpdatedNoChange = nil;
+
+ beforeEach(^{
+ numberOfTimesObserverCalled = 0;
+
+ // Create a permission update disallowing our current HMI level for the observed permission
+ SDLParameterPermissions *testParameterPermissions = [[SDLParameterPermissions alloc] init];
+ SDLHMIPermissions *testHMIPermissionsUpdated = [[SDLHMIPermissions alloc] init];
+ testHMIPermissionsUpdated.allowed = @[SDLHMILevelBackground, SDLHMILevelFull];
+ testHMIPermissionsUpdated.userDisallowed = @[SDLHMILevelLimited, SDLHMILevelNone];
+
+ testPermissionUpdatedNoChange = [[SDLPermissionItem alloc] init];
+ testPermissionUpdatedNoChange.rpcName = testRPCNameAllAllowed;
+ testPermissionUpdatedNoChange.hmiPermissions = testHMIPermissionsUpdated;
+ testPermissionUpdatedNoChange.parameterPermissions = testParameterPermissions;
+
+ testPermissionChangeUpdateNoChange = [[SDLOnPermissionsChange alloc] init];
+ testPermissionChangeUpdateNoChange.permissionItem = [NSArray arrayWithObject:testPermissionUpdated];
+
+ // Send the permission update
+ SDLRPCNotificationNotification *updatedNotification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangePermissionsNotification object:nil rpcNotification:testPermissionChangeUpdate];
+ [[NSNotificationCenter defaultCenter] postNotification:updatedNotification];
+ });
+
+ it(@"should not call the filter observer again", ^{
+ expect(numberOfTimesObserverCalled).to(equal(0));
+ });
+ });
+ });
+
+ context(@"to match an all allowed observer", ^{
+ beforeEach(^{
+ // Reset vars
+ numberOfTimesObserverCalled = 0;
+ changeDicts = [NSMutableArray array];
+ testStatuses = [NSMutableArray array];
+
+ // Post the notification before setting the observer to make sure data is already present
+ // HMI Full & Limited allowed, hmi level BACKGROUND
+ [[NSNotificationCenter defaultCenter] postNotification:backgroundHMINotification];
+ [[NSNotificationCenter defaultCenter] postNotification:testPermissionsNotification];
+ });
+
+ context(@"so that it becomes All Allowed", ^{
+ beforeEach(^{
+ // Set an observer that should be called immediately for the preexisting data, then called again when new data is sent
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameAllDisallowed, testRPCNameFullLimitedBackgroundAllowed] groupType:SDLPermissionGroupTypeAllAllowed withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber *> * _Nonnull change, SDLPermissionGroupStatus status) {
+ numberOfTimesObserverCalled++;
+ [changeDicts addObject:change];
+ [testStatuses addObject:@(status)];
+ }];
+
+ // Create a permission update allowing our current HMI level for the observed permission
+ SDLParameterPermissions *testParameterPermissions = [[SDLParameterPermissions alloc] init];
+ SDLHMIPermissions *testHMIPermissionsUpdated = [[SDLHMIPermissions alloc] init];
+ testHMIPermissionsUpdated.allowed = @[SDLHMILevelLimited, SDLHMILevelNone, SDLHMILevelBackground, SDLHMILevelFull];
+ testHMIPermissionsUpdated.userDisallowed = @[];
+
+ testPermissionUpdated = [[SDLPermissionItem alloc] init];
+ testPermissionUpdated.rpcName = testRPCNameAllDisallowed;
+ testPermissionUpdated.hmiPermissions = testHMIPermissionsUpdated;
+ testPermissionUpdated.parameterPermissions = testParameterPermissions;
+
+ testPermissionChangeUpdate = [[SDLOnPermissionsChange alloc] init];
+ testPermissionChangeUpdate.permissionItem = [NSArray arrayWithObject:testPermissionUpdated];
+
+ // Send the permission update
+ SDLRPCNotificationNotification *updatedNotification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangePermissionsNotification object:nil rpcNotification:testPermissionChangeUpdate];
+ [[NSNotificationCenter defaultCenter] postNotification:updatedNotification];
+ });
+
+ it(@"should call the observer twice", ^{
+ expect(@(numberOfTimesObserverCalled)).to(equal(@1));
+ });
+
+ it(@"should have proper data in the first change dict", ^{
+ expect(changeDicts[0].allKeys).to(haveCount(@2));
+ expect(testStatuses[0]).to(equal(@(SDLPermissionGroupStatusMixed)));
+ });
+
+ it(@"should have the proper data in the second change dict", ^{
+ expect(changeDicts[1].allKeys).to(haveCount(@2));
+ expect(testStatuses[1]).to(equal(@(SDLPermissionGroupStatusAllowed)));
+ });
+ });
+
+ context(@"so that it goes from All Allowed to mixed", ^{
+ beforeEach(^{
+ // Set an observer that should be called immediately for the preexisting data, then called again when new data is sent
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameAllAllowed] groupType:SDLPermissionGroupTypeAllAllowed withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber *> * _Nonnull change, SDLPermissionGroupStatus status) {
+ numberOfTimesObserverCalled++;
+ [changeDicts addObject:change];
+ [testStatuses addObject:@(status)];
+ }];
+
+ // Create a permission update disallowing our current HMI level for the observed permission
+ SDLParameterPermissions *testParameterPermissions = [[SDLParameterPermissions alloc] init];
+ SDLHMIPermissions *testHMIPermissionsUpdated = [[SDLHMIPermissions alloc] init];
+ testHMIPermissionsUpdated.allowed = @[];
+ testHMIPermissionsUpdated.userDisallowed = @[SDLHMILevelBackground, SDLHMILevelFull, SDLHMILevelLimited, SDLHMILevelNone];
+
+ testPermissionUpdated = [[SDLPermissionItem alloc] init];
+ testPermissionUpdated.rpcName = testRPCNameAllAllowed;
+ testPermissionUpdated.hmiPermissions = testHMIPermissionsUpdated;
+ testPermissionUpdated.parameterPermissions = testParameterPermissions;
+
+ testPermissionChangeUpdate = [[SDLOnPermissionsChange alloc] init];
+ testPermissionChangeUpdate.permissionItem = [NSArray arrayWithObject:testPermissionUpdated];
+
+ // Send the permission update
+ SDLRPCNotificationNotification *updatedNotification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangePermissionsNotification object:nil rpcNotification:testPermissionChangeUpdate];
+ [[NSNotificationCenter defaultCenter] postNotification:updatedNotification];
+ });
+
+ it(@"should call the observer twice", ^{
+ expect(@(numberOfTimesObserverCalled)).to(equal(@2));
+ });
+
+ it(@"should have proper data in the first change dict", ^{
+ expect(testStatuses[0]).to(equal(@(SDLPermissionGroupStatusAllowed)));
+ expect(changeDicts[0].allKeys).to(contain(testRPCNameAllAllowed));
+
+ NSNumber<SDLBool> *isAllowed = changeDicts[0][testRPCNameAllAllowed];
+ expect(isAllowed).to(equal(@YES));
+ });
+
+ it(@"should have the proper data in the second change dict", ^{
+ expect(testStatuses[1]).to(equal(@(SDLPermissionGroupStatusDisallowed)));
+ expect(changeDicts[1].allKeys).to(contain(testRPCNameAllAllowed));
+
+ NSNumber<SDLBool> *isAllowed = changeDicts[1][testRPCNameAllAllowed];
+ expect(isAllowed).to(equal(@NO));
+ });
+ });
+ });
+
+ context(@"to not match an all allowed observer", ^{
+ beforeEach(^{
+ // Reset vars
+ numberOfTimesObserverCalled = 0;
+ changeDicts = [NSMutableArray array];
+ testStatuses = [NSMutableArray array];
+
+ // Post the notification before setting the observer to make sure data is already present
+ // HMI Full & Limited allowed, hmi level BACKGROUND
+ [[NSNotificationCenter defaultCenter] postNotification:backgroundHMINotification];
+ [[NSNotificationCenter defaultCenter] postNotification:testPermissionsNotification];
+ });
+
+ context(@"from mixed to disallowed", ^{
+ beforeEach(^{
+ // Set an observer that should be called immediately for the preexisting data, then called again when new data is sent
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameAllAllowed, testRPCNameAllDisallowed] groupType:SDLPermissionGroupTypeAllAllowed withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber *> * _Nonnull change, SDLPermissionGroupStatus status) {
+ numberOfTimesObserverCalled++;
+ [changeDicts addObject:change];
+ [testStatuses addObject:@(status)];
+ }];
+
+ // Create a permission update disallowing our current HMI level for the observed permission
+ SDLParameterPermissions *testParameterPermissions = [[SDLParameterPermissions alloc] init];
+ SDLHMIPermissions *testHMIPermissionsUpdated = [[SDLHMIPermissions alloc] init];
+ testHMIPermissionsUpdated.allowed = @[];
+ testHMIPermissionsUpdated.userDisallowed = @[SDLHMILevelBackground, SDLHMILevelFull, SDLHMILevelLimited, SDLHMILevelNone];
+
+ testPermissionUpdated = [[SDLPermissionItem alloc] init];
+ testPermissionUpdated.rpcName = testRPCNameAllAllowed;
+ testPermissionUpdated.hmiPermissions = testHMIPermissionsUpdated;
+ testPermissionUpdated.parameterPermissions = testParameterPermissions;
+
+ testPermissionChangeUpdate = [[SDLOnPermissionsChange alloc] init];
+ testPermissionChangeUpdate.permissionItem = [NSArray arrayWithObject:testPermissionUpdated];
+
+ // Send the permission update
+ SDLRPCNotificationNotification *updatedNotification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangePermissionsNotification object:nil rpcNotification:testPermissionChangeUpdate];
+ [[NSNotificationCenter defaultCenter] postNotification:updatedNotification];
+ });
+
+ it(@"should call the observer with a mixed status", ^{
+ expect(@(numberOfTimesObserverCalled)).to(equal(@1));
+ expect(testStatuses[0]).to(equal(@(SDLPermissionGroupStatusMixed)));
+ });
+ });
+
+ context(@"from disallowed to mixed", ^{
+ beforeEach(^{
+ // Set an observer that should be called immediately for the preexisting data, then called again when new data is sent
+ [testPermissionsManager addStrictObserverForRPCs:@[testRPCNameFullLimitedAllowed, testRPCNameAllDisallowed] groupType:SDLPermissionGroupTypeAllAllowed withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber *> * _Nonnull change, SDLPermissionGroupStatus status) {
+ numberOfTimesObserverCalled++;
+ [changeDicts addObject:change];
+ [testStatuses addObject:@(status)];
+ }];
+
+ // Create a permission update disallowing our current HMI level for the observed permission
+ SDLParameterPermissions *testParameterPermissions = [[SDLParameterPermissions alloc] init];
+ SDLHMIPermissions *testHMIPermissionsUpdated = [[SDLHMIPermissions alloc] init];
+ testHMIPermissionsUpdated.allowed = @[SDLHMILevelLimited, SDLHMILevelBackground];
+ testHMIPermissionsUpdated.userDisallowed = @[SDLHMILevelFull, SDLHMILevelNone];
+
+ testPermissionUpdated = [[SDLPermissionItem alloc] init];
+ testPermissionUpdated.rpcName = testRPCNameAllAllowed;
+ testPermissionUpdated.hmiPermissions = testHMIPermissionsUpdated;
+ testPermissionUpdated.parameterPermissions = testParameterPermissions;
+
+ testPermissionChangeUpdate = [[SDLOnPermissionsChange alloc] init];
+ testPermissionChangeUpdate.permissionItem = [NSArray arrayWithObject:testPermissionUpdated];
+
+ // Send the permission update
+ SDLRPCNotificationNotification *updatedNotification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangePermissionsNotification object:nil rpcNotification:testPermissionChangeUpdate];
+ [[NSNotificationCenter defaultCenter] postNotification:updatedNotification];
+ });
+
+ it(@"should call the observer", ^{
+ expect(@(numberOfTimesObserverCalled)).to(equal(@1));
+ expect(testStatuses[0]).to(equal(@(SDLPermissionGroupStatusDisallowed)));
+ });
+ });
+ });
+ });
+ });
+
+
+
+
+
+
+
+
+
+
+
+
+
describe(@"adding new observers", ^{
context(@"when no data is present", ^{
__block BOOL testObserverCalled = NO;