ComponentKitTests/TransactionalDataSource/CKDataSourceAppliedChangesTests.mm (923 lines of code) (raw):

/* * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #import <XCTest/XCTest.h> #import <UIKit/UIKit.h> #import <ComponentKit/CKDataSourceAppliedChanges.h> #import <ComponentKitTestHelpers/CKChangesetHelpers.h> using namespace CK; @interface CKDataSourceAppliedChangesTests : XCTestCase @end @implementation CKDataSourceAppliedChangesTests - (void)testAppliedChangesEquality { CKDataSourceAppliedChanges *firstAppliedChanges = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedSections:[NSIndexSet indexSetWithIndex:2] movedIndexPaths:@{ [NSIndexPath indexPathForItem:3 inSection:0] : [NSIndexPath indexPathForItem:4 inSection:0] } insertedSections:[NSIndexSet indexSetWithIndex:1] insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:5 inSection:0]] userInfo:@{ @"key" : @"value"}]; CKDataSourceAppliedChanges *secondAppliedChanges = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedSections:[NSIndexSet indexSetWithIndex:2] movedIndexPaths:@{ [NSIndexPath indexPathForItem:3 inSection:0] : [NSIndexPath indexPathForItem:4 inSection:0] } insertedSections:[NSIndexSet indexSetWithIndex:1] insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:5 inSection:0]] userInfo:@{ @"key" : @"value"}]; XCTAssertEqualObjects(firstAppliedChanges, secondAppliedChanges); } - (void)testNonEqualAppliedChanges { CKDataSourceAppliedChanges *firstAppliedChanges = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedSections:[NSIndexSet indexSetWithIndex:2] movedIndexPaths:@{ [NSIndexPath indexPathForItem:3 inSection:0] : [NSIndexPath indexPathForItem:4 inSection:0] } insertedSections:[NSIndexSet indexSetWithIndex:1] insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:5 inSection:0]] userInfo:@{ @"key" : @"value"}]; CKDataSourceAppliedChanges *secondAppliedChanges = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedSections:[NSIndexSet indexSetWithIndex:2] movedIndexPaths:@{ [NSIndexPath indexPathForItem:3 inSection:0] : [NSIndexPath indexPathForItem:4 inSection:0] } insertedSections:[NSIndexSet indexSetWithIndex:1] insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:5 inSection:0]] userInfo:@{ @"key2" : @"value2"}]; XCTAssertNotEqualObjects(firstAppliedChanges, secondAppliedChanges); } #pragma mark - Empty changeset - (void)testEmptyChangeset { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:nil removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; XCTAssertEqual([[changes finalUpdatedIndexPaths] count], 0); } #pragma mark - Unaffected updates - (void)testUpdate_UnaffectedByInsertion_SameSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_UnaffectedByInsertion_DifferentSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:1]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_UnaffectedByInsertedSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndex:1] insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_UnaffectedByRemoval_SameSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_UnaffectedByRemoval_DifferentSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:1]] removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_UnaffectedByRemovedSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:[NSIndexSet indexSetWithIndex:1] movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_UnaffectedByOffsettingInsertionsAndRemovals { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_UnaffectedByMoveBefore_SameSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_UnaffectedByMoveAfter_SameSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:3 inSection:0] : [NSIndexPath indexPathForItem:4 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_UnaffectedByMoveAfter_FromDifferentSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:1 inSection:1] : [NSIndexPath indexPathForItem:4 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_UnaffectedByMoveAfter_ToDifferentSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:3 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:1] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_UnaffectedByTwoOffsettingMoves_SameSection { NSDictionary *moves = @{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:4 inSection:0], [NSIndexPath indexPathForItem:3 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:0]}; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:moves insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_UnaffectedByTwoOffsettingMoves_DifferentSections { NSDictionary *moves = @{ [NSIndexPath indexPathForItem:0 inSection:1] : [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:1]}; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:moves insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_UnaffectedByOffsettingInsertionAndMove { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:3 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:6 inSection:0] } insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:3 inSection:0]], [NSIndexPath indexPathForItem:3 inSection:0]); } - (void)testUpdate_UnaffectedByOffsettingRemovalAndMove { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:3 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:6 inSection:0] : [NSIndexPath indexPathForItem:0 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:3 inSection:0]], [NSIndexPath indexPathForItem:3 inSection:0]); } #pragma mark - Affected updates by single operation (with potentially multiple pieces, i.e. two insertions, but not an insertion and a removal) - (void)testUpdate_AffectedBySingleInsert { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_AffectedByMultipleDistinctInsertions { NSSet *insertions = [NSSet setWithArray:@[[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0]]]; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:insertions userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:3 inSection:0]); } - (void)testUpdate_AffectedByMultipleIdenticalInsertions { NSSet *insertions = [NSSet setWithArray:@[[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:0]]]; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:insertions userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); // NOTE: the indexpath's row is only increased by 1 because changesets deduplicate identical inserts XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_AffectedBySingleInsertedSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndex:0] insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:1 inSection:1]); } - (void)testUpdate_AffectedByMultipleInsertedSections { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:1]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)] insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:1]], [NSIndexPath indexPathForItem:1 inSection:3]); } - (void)testUpdate_AffectedBySingleRemoval { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:0]); } - (void)testUpdate_AffectedByMultipleDistinctRemovals { NSSet *removedIndexPaths = [NSSet setWithArray:@[[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0]]]; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:removedIndexPaths removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:0]); } - (void)testUpdate_AffectedByRemovingSingleSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:1]] removedIndexPaths:nil removedSections:[NSIndexSet indexSetWithIndex:0] movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:1]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_AffectedByRemovingMultipleSections { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:2]] removedIndexPaths:nil removedSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)] movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:2]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_AffectedByMultipleIdenticalRemovals { NSSet *removedIndexPaths = [NSSet setWithArray:@[[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:0]]]; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:removedIndexPaths removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:1 inSection:0]); } - (void)testUpdate_AffectedBySingleMove_SameSection_FromBeforeToAfter { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:2 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:0]); } - (void)testUpdate_AffectedBySingleMove_SameSection_FromAfterToBefore { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:2 inSection:0] : [NSIndexPath indexPathForItem:0 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_AffectedBySingleMove_IntoSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:2 inSection:1] : [NSIndexPath indexPathForItem:0 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:2 inSection:0]); } - (void)testUpdate_AffectedBySingleMove_OutOfSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:0 inSection:1] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:0]); } - (void)testUpdate_AffectedByMultipleMoves_SameSection_FromBeforeToAfter { NSDictionary *moves = @{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:3 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0] : [NSIndexPath indexPathForItem:4 inSection:0] }; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:moves insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:0]); } - (void)testUpdate_AffectedByMultipleMoves_SameSection_FromAfterToBefore { NSDictionary *moves = @{ [NSIndexPath indexPathForItem:3 inSection:0] : [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:4 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:0] }; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:moves insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:4 inSection:0]); } - (void)testUpdate_AffectedByMultipleMoves_IntoSection { NSDictionary *moves = @{ [NSIndexPath indexPathForItem:0 inSection:1] : [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:1 inSection:1] : [NSIndexPath indexPathForItem:1 inSection:0]}; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:moves insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:4 inSection:0]); } - (void)testUpdate_AffectedByMultipleMoves_OutOfSection { NSDictionary *moves = @{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:0 inSection:1], [NSIndexPath indexPathForItem:1 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:1]}; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:moves insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:0]); } #pragma mark - Affected updates by multiple operations - (void)testUpdate_AffectedByInsertionAndMove { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:5 inSection:0] : [NSIndexPath indexPathForItem:0 inSection:0] } insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:4 inSection:0]); } // NOTE: In the transactional data source, rows are updated before insertions happen, and inserted sections happen before inserted rows (see comment at top of file). In this test case, the row insertion (section 0, row 0) does not affect the updated row (section 0, row 0) because the updated row would have been pushed to section 1 (because of the newly inserted section) before the new row is inserted. - (void)testUpdate_AffectedBySectionInsertionAndRowInsertion { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndex:0] insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:1]); } - (void)testUpdate_AffectedBySectionInsertionAndRowRemoval { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:0]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedSections:nil movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndex:0] insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:1]); } - (void)testUpdate_AffectedBySectionRemovalAndRowInsertion { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:1]] removedIndexPaths:nil removedSections:[NSIndexSet indexSetWithIndex:0] movedIndexPaths:nil insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:1]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:1]], [NSIndexPath indexPathForItem:0 inSection:0]); } - (void)testUpdate_AffectedBySectionRemovalAndRowRemoval { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:1]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:1]] removedSections:[NSIndexSet indexSetWithIndex:0] movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:1 inSection:1]], [NSIndexPath indexPathForItem:0 inSection:0]); } // NOTE: Because of the order of operations (see comment at the top of this file), the inserted row doesn't affect the updated row, so the inserted section increments the update's section and the moved rows increment the update's row ( {0,3} -> {1,4} ) - (void)testUpdate_AffectedByMoveAndInsertedSection_UnaffectedByInsertedRows { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:3 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:4 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:1] } insertedSections:[NSIndexSet indexSetWithIndex:0] insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:3 inSection:0]], [NSIndexPath indexPathForItem:4 inSection:1]); } - (void)testUpdate_UnaffectedByOffsettingInsertionAndRemoval_AffectedByRemovedSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:5 inSection:1]] removedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:1]] removedSections:[NSIndexSet indexSetWithIndex:0] movedIndexPaths:nil insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:1 inSection:1]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:5 inSection:1]], [NSIndexPath indexPathForItem:4 inSection:0]); } - (void)testUpdate_AffectedByInsertedRowAfterBeingMovedToNewSection { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:1]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndex:1] insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:2]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:1]], [NSIndexPath indexPathForItem:1 inSection:2]); } - (void)testUpdate_AffectedByMoveAndUpdateAtSameIndexPath { // [0, 1, 2] -> [2', 1', 0'] CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObjects:[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0], [NSIndexPath indexPathForItem:2 inSection:0], nil] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:2 inSection:0] : [NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqualObjects(updateMapping, (@{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:2 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:0], [NSIndexPath indexPathForItem:2 inSection:0] : [NSIndexPath indexPathForItem:0 inSection:0] })); } - (void)testUpdate_AffectedByAllOthers { // [1, 2, 3] -> [0, 1', 4, 3', 2'] CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObjects:[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0], [NSIndexPath indexPathForItem:2 inSection:0], nil] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:2 inSection:0] : [NSIndexPath indexPathForItem:3 inSection:0] } insertedSections:nil insertedIndexPaths:[NSSet setWithObjects:[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:2 inSection:0], nil] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqualObjects(updateMapping, (@{ [NSIndexPath indexPathForItem:0 inSection:0] : [NSIndexPath indexPathForItem:1 inSection:0], [NSIndexPath indexPathForItem:1 inSection:0] : [NSIndexPath indexPathForItem:4 inSection:0], [NSIndexPath indexPathForItem:2 inSection:0] : [NSIndexPath indexPathForItem:3 inSection:0] })); } #pragma mark - Special cases - (void)testUpdate_UpdatedRowBeingMoved_withoutAffectedDestination { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:2 inSection:0] : [NSIndexPath indexPathForItem:5 inSection:0] } insertedSections:nil insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:5 inSection:0]); } - (void)testUpdate_UpdatedRowBeingMoved_withAffectedDestination { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:2 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ [NSIndexPath indexPathForItem:2 inSection:0] : [NSIndexPath indexPathForItem:5 inSection:0] } insertedSections:nil insertedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:4 inSection:0]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:2 inSection:0]], [NSIndexPath indexPathForItem:5 inSection:0]); } - (void)testUpdate_insertingThreeSectionsBefore { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)] insertedIndexPaths:nil userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:3]); } - (void)testUpdate_insertingThreeRowsBefore { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:[NSSet setWithArray:@[[NSIndexPath indexPathForRow:0 inSection:0], [NSIndexPath indexPathForRow:1 inSection:0], [NSIndexPath indexPathForRow:2 inSection:0]]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:0]], [NSIndexPath indexPathForItem:3 inSection:0]); } - (void)testUpdate_insertingThreeSectionsAndThreeRowsBefore { CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithObject:[NSIndexPath indexPathForItem:0 inSection:0]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)] insertedIndexPaths:[NSSet setWithArray:@[[NSIndexPath indexPathForRow:0 inSection:3], [NSIndexPath indexPathForRow:1 inSection:3], [NSIndexPath indexPathForRow:2 inSection:3]]] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], 1); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:0]], [NSIndexPath indexPathForItem:3 inSection:3]); } - (void)testUpdate_mirroringGroupsCrash { NSArray *updatedIndexPaths = @[[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:1], [NSIndexPath indexPathForItem:0 inSection:4]]; NSMutableIndexSet *insertedSections = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 4)]; [insertedSections addIndex:5]; NSArray *insertedIndexPaths = @[[NSIndexPath indexPathForItem:0 inSection:0], [NSIndexPath indexPathForItem:0 inSection:1], [NSIndexPath indexPathForItem:0 inSection:2], [NSIndexPath indexPathForItem:0 inSection:3], [NSIndexPath indexPathForItem:0 inSection:5]]; CKDataSourceAppliedChanges *changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithArray:updatedIndexPaths] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:insertedSections insertedIndexPaths:[NSSet setWithArray:insertedIndexPaths] userInfo:nil]; NSDictionary *updateMapping = [changes finalUpdatedIndexPaths]; XCTAssertEqual([updateMapping count], [updatedIndexPaths count]); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:0]], [NSIndexPath indexPathForItem:0 inSection:4]); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:1]], [NSIndexPath indexPathForItem:0 inSection:6]); XCTAssertEqualObjects(updateMapping[[NSIndexPath indexPathForItem:0 inSection:4]], [NSIndexPath indexPathForItem:0 inSection:9]); } @end @interface CKDataSourceAppliedChangesTests_Description : XCTestCase @end @implementation CKDataSourceAppliedChangesTests_Description - (void)test_WhenEmpty_DescriptionIsEmpty { auto const changes = [CKDataSourceAppliedChanges new]; auto const description = [changes description]; XCTAssertEqualObjects(description, @""); } - (void)test_WhenHasSectionChanges_IncludesThemInDescription { auto const changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:nil removedIndexPaths:nil removedSections:[NSIndexSet indexSetWithIndexesInRange:{0, 2}] movedIndexPaths:nil insertedSections:[NSIndexSet indexSetWithIndex:0] insertedIndexPaths:nil userInfo:nil];; auto const description = [changes description]; auto const expectedDescription = @"\ {\n\ Removed Sections: 0–1\n\ Inserted Sections: 0\n\ }"; XCTAssertEqualObjects(description, expectedDescription); } - (void)test_WhenHasRemovedItems_IncludesThemInDescriptionSorted { auto const changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:nil removedIndexPaths:[NSSet setWithArray:@[ IndexPath{1, 1}.toCocoa(), IndexPath{0, 2}.toCocoa(), ]] removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil];; auto const description = [changes description]; auto const expectedDescription = @"\ {\n\ Removed Items: {\n\ (0-2),\n\ (1-1)\n\ }\n\ }"; XCTAssertEqualObjects(description, expectedDescription); } - (void)test_WhenHasUpdatedItems_IncludesThemInDescriptionSorted { auto const changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:[NSSet setWithArray:@[ IndexPath{1, 1}.toCocoa(), IndexPath{0, 2}.toCocoa(), ]] removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:nil userInfo:nil];; auto const description = [changes description]; auto const expectedDescription = @"\ {\n\ Updated Items: {\n\ (0-2),\n\ (1-1)\n\ }\n\ }"; XCTAssertEqualObjects(description, expectedDescription); } - (void)test_WhenHasInsertedItems_IncludesThemInDescriptionSorted { auto const changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:nil removedIndexPaths:nil removedSections:nil movedIndexPaths:nil insertedSections:nil insertedIndexPaths:[NSSet setWithArray:@[ IndexPath{1, 1}.toCocoa(), IndexPath{0, 2}.toCocoa(), ]] userInfo:nil];; auto const description = [changes description]; auto const expectedDescription = @"\ {\n\ Inserted Items: {\n\ (0-2),\n\ (1-1)\n\ }\n\ }"; XCTAssertEqualObjects(description, expectedDescription); } - (void)test_WhenHasMovedItems_IncludesThemInDescriptionSortedByFromIndexPath { auto const changes = [[CKDataSourceAppliedChanges alloc] initWithUpdatedIndexPaths:nil removedIndexPaths:nil removedSections:nil movedIndexPaths:@{ IndexPath{1, 1}.toCocoa() : IndexPath{1, 2}.toCocoa(), IndexPath{0, 2}.toCocoa() : IndexPath{0, 0}.toCocoa(), } insertedSections:nil insertedIndexPaths:nil userInfo:nil];; auto const description = [changes description]; auto const expectedDescription = @"\ {\n\ Moved Items: {\n\ (0-2) -> (0-0),\n\ (1-1) -> (1-2)\n\ }\n\ }"; XCTAssertEqualObjects(description, expectedDescription); } @end