diff --git a/Example/mParticleExample/ViewController.m b/Example/mParticleExample/ViewController.m index 9c10f845..76b4e4fd 100644 --- a/Example/mParticleExample/ViewController.m +++ b/Example/mParticleExample/ViewController.m @@ -111,9 +111,11 @@ - (void)logEvent { MPEvent *event = [[MPEvent alloc] initWithName:@"Event Name" type:MPEventTypeTransaction]; // Add attributes to an event + NSDate *currentDate = [NSDate dateWithTimeIntervalSinceNow:0]; event.customAttributes = @{@"A_String_Key":@"A String Value", - @"A Number Key":@(42), - @"A Date Key":[NSDate date]}; + @"A Number Key":@(42), + @"A Date Key":[NSDate date], + @"test Dictionary": @{@"test1": @"test", @"test2": @2, @"test3": currentDate}}; // Custom flags are attributes sent to mParticle, but not forwarded to other providers [event addCustomFlag:@"Top Secret" withKey:@"Not_forwarded_to_providers"]; diff --git a/UnitTests/MPEventTests.mm b/UnitTests/MPEventTests.mm index a14dd96e..d0f5df4c 100644 --- a/UnitTests/MPEventTests.mm +++ b/UnitTests/MPEventTests.mm @@ -47,7 +47,8 @@ - (void)testInstance { } NSDictionary *eventInfo = @{@"speed":@25, - @"modality":@"sprinting"}; + @"modality":@"sprinting", + @"stats":@{}}; event.customAttributes = eventInfo; event.category = @"Olympic Games"; @@ -86,8 +87,8 @@ - (void)testInstance { XCTAssertNotNil(event.customAttributes, @"Should not have been nil."); XCTAssertNotNil(event.info, @"Should not have been nil."); - XCTAssertEqual(event.customAttributes.count, 2, @"Should have been two values in the customAttributes dictionary."); - XCTAssertEqual(event.info.count, 2, @"Should have been two values in the info dictionary."); + XCTAssertEqual(event.customAttributes.count, 3, @"Should have been three values in the customAttributes dictionary."); + XCTAssertEqual(event.info.count, 3, @"Should have been three values in the info dictionary."); NSDictionary *copyEventInfo = [eventInfo copy]; event.customAttributes = copyEventInfo; @@ -163,7 +164,78 @@ - (void)testDictionaryRepresentation { MPEvent *event = [[MPEvent alloc] initWithName:@"Dinosaur Run" type:MPEventTypeOther]; event.duration = eventDuration; event.customAttributes = @{@"speed":@25, - @"modality":@"sprinting"}; + @"modality":@"sprinting", + @"stats":@{}}; + event.category = @"Olympic Games"; + + [session incrementCounter]; + [session incrementCounter]; + [session incrementCounter]; + + NSDictionary *dictionaryRepresentation = [event dictionaryRepresentation]; + XCTAssertNotNil(dictionaryRepresentation, @"Dictionary representation should not have been nil."); + XCTAssertEqualObjects(dictionaryRepresentation[kMPEventNameKey], @"Dinosaur Run", @"Name is not correct."); + XCTAssertNotNil(dictionaryRepresentation[kMPEventStartTimestamp], @"Start timestamp should not have been nil."); + XCTAssertEqualObjects(dictionaryRepresentation[kMPEventTypeKey], @"Other", @"Type should have been 'Other.'"); + XCTAssertEqualObjects(dictionaryRepresentation[kMPEventLength], @2, @"Length should have been 2."); + XCTAssertEqualObjects(dictionaryRepresentation[kMPEventCounterKey], @3, @"Event counter should have been 3."); + + NSDictionary *attributes = @{@"speed":@25, + @"modality":@"sprinting", + @"stats":@{}, + @"$Category":@"Olympic Games", + @"EventLength":eventDuration}; + XCTAssertEqualObjects(dictionaryRepresentation[kMPAttributesKey], attributes, @"Attributes are not being set correctly."); +} + +- (void)testDictionaryRepresentationWithDictionaryValues { + MPSession *session = [[MPSession alloc] initWithStartTime:[[NSDate date] timeIntervalSince1970] userId:[MPPersistenceController mpId]]; + MPStateMachine *stateMachine = [MParticle sharedInstance].stateMachine; + stateMachine.currentSession = session; + + NSNumber *eventDuration = @2; + + MPEvent *event = [[MPEvent alloc] initWithName:@"Dinosaur Run" type:MPEventTypeOther]; + event.duration = eventDuration; + NSDate *currentDate = [NSDate dateWithTimeIntervalSinceNow:0]; + event.customAttributes = @{@"speed":@25, + @"modality":@"sprinting", + @"stats":@{@"test1": @"test", @"test2": @2, @"test3": currentDate}}; + event.category = @"Olympic Games"; + + [session incrementCounter]; + [session incrementCounter]; + [session incrementCounter]; + + NSDictionary *dictionaryRepresentation = [event dictionaryRepresentation]; + XCTAssertNotNil(dictionaryRepresentation, @"Dictionary representation should not have been nil."); + XCTAssertEqualObjects(dictionaryRepresentation[kMPEventNameKey], @"Dinosaur Run", @"Name is not correct."); + XCTAssertNotNil(dictionaryRepresentation[kMPEventStartTimestamp], @"Start timestamp should not have been nil."); + XCTAssertEqualObjects(dictionaryRepresentation[kMPEventTypeKey], @"Other", @"Type should have been 'Other.'"); + XCTAssertEqualObjects(dictionaryRepresentation[kMPEventLength], @2, @"Length should have been 2."); + XCTAssertEqualObjects(dictionaryRepresentation[kMPEventCounterKey], @3, @"Event counter should have been 3."); + + NSDictionary *attributes = @{@"speed":@25, + @"modality":@"sprinting", + @"stats":@{@"test1": @"test", @"test2": @2, @"test3": currentDate}, + @"$Category":@"Olympic Games", + @"EventLength":eventDuration}; + XCTAssertEqualObjects(dictionaryRepresentation[kMPAttributesKey], attributes, @"Attributes are not being set correctly."); +} + +- (void)testDictionaryRepresentationWithDictionaryValuesContainingDictionary { + MPSession *session = [[MPSession alloc] initWithStartTime:[[NSDate date] timeIntervalSince1970] userId:[MPPersistenceController mpId]]; + MPStateMachine *stateMachine = [MParticle sharedInstance].stateMachine; + stateMachine.currentSession = session; + + NSNumber *eventDuration = @2; + + MPEvent *event = [[MPEvent alloc] initWithName:@"Dinosaur Run" type:MPEventTypeOther]; + event.duration = eventDuration; + NSDate *currentDate = [NSDate dateWithTimeIntervalSinceNow:0]; + event.customAttributes = @{@"speed":@25, + @"modality":@"sprinting", + @"stats":@{@"test1": @"test", @"test2": @2, @"test3": currentDate}, @"test3": @{@"test1": @"test", @"test2": @2}}; event.category = @"Olympic Games"; [session incrementCounter]; @@ -180,6 +252,7 @@ - (void)testDictionaryRepresentation { NSDictionary *attributes = @{@"speed":@25, @"modality":@"sprinting", + @"stats":@{@"test1": @"test", @"test2": @2, @"test3": currentDate}, @"test3": @{@"test1": @"test", @"test2": @2}, @"$Category":@"Olympic Games", @"EventLength":eventDuration}; XCTAssertEqualObjects(dictionaryRepresentation[kMPAttributesKey], attributes, @"Attributes are not being set correctly."); diff --git a/mParticle-Apple-SDK/Utils/NSDictionary+MPCaseInsensitive.m b/mParticle-Apple-SDK/Utils/NSDictionary+MPCaseInsensitive.m index 3dd37484..1ba17053 100644 --- a/mParticle-Apple-SDK/Utils/NSDictionary+MPCaseInsensitive.m +++ b/mParticle-Apple-SDK/Utils/NSDictionary+MPCaseInsensitive.m @@ -70,6 +70,14 @@ - (id)valueForCaseInsensitiveKey:(NSString *)key { transformedDictionary[key] = [MPDateFormatter stringFromDateRFC3339:obj]; } else if ([obj isKindOfClass:[NSData class]] && [(NSData *)obj length] > 0) { transformedDictionary[key] = [[NSString alloc] initWithData:obj encoding:NSUTF8StringEncoding]; + } else if ([obj isKindOfClass:[NSDictionary class]]) { + transformedDictionary[key] = [obj description]; + } else if ([obj isKindOfClass:[NSMutableDictionary class]]) { + transformedDictionary[key] = [obj description]; + } else if ([obj isKindOfClass:[NSArray class]]) { + transformedDictionary[key] = [obj description]; + } else if ([obj isKindOfClass:[NSMutableArray class]]) { + transformedDictionary[key] = [obj description]; } else { MPILogError(@"Data type is not supported as an attribute value: %@ - %@", obj, [[obj class] description]); NSAssert([obj isKindOfClass:[NSString class]], @"Data type is not supported as an attribute value");