// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #import #import #import "OCTRealmTests.h" #import "OCTSubmanagerChatsImpl.h" #import "OCTRealmManager.h" #import "OCTTox.h" #import "OCTMessageAbstract.h" #import "OCTMessageText.h" @interface OCTSubmanagerChatsImplTests : OCTRealmTests @property (strong, nonatomic) OCTSubmanagerChatsImpl *submanager; @property (strong, nonatomic) NSNotificationCenter *notificationCenter; @property (strong, nonatomic) id dataSource; @property (strong, nonatomic) id tox; @end @implementation OCTSubmanagerChatsImplTests - (void)setUp { [super setUp]; self.notificationCenter = [[NSNotificationCenter alloc] init]; self.dataSource = OCMProtocolMock(@protocol(OCTSubmanagerDataSource)); OCMStub([self.dataSource managerGetNotificationCenter]).andReturn(self.notificationCenter); OCMStub([self.dataSource managerGetRealmManager]).andReturn(self.realmManager); self.tox = OCMClassMock([OCTTox class]); OCMStub([self.dataSource managerGetTox]).andReturn(self.tox); self.submanager = [OCTSubmanagerChatsImpl new]; self.submanager.dataSource = self.dataSource; [self.submanager configure]; } - (void)tearDown { self.dataSource = nil; self.tox = nil; self.submanager = nil; // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testGetOrCreateChatWithFriend { OCTFriend *friend = [self createFriendWithFriendNumber:5]; [self.realmManager.realm beginWriteTransaction]; [self.realmManager.realm addObject:friend]; [self.realmManager.realm commitWriteTransaction]; OCTChat *first = [self.realmManager getOrCreateChatWithFriend:friend]; OCTChat *second = [self.realmManager getOrCreateChatWithFriend:friend]; XCTAssertEqualObjects(first, second); XCTAssertEqualObjects([first.friends firstObject], friend); } - (void)testRemoveMessages { XCTestExpectation *expect = [self expectationWithDescription:@""]; [self.notificationCenter addObserverForName:kOCTScheduleFileTransferCleanupNotification object:nil queue:nil usingBlock:^(NSNotification *note) { [expect fulfill]; }]; NSArray *messages = [NSArray new]; OCMExpect([self.realmManager removeMessages:messages]); [self.submanager removeMessages:messages]; [self waitForExpectationsWithTimeout:0.0 handler:nil]; OCMVerifyAll((id)self.realmManager); } - (void)testRemoveMessagesWithChat { XCTestExpectation *expect = [self expectationWithDescription:@""]; [self.notificationCenter addObserverForName:kOCTScheduleFileTransferCleanupNotification object:nil queue:nil usingBlock:^(NSNotification *note) { [expect fulfill]; }]; OCTChat *chat = [OCTChat new]; OCMExpect([self.realmManager removeAllMessagesInChat:chat removeChat:YES]); [self.submanager removeAllMessagesInChat:chat removeChat:YES]; [self waitForExpectationsWithTimeout:0.0 handler:nil]; OCMVerifyAll((id)self.realmManager); } - (void)testSendMessageToChatSuccess { id message = OCMClassMock([OCTMessageAbstract class]); id friend = OCMClassMock([OCTFriend class]); OCMStub([friend friendNumber]).andReturn(5); NSArray *friends = @[friend]; id chat = OCMClassMock([OCTChat class]); OCMStub([chat friends]).andReturn(friends); OCMStub([self.tox sendMessageWithFriendNumber:5 type:OCTToxMessageTypeAction message:@"text" error:[OCMArg anyObjectRef]]).andReturn(7); OCMExpect([self.realmManager addMessageWithText:@"text" type:OCTToxMessageTypeAction chat:chat sender:nil messageId:7]).andReturn(message); XCTestExpectation *expectation = [self expectationWithDescription:@""]; [self.submanager sendMessageToChat:chat text:@"text" type:OCTToxMessageTypeAction successBlock:^(OCTMessageAbstract *theMessage) { OCMVerifyAll((id)self.realmManager); XCTAssertEqualObjects(message, theMessage); [expectation fulfill]; } failureBlock:^(NSError *error) { XCTAssertTrue(false, @"This block shouldn't be called"); }]; [self waitForExpectationsWithTimeout:0.2 handler:nil]; } - (void)testSendMessageToChatFailure { id friend = OCMClassMock([OCTFriend class]); OCMStub([friend friendNumber]).andReturn(5); NSArray *friends = @[friend]; id chat = OCMClassMock([OCTChat class]); OCMStub([chat friends]).andReturn(friends); NSError *error2 = OCMClassMock([NSError class]); OCMStub([self.tox sendMessageWithFriendNumber:5 type:OCTToxMessageTypeAction message:@"text" error:[OCMArg setTo:error2]]).andReturn(0); XCTestExpectation *expectation = [self expectationWithDescription:@""]; [self.submanager sendMessageToChat:chat text:@"text" type:OCTToxMessageTypeAction successBlock:^(OCTMessageAbstract *theMessage) { XCTAssertTrue(false, @"This block shouldn't be called"); } failureBlock:^(NSError *error) { OCMVerifyAll((id)self.realmManager); XCTAssertEqualObjects(error, error2); [expectation fulfill]; }]; [self waitForExpectationsWithTimeout:0.2 handler:nil]; } - (void)testSendMessageToChatFauxEnabled { OCMStub([self.dataSource managerUseFauxOfflineMessaging]).andReturn(YES); id message = OCMClassMock([OCTMessageAbstract class]); id friend = OCMClassMock([OCTFriend class]); OCMStub([friend friendNumber]).andReturn(5); NSArray *friends = @[friend]; id chat = OCMClassMock([OCTChat class]); OCMStub([chat friends]).andReturn(friends); NSError *error2 = OCMClassMock([NSError class]); OCMStub(error2.code).andReturn(OCTToxErrorFriendSendMessageFriendNotConnected); OCMStub([self.tox sendMessageWithFriendNumber:5 type:OCTToxMessageTypeAction message:@"text" error:[OCMArg setTo:error2]]).andReturn(0); OCMExpect([self.realmManager addMessageWithText:@"text" type:OCTToxMessageTypeAction chat:chat sender:nil messageId:-1]).andReturn(message); XCTestExpectation *expectation = [self expectationWithDescription:@""]; [self.submanager sendMessageToChat:chat text:@"text" type:OCTToxMessageTypeAction successBlock:^(OCTMessageAbstract *theMessage) { OCMVerifyAll((id)self.realmManager); XCTAssertEqualObjects(message, theMessage); [expectation fulfill]; } failureBlock:^(NSError *error) { XCTAssertTrue(false, @"This block shouldn't be called"); }]; [self waitForExpectationsWithTimeout:0.2 handler:nil]; } - (void)testSendMessageToChatFauxDisabled { OCMStub([self.dataSource managerUseFauxOfflineMessaging]).andReturn(NO); id friend = OCMClassMock([OCTFriend class]); OCMStub([friend friendNumber]).andReturn(5); NSArray *friends = @[friend]; id chat = OCMClassMock([OCTChat class]); OCMStub([chat friends]).andReturn(friends); NSError *error2 = OCMClassMock([NSError class]); OCMStub(error2.code).andReturn(OCTToxErrorFriendSendMessageFriendNotConnected); OCMStub([self.tox sendMessageWithFriendNumber:5 type:OCTToxMessageTypeAction message:@"text" error:[OCMArg setTo:error2]]).andReturn(0); XCTestExpectation *expectation = [self expectationWithDescription:@""]; [self.submanager sendMessageToChat:chat text:@"text" type:OCTToxMessageTypeAction successBlock:^(OCTMessageAbstract *theMessage) { XCTAssertTrue(false, @"This block shouldn't be called"); } failureBlock:^(NSError *error) { OCMVerifyAll((id)self.realmManager); XCTAssertEqualObjects(error, error2); [expectation fulfill]; }]; [self waitForExpectationsWithTimeout:0.2 handler:nil]; } - (void)testSetIsTyping { id friend = OCMClassMock([OCTFriend class]); OCMStub([friend friendNumber]).andReturn(5); NSArray *friends = @[friend]; id chat = OCMClassMock([OCTChat class]); OCMStub([chat friends]).andReturn(friends); NSError *error; NSError *error2 = OCMClassMock([NSError class]); OCMExpect([self.tox setUserIsTyping:YES forFriendNumber:5 error:[OCMArg setTo:error2]]).andReturn(NO); XCTAssertFalse([self.submanager setIsTyping:YES inChat:chat error:&error]); XCTAssertEqual(error, error2); OCMVerifyAll(self.tox); } - (void)testResendUndeliveredMessages { NSArray * (^createMessages)(OCTChat *, OCTToxMessageId) = ^(OCTChat *chat, OCTToxMessageId number) { NSMutableArray *array = [NSMutableArray new]; for (OCTToxMessageId index = 0; index < number; index++) { BOOL outgoing = index % 2; OCTMessageAbstract *message = [self createTextMessageInChat:chat outgoing:outgoing messageId:index]; [array addObject:message]; } return [array copy]; }; OCTToxFriendNumber friendNumber = 1; OCTFriend *friend1 = [self createFriendWithFriendNumber:friendNumber++]; OCTFriend *friend2 = [self createFriendWithFriendNumber:friendNumber++]; NSString *publicKey1 = friend1.publicKey; NSString *publicKey2 = friend2.publicKey; OCMStub([self.tox publicKeyFromFriendNumber:friend1.friendNumber error:nil]).andReturn(publicKey1); OCMStub([self.tox publicKeyFromFriendNumber:friend2.friendNumber error:nil]).andReturn(publicKey2); OCTChat *chat1 = [self createChatWithFriend:friend1]; OCTChat *chat2 = [self createChatWithFriend:friend2]; NSArray *messages1 = createMessages(chat1, 10); NSArray *messages2 = createMessages(chat2, 2); [self.realmManager.realm beginWriteTransaction]; [self.realmManager.realm addObject:chat1]; [self.realmManager.realm addObject:chat2]; [self.realmManager.realm addObjects:messages1]; [self.realmManager.realm addObjects:messages2]; [self.realmManager.realm commitWriteTransaction]; OCMStub([self.tox sendMessageWithFriendNumber:1 type:OCTToxMessageTypeNormal message:@"1" error:[OCMArg anyObjectRef]]).andReturn(101); OCMStub([self.tox sendMessageWithFriendNumber:1 type:OCTToxMessageTypeNormal message:@"3" error:[OCMArg anyObjectRef]]).andReturn(103); OCMStub([self.tox sendMessageWithFriendNumber:1 type:OCTToxMessageTypeNormal message:@"5" error:[OCMArg anyObjectRef]]).andReturn(105); OCMStub([self.tox sendMessageWithFriendNumber:1 type:OCTToxMessageTypeNormal message:@"7" error:[OCMArg anyObjectRef]]).andReturn(107); OCMStub([self.tox sendMessageWithFriendNumber:1 type:OCTToxMessageTypeNormal message:@"9" error:[OCMArg anyObjectRef]]).andReturn(109); [self.realmManager.realm beginWriteTransaction]; friend1.connectionStatus = OCTToxConnectionStatusUDP; friend1.isConnected = YES; [self.realmManager.realm commitWriteTransaction]; [self.notificationCenter postNotificationName:kOCTFriendConnectionStatusChangeNotification object:friend1]; #define VERIFY_MESSAGE(__array, __index, __messageId, __delivered) \ { \ NSString *identifier = [__array[__index] uniqueIdentifier]; \ OCTMessageAbstract *message = [self.realmManager objectWithUniqueIdentifier:identifier class:[OCTMessageAbstract class]]; \ XCTAssertEqual(message.messageText.messageId, __messageId); \ XCTAssertEqual(message.messageText.isDelivered, __delivered); \ } XCTestExpectation *expectation = [self expectationWithDescription:@""]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ VERIFY_MESSAGE(messages1, 0, 0, NO); VERIFY_MESSAGE(messages1, 1, 101, NO); VERIFY_MESSAGE(messages1, 2, 2, NO); VERIFY_MESSAGE(messages1, 3, 103, NO); VERIFY_MESSAGE(messages1, 4, 4, NO); VERIFY_MESSAGE(messages1, 5, 105, NO); VERIFY_MESSAGE(messages1, 6, 6, NO); VERIFY_MESSAGE(messages1, 7, 107, NO); VERIFY_MESSAGE(messages1, 8, 8, NO); VERIFY_MESSAGE(messages1, 9, 109, NO); VERIFY_MESSAGE(messages2, 0, 0, NO); VERIFY_MESSAGE(messages2, 1, 1, NO); [expectation fulfill]; }); [self waitForExpectationsWithTimeout:0.3 handler:nil]; // Deliver some messages, then resend all left again. [self.submanager tox:self.tox messageDelivered:101 friendNumber:1]; [self.submanager tox:self.tox messageDelivered:103 friendNumber:1]; [self.submanager tox:self.tox messageDelivered:105 friendNumber:1]; { OCTMessageAbstract *message; [self.realmManager.realm beginWriteTransaction]; message = messages1[7]; message.messageText.text = @"107"; message = messages1[9]; message.messageText.text = @"109"; [self.realmManager.realm commitWriteTransaction]; } OCMStub([self.tox sendMessageWithFriendNumber:1 type:OCTToxMessageTypeNormal message:@"107" error:[OCMArg anyObjectRef]]).andReturn(207); OCMStub([self.tox sendMessageWithFriendNumber:1 type:OCTToxMessageTypeNormal message:@"109" error:[OCMArg anyObjectRef]]).andReturn(209); [self.notificationCenter postNotificationName:kOCTFriendConnectionStatusChangeNotification object:friend1]; XCTestExpectation *expectation2 = [self expectationWithDescription:@""]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ VERIFY_MESSAGE(messages1, 0, 0, NO); VERIFY_MESSAGE(messages1, 1, 101, YES); VERIFY_MESSAGE(messages1, 2, 2, NO); VERIFY_MESSAGE(messages1, 3, 103, YES); VERIFY_MESSAGE(messages1, 4, 4, NO); VERIFY_MESSAGE(messages1, 5, 105, YES); VERIFY_MESSAGE(messages1, 6, 6, NO); VERIFY_MESSAGE(messages1, 7, 207, NO); VERIFY_MESSAGE(messages1, 8, 8, NO); VERIFY_MESSAGE(messages1, 9, 209, NO); VERIFY_MESSAGE(messages2, 0, 0, NO); VERIFY_MESSAGE(messages2, 1, 1, NO); [expectation2 fulfill]; }); [self waitForExpectationsWithTimeout:0.3 handler:nil]; } #pragma mark - OCTToxDelegate - (void)testFriendMessage { OCTFriend *friend = [self createFriendWithFriendNumber:5]; NSString *publicKey = friend.publicKey; OCMStub([self.tox publicKeyFromFriendNumber:friend.friendNumber error:nil]).andReturn(publicKey); OCTChat *chat = [OCTChat new]; [chat.friends addObject:friend]; [self.realmManager.realm beginWriteTransaction]; [self.realmManager.realm addObject:chat]; [self.realmManager.realm commitWriteTransaction]; [self.submanager tox:nil friendMessage:@"message" type:OCTToxMessageTypeAction friendNumber:5]; RLMResults *results = [OCTMessageAbstract allObjectsInRealm:self.realmManager.realm]; XCTAssertEqual(results.count, 1); OCTMessageAbstract *message = [results firstObject]; XCTAssertEqualObjects(message.senderUniqueIdentifier, friend.uniqueIdentifier); XCTAssertEqualObjects(message.chatUniqueIdentifier, chat.uniqueIdentifier); XCTAssertNotNil(message.messageText); XCTAssertEqualObjects(message.messageText.text, @"message"); XCTAssertEqual(message.messageText.type, OCTToxMessageTypeAction); } - (void)testMessageDelivered { OCTFriend *friend = [self createFriendWithFriendNumber:5]; NSString *publicKey = friend.publicKey; OCMStub([self.tox publicKeyFromFriendNumber:friend.friendNumber error:nil]).andReturn(publicKey); OCTChat *chat = [OCTChat new]; [chat.friends addObject:friend]; OCTMessageAbstract *message = [OCTMessageAbstract new]; message.chatUniqueIdentifier = chat.uniqueIdentifier; message.dateInterval = [[NSDate date] timeIntervalSince1970]; message.messageText = [OCTMessageText new]; message.messageText.text = @""; message.messageText.messageId = 10; message.messageText.isDelivered = NO; [self.realmManager.realm beginWriteTransaction]; [self.realmManager.realm addObject:friend]; [self.realmManager.realm addObject:chat]; [self.realmManager.realm addObject:message]; [self.realmManager.realm commitWriteTransaction]; [self.submanager tox:self.tox messageDelivered:10 friendNumber:5]; XCTAssertTrue(message.messageText.isDelivered); OCTMessageAbstract *anotherMessageSameId = [OCTMessageAbstract new]; anotherMessageSameId.chatUniqueIdentifier = chat.uniqueIdentifier; anotherMessageSameId.dateInterval = [[NSDate date] timeIntervalSince1970]; anotherMessageSameId.messageText = [OCTMessageText new]; anotherMessageSameId.messageText.text = @""; anotherMessageSameId.messageText.messageId = 10; anotherMessageSameId.messageText.isDelivered = NO; [self.realmManager.realm beginWriteTransaction]; [self.realmManager.realm addObject:anotherMessageSameId]; [self.realmManager.realm commitWriteTransaction]; [self.submanager tox:self.tox messageDelivered:10 friendNumber:5]; XCTAssertTrue(anotherMessageSameId.messageText.isDelivered); } - (OCTChat *)createChatWithFriend:(OCTFriend *)friend { OCTChat *chat = [OCTChat new]; [chat.friends addObject:friend]; return chat; } - (OCTMessageAbstract *)createTextMessageInChat:(OCTChat *)chat outgoing:(BOOL)outgoing messageId:(OCTToxMessageId)messageId { OCTMessageAbstract *message = [OCTMessageAbstract new]; message.chatUniqueIdentifier = chat.uniqueIdentifier; message.messageText = [OCTMessageText new]; message.messageText.text = [NSString stringWithFormat:@"%d", messageId]; message.messageText.messageId = messageId; if (! outgoing) { OCTFriend *friend = chat.friends.lastObject; message.senderUniqueIdentifier = friend.uniqueIdentifier; } return message; } @end