         super.tearDown()
     }
 
+    var tableView: MockTableView? = nil
+    var dataSource: DataSource<MockTVItem>? = nil
+
+    // MARK: - helper
+
+    func mockTVItemsForIdentifiers(identifiers: [String]) -> [MockTVItem] {
+        return identifiers.map { return MockTVItem(identifier:$0) }
+    }
+
     // MARK: - given
 
-    // MARK: - when
-
-    func whenDelegate() -> (MockTableView,DataSource<MockTVItem>) {
-        let tableView = MockTableView(frame: CGRect(x: 0, y: 0, width: 320, height: 960), style: .Plain)
-        let dataSource = DataSource<MockTVItem>(tableView: tableView) { (inLocation) -> UITableViewCell in
+    func givenDelegateAndDataSource() {
+        self.tableView = MockTableView(frame: CGRect(x: 0, y: 0, width: 320, height: 960), style: .Plain)
+        guard let tableView = self.tableView else {
+            XCTFail("could not instantiate table view")
+            return
+        }
+        self.dataSource = DataSource<MockTVItem>(tableView: tableView) { (inLocation) -> UITableViewCell in
             cellForSectionID(inLocation.sectionID, item: inLocation.item, tableView: inLocation.tableView)
         }
-
-        return (tableView,dataSource)
-    }
-
-    func whenDataSource(inDataSource: DataSource<MockTVItem>, canMoveItemAtSectionID inSectionID: String, rowID inRowID: String) {
-        inDataSource.canMove = {(toLocation:Location<MockTVItem>) -> Bool in
-            return toLocation.sectionID == inSectionID && toLocation.item.identifier == inRowID
-        }
-    }
-
-    func whenDataSource(inDataSource:DataSource<MockTVItem>, retargetsToLocation inRetargetLocation:LocationWithOptionalItem<MockTVItem>) {
-        inDataSource.targetMovedItem = { (fromLocation:Location<MockTVItem>, proposedLocation:LocationWithOptionalItem<MockTVItem>) -> LocationWithOptionalItem<MockTVItem> in
-            return inRetargetLocation
-        }
-    }
-
-    func whenDataSource(inDataSource: DataSource<MockTVItem>, canEditItemAtSectionID inSectionID: String, rowID inRowID: String) {
-        inDataSource.canEdit = {(atLocation:Location<MockTVItem>) -> Bool in
-            return atLocation.sectionID == inSectionID && atLocation.item.identifier == inRowID
-        }
-    }
-
-    func whenDataSource(inDataSource:DataSource<MockTVItem>, hasSectionIDs inSectionIDs:Array<String>) {
-        inDataSource.updateSections(inSectionIDs, animated: true)
-    }
-
-    func whenDataSource(inDataSource: DataSource<MockTVItem>, hasRowIDs inRowIDs: Array<String>, forSectionID inSectionID: String) {
-        let rows = inRowIDs.map { (inRowID: String) -> MockTVItem in
-            return MockTVItem(identifier: inRowID)
-        }
-
-        inDataSource.updateRows(rows, section: inSectionID, animated: true)
-    }
-
-    // MARK: - then
-
-    // MARK: - test
-
-    func testDataSourceSections() {
-        let (tableView,dataSource) = self.whenDelegate()
-
-        dataSource.updateSections(["a","b","c"], animated: true)
-        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 3, "...")
-
-        dataSource.updateSections(["a","d","c"], animated: true)
-        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 3, "...")
-
-        dataSource.updateSections([], animated: true)
-        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 0, "...")
-
-    }
-
-    func testDataSourceRows() {
-        let (tableView,dataSource) = self.whenDelegate()
 
         tableView.insertCallback = { print("insert \($0)") }
         tableView.deleteCallback = { print("delete \($0)") }
-
-        self.whenDataSource(dataSource, hasSectionIDs: ["a","b","c"])
-
-        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 3, "...")
-
-        dataSource.updateRows([MockTVItem(identifier:"0"),MockTVItem(identifier:"1"),MockTVItem(identifier:"2")], section: "a", animated: true)
-        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 3, "...")
-        XCTAssert(tableView.insertionIndexPaths == [NSIndexPath(forRow: 0, inSection: 0),NSIndexPath(forRow: 1, inSection: 0),NSIndexPath(forRow: 2, inSection: 0)])
-        XCTAssert(tableView.deletionIndexPaths == [])
-        tableView.insertionIndexPaths = []
-
-        dataSource.updateRows([MockTVItem(identifier:"0"),MockTVItem(identifier:"2"),MockTVItem(identifier:"3")], section: "a", animated: true)
-        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 3, "...")
-        XCTAssert(tableView.insertionIndexPaths == [NSIndexPath(forRow: 2, inSection: 0)])
-        XCTAssert(tableView.deletionIndexPaths == [NSIndexPath(forRow: 1, inSection: 0)])
-        tableView.insertionIndexPaths = []
-        tableView.deletionIndexPaths = []
-
-        print("")
-    }
-
-    func testDataSourceRowsDelete() {
-        let (tableView,dataSource) = self.whenDelegate()
-
-        tableView.insertCallback = { print("insert \($0)") }
-        tableView.deleteCallback = { print("delete \($0)") }
-
-        self.whenDataSource(dataSource, hasSectionIDs: ["a","b","c"])
-
-        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 3, "...")
-
-        dataSource.updateRows([MockTVItem(identifier:"0"),MockTVItem(identifier:"1"),MockTVItem(identifier:"2")], section: "a", animated: true)
-        tableView.insertionIndexPaths = []
-        tableView.deletionIndexPaths = []
-
-        dataSource.updateRows([MockTVItem(identifier:"0"),MockTVItem(identifier:"5"),MockTVItem(identifier:"4"),MockTVItem(identifier:"2")], section: "a", animated: true)
-        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 4, "...")
-        XCTAssert(tableView.insertionIndexPaths == [NSIndexPath(forRow: 1, inSection: 0),NSIndexPath(forRow: 2, inSection: 0)])
-        XCTAssertEqual(tableView.deletionIndexPaths, [NSIndexPath(forRow: 1, inSection: 0)])
-        tableView.insertionIndexPaths = []
-        tableView.deletionIndexPaths = []
-
-        print("")
-
-        dataSource.updateRows([MockTVItem(identifier:"0"),MockTVItem(identifier:"2")], section: "a", animated: true)
-        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 2, "...")
-        XCTAssert(tableView.insertionIndexPaths == [])
-        XCTAssertEqual(tableView.deletionIndexPaths, [NSIndexPath(forRow: 1, inSection: 0),NSIndexPath(forRow: 2, inSection: 0)])
-        tableView.insertionIndexPaths = []
-        tableView.deletionIndexPaths = []
-
-        dataSource.updateRows(["0","1","2","3","4","5"].map({ return MockTVItem(identifier:$0) }), section: "a", animated: true)
-        tableView.insertionIndexPaths = []
-        tableView.deletionIndexPaths = []
-
-        dataSource.updateRows(["0","2","4"].map({ return MockTVItem(identifier:$0) }), section: "a", animated: true)
-        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 3, "...")
-        XCTAssert(tableView.insertionIndexPaths == [])
-        XCTAssertEqual(tableView.deletionIndexPaths, [1,3,5].map({ return NSIndexPath(forRow: $0, inSection: 0)}))
-        tableView.insertionIndexPaths = []
-        tableView.deletionIndexPaths = []
-    }
-
-    func testDataSourceWhenCompletelyEmpty() {
-        let (tableView,dataSource) = self.whenDelegate()
-
-        let numSections = dataSource.numberOfSectionsInTableView(tableView)
-        XCTAssert(numSections == 0, "...")
-
-        let numRows = dataSource.tableView(tableView, numberOfRowsInSection: 0)
-        XCTAssert(numRows == 0, "...")
-    }
-
-    func testDidSelect() {
-        var didCallHandler = false
-        let (tableView,dataSource) = self.whenDelegate()
+        didCallDidSelectHandler = false
+    }
+
+    func givenDataSourceCanMoveItemAtSectionID(inSectionID: String, rowID inRowID: String) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        dataSource.canMove = {(toLocation:Location<MockTVItem>) -> Bool in
+            return toLocation.sectionID == inSectionID && toLocation.item.identifier == inRowID
+        }
+    }
+
+    func givenDataSourceRetargetsToRowIDSectionID(rowID: String, sectionID: String) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        guard let tableView = self.tableView else {
+            XCTFail("could not instantiate table view")
+            return
+        }
+        let location = LocationWithOptionalItem(tableView: tableView, sectionID: sectionID, item: MockTVItem(identifier: rowID))
+        dataSource.targetMovedItem = { (fromLocation:Location<MockTVItem>, proposedLocation:LocationWithOptionalItem<MockTVItem>) -> LocationWithOptionalItem<MockTVItem> in
+            return location
+        }
+    }
+
+    func givenDataSourceCanEditItemAtSectionID(inSectionID: String, rowID inRowID: String) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        dataSource.canEdit = {(atLocation:Location<MockTVItem>) -> Bool in
+            return atLocation.sectionID == inSectionID && atLocation.item.identifier == inRowID
+        }
+    }
+
+    var didCallDidSelectHandler = false
+
+    func givenDataSourceWillAllowSelectInSectionID(sectionID: String, rowID inRowID: String) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        didCallDidSelectHandler = false
         dataSource.didSelect = { (inLocation:Location<MockTVItem>) -> Void in
             XCTAssert(inLocation.sectionID == "a")
             XCTAssert(inLocation.item.identifier == "1")
-            didCallHandler = true
-        }
-
-        self.whenDataSource(dataSource, hasSectionIDs: ["a","b","c"])
-
-        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 3, "...")
-
-        dataSource.updateRows([MockTVItem(identifier:"0"),MockTVItem(identifier:"1"),MockTVItem(identifier:"2")], section: "a", animated: true)
-        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 3, "...")
-
-        dataSource.tableView(tableView, didSelectRowAtIndexPath: NSIndexPath(forRow: 1, inSection: 0))
-        XCTAssert(didCallHandler == true)
+            self.didCallDidSelectHandler = true
+        }
+    }
+
+    func givenDiffsAreCleared() {
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+        tableView.deletionIndexPaths = []
+        tableView.insertionIndexPaths = []
+    }
+
+    func givenExpectRowIDsAfterMove(rowIDs: [String], forSectionID sectionID: String, withSectionCount sectionCount: Int) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        dataSource.didChangeSectionIDs = { (inSectionIDs:Dictionary<String,Array<MockTVItem>>) -> Void in
+            XCTAssert(inSectionIDs.count == sectionCount)
+
+            guard let rows = inSectionIDs[sectionID] else {
+                XCTFail("no rows?")
+                return
+            }
+
+            let mappedIDs = rows.map({ (item) -> String in
+                return item.identifier
+            })
+
+            XCTAssert(mappedIDs == rowIDs)
+        }
+
+    }
+
+    // MARK: - when
+
+    func whenDataSourceHasSectionIDs(inSectionIDs:Array<String>) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        dataSource.updateSections(inSectionIDs, animated: true)
+    }
+
+    func whenUpdatingRowsWithIdentifiers(identifiers: [String], sectionID: String) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        dataSource.updateRows(self.mockTVItemsForIdentifiers(identifiers), section: sectionID, animated: true)
+    }
+
+    func whenSelectingRow(row: Int, section: Int) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+        let indexPath = NSIndexPath(forRow: row, inSection: section)
+        dataSource.tableView(tableView, didSelectRowAtIndexPath: indexPath)
+
+    }
+
+    func whenMovingRow(sourceRow: Int, sourceSection: Int, toRow destinationRow: Int, toSection destinationSection: Int) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+        dataSource.tableView(tableView, moveRowAtIndexPath: NSIndexPath(forRow: sourceRow, inSection: sourceSection), toIndexPath: NSIndexPath(forRow: destinationRow, inSection: destinationSection))
+    }
+
+    // MARK: - then
+
+    func thenNumberOfSectionsIs(numberOfSections: Int) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == numberOfSections, "...")
+    }
+
+    func thenNumberOfRowsIs(numberOfRows: Int, sectionIndex: Int) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: sectionIndex) == numberOfRows)
+    }
+
+    let indexListMapper = { (indexList: [Int]) -> NSIndexPath in
+        if indexList.count != 2 {
+            return NSIndexPath(forItem: Int.max, inSection: Int.max)
+        }
+        return NSIndexPath(forItem: indexList[0], inSection: indexList[1])
+    }
+
+    func thenInsertionRowsSectionsAre(indexPaths: [[Int]]) {
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+
+        let realIndexPaths = indexPaths.map(indexListMapper)
+
+        XCTAssert(tableView.insertionIndexPaths == realIndexPaths)
+    }
+
+    func thenDeletionRowsSectionsAre(indexPaths: [[Int]]) {
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+
+        let realIndexPaths = indexPaths.map(indexListMapper)
+
+        XCTAssert(tableView.deletionIndexPaths == realIndexPaths)
+    }
+
+    func thenCanSelectHandlerWasCalled() {
+        XCTAssert(self.didCallDidSelectHandler)
+    }
+
+    func thenCanMoveItemAtRow(row: Int, section: Int, canMove: Bool) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+        XCTAssert(dataSource.tableView(tableView, canMoveRowAtIndexPath: NSIndexPath(forRow: row, inSection: section)) == canMove);
+
+    }
+
+    func thenCanEditItemAtRow(row: Int, section: Int, canMove: Bool) {
+        guard let dataSource = self.dataSource else {
+            XCTFail("no data source")
+            return
+        }
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+        XCTAssert(dataSource.tableView(tableView, canEditRowAtIndexPath: NSIndexPath(forRow: row, inSection: section)) == canMove);
+    }
+
+    // MARK: - test
+
+    func testDataSourceSections() {
+        self.givenDelegateAndDataSource()
+
+        self.dataSource?.updateSections(["a","b","c"], animated: true)
+        self.thenNumberOfSectionsIs(3)
+
+        self.dataSource?.updateSections(["a","d","c"], animated: true)
+        self.thenNumberOfSectionsIs(3)
+
+        self.dataSource?.updateSections([], animated: true)
+        self.thenNumberOfSectionsIs(0)
+
+    }
+
+    func testDataSourceRows() {
+        self.givenDelegateAndDataSource()
+
+        self.whenDataSourceHasSectionIDs(["a","b","c"])
+        self.thenNumberOfSectionsIs(3)
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2"], sectionID: "a")
+
+        self.thenNumberOfRowsIs(3, sectionIndex: 0)
+        self.thenInsertionRowsSectionsAre([[0,0],[1,0],[2,0]])
+        self.thenDeletionRowsSectionsAre([])
+
+        self.givenDiffsAreCleared()
+
+        self.whenUpdatingRowsWithIdentifiers(["0","2","3"], sectionID: "a")
+        self.thenNumberOfSectionsIs(3)
+        self.thenInsertionRowsSectionsAre([[2,0]])
+        self.thenDeletionRowsSectionsAre([[1,0]])
+    }
+
+    func testDataSourceRowsDelete() {
+        self.givenDelegateAndDataSource()
+
+        self.whenDataSourceHasSectionIDs(["a","b","c"])
+        self.thenNumberOfSectionsIs(3)
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2"], sectionID: "a")
+        self.givenDiffsAreCleared()
+
+        self.whenUpdatingRowsWithIdentifiers(["0","5","4","2"], sectionID: "a")
+        self.thenNumberOfRowsIs(4, sectionIndex: 0)
+        self.thenInsertionRowsSectionsAre([[1,0],[2,0]])
+        self.thenDeletionRowsSectionsAre([[1,0]])
+
+        self.givenDiffsAreCleared()
+
+        print("")
+
+        self.whenUpdatingRowsWithIdentifiers(["0","2"], sectionID: "a")
+        self.thenNumberOfRowsIs(2, sectionIndex: 0)
+        self.thenInsertionRowsSectionsAre([])
+        self.thenDeletionRowsSectionsAre([[1,0],[2,0]])
+
+        self.givenDiffsAreCleared()
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2","3","4","5"], sectionID: "a")
+        self.givenDiffsAreCleared()
+
+        self.whenUpdatingRowsWithIdentifiers(["0","2","4"], sectionID: "a")
+        self.thenNumberOfRowsIs(3, sectionIndex: 0)
+        self.thenInsertionRowsSectionsAre([])
+        self.thenDeletionRowsSectionsAre([[1,0],[3,0],[5,0]])
+    }
+
+    func testDataSourceWhenCompletelyEmpty() {
+        self.givenDelegateAndDataSource()
+
+        self.thenNumberOfSectionsIs(0)
+        self.thenNumberOfRowsIs(0, sectionIndex: 0)
+    }
+
+    func testDidSelect() {
+        self.givenDelegateAndDataSource()
+        self.givenDataSourceWillAllowSelectInSectionID("a", rowID: "1")
+
+        self.whenDataSourceHasSectionIDs(["a","b","c"])
+        self.thenNumberOfSectionsIs(3)
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2"], sectionID: "a")
+        self.thenNumberOfRowsIs(3, sectionIndex: 0)
+
+        self.whenSelectingRow(1, section: 0)
+        self.thenCanSelectHandlerWasCalled()
     }
 
     func testCanMove() {
-        let (tableView,dataSource) = self.whenDelegate()
-        self.whenDataSource(dataSource, canMoveItemAtSectionID: "a", rowID: "2")
-
-        self.whenDataSource(dataSource, hasSectionIDs: ["a","b","c"])
-        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 3, "...")
-
-        dataSource.updateRows([MockTVItem(identifier:"0"),MockTVItem(identifier:"1"),MockTVItem(identifier:"2")], section: "a", animated: true)
-        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 3, "...")
-
-        XCTAssert(dataSource.tableView(tableView, canMoveRowAtIndexPath: NSIndexPath(forRow: 2, inSection: 0)) == true);
-        XCTAssert(dataSource.tableView(tableView, canMoveRowAtIndexPath: NSIndexPath(forRow: 1, inSection: 0)) == false);
+        self.givenDelegateAndDataSource()
+        self.givenDataSourceCanMoveItemAtSectionID("a", rowID: "2")
+
+        self.whenDataSourceHasSectionIDs(["a","b","c"])
+        self.thenNumberOfSectionsIs(3)
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2"], sectionID: "a")
+        self.thenNumberOfRowsIs(3, sectionIndex: 0)
+
+        self.thenCanMoveItemAtRow(2, section: 0, canMove: true)
+        self.thenCanMoveItemAtRow(1, section: 0, canMove: false)
     }
 
     func testMove() {
-        let (tableView,dataSource) = self.whenDelegate()
-        self.whenDataSource(dataSource, canMoveItemAtSectionID: "a", rowID: "2")
+        self.givenDelegateAndDataSource()
+        self.givenDataSourceCanMoveItemAtSectionID("a", rowID: "2")
+        self.givenExpectRowIDsAfterMove(["0","2","1"], forSectionID: "a", withSectionCount: 1)
+
+
+        self.whenDataSourceHasSectionIDs(["a","b","c"])
+        self.thenNumberOfSectionsIs(3)
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2"], sectionID: "a")
+        self.thenNumberOfRowsIs(3, sectionIndex: 0)
+
+        self.whenMovingRow(2, sourceSection: 0, toRow: 1, toSection: 0)
+    }
+
+    func testMoveBeyondLastItem() {
+        self.givenDelegateAndDataSource()
+        self.givenDataSourceCanMoveItemAtSectionID("a", rowID: "1")
+        self.givenExpectRowIDsAfterMove(["0","2","1"], forSectionID: "a", withSectionCount: 1)
+
+        self.whenDataSourceHasSectionIDs(["a","b","c"])
+        self.thenNumberOfSectionsIs(3)
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2"], sectionID: "a")
+        self.thenNumberOfRowsIs(3, sectionIndex: 0)
+
+        self.whenMovingRow(1, sourceSection: 0, toRow: 3, toSection: 0)
+    }
+
+
+    func testMoveAcrossSections() {
+        self.givenDelegateAndDataSource()
+        self.givenDataSourceCanMoveItemAtSectionID("a", rowID: "3")
+
+        self.whenDataSourceHasSectionIDs(["a","b","c"])
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2","3"], sectionID: "a")
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2"], sectionID: "b")
+
+        let expectation = expectationWithDescription("sections changed callback")
+
+        guard let dataSource = self.dataSource else {
+            XCTFail()
+            return
+        }
 
         dataSource.didChangeSectionIDs = { (inSectionIDs:Dictionary<String,Array<MockTVItem>>) -> Void in
+            expectation.fulfill()
+            XCTAssert(inSectionIDs.count == 2, "should be only two sections")
+
+            guard let rowsA = inSectionIDs["a"] else {
+                XCTFail("no rows for a?")
+                return
+            }
+
+            let mappedIDsA = rowsA.map({ (item) -> String in
+                return item.identifier
+            })
+
+            XCTAssert(mappedIDsA == ["0","1","2"])
+
+            guard let rowsB = inSectionIDs["b"] else {
+                XCTFail("no rows for b?")
+                return
+            }
+
+            let mappedIDsB = rowsB.map({ (item) -> String in
+                return item.identifier
+            })
+
+            XCTAssert(mappedIDsB == ["0","1","3","2"])
+        }
+
+        self.whenMovingRow(3, sourceSection: 0, toRow: 2, toSection: 1)
+
+        self.waitForExpectationsWithTimeout(10, handler: nil)
+    }
+
+    func testMoveWithCorrectedTarget() {
+        self.givenDelegateAndDataSource()
+        self.givenDataSourceCanMoveItemAtSectionID("a", rowID: "3")
+        self.givenDataSourceRetargetsToRowIDSectionID("1", sectionID: "a")
+
+        self.whenDataSourceHasSectionIDs(["a","b","c"])
+
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2","3"], sectionID: "a")
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2"], sectionID: "b")
+
+        guard let dataSource = self.dataSource else {
+            XCTFail()
+            return
+        }
+        guard let tableView = self.tableView else {
+            XCTFail("no table view")
+            return
+        }
+        let indexPath = dataSource.tableView(tableView, targetIndexPathForMoveFromRowAtIndexPath: NSIndexPath(forRow: 3, inSection: 0), toProposedIndexPath: NSIndexPath(forRow: 2, inSection: 0))
+        XCTAssert(indexPath.section == 0)
+        XCTAssert(indexPath.row == 1)
+    }
+
+    // testing: optional func tableView(_ tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool
+    func testCanEditItem() {
+        self.givenDelegateAndDataSource()
+        self.givenDataSourceCanEditItemAtSectionID("a", rowID: "1")
+
+        self.whenDataSourceHasSectionIDs(["a"])
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2","3"], sectionID: "a")
+
+        self.thenCanEditItemAtRow(1, section: 0, canMove: true)
+        self.thenCanEditItemAtRow(0, section: 0, canMove: false)
+        self.thenCanEditItemAtRow(1000, section: 0, canMove: false)
+        self.thenCanEditItemAtRow(0, section: 1000, canMove: false)
+    }
+
+    func testDeleteItem() {
+        self.givenDelegateAndDataSource()
+        self.whenDataSourceHasSectionIDs(["a"])
+        self.whenUpdatingRowsWithIdentifiers(["0","1","2","3"], sectionID: "a")
+
+        let willDeleteExpectation = expectationWithDescription("will delete callback")
+        let didDeleteExpectation = expectationWithDescription("did delete callback")
+        let sectionChangedExpectation = expectationWithDescription("sections changed callback")
+
+        guard let dataSource = self.dataSource else {
+            XCTFail()
+            return
+        }
+        dataSource.willDelete = { (atLocation:Location<MockTVItem>) -> Void in
+            XCTAssert(atLocation.sectionID == "a")
+            XCTAssert(atLocation.item.identifier == "1")
+            willDeleteExpectation.fulfill()
+        }
+
+        dataSource.didDelete = { (item: MockTVItem) -> Void in
+            XCTAssert(item.identifier == "1")
+            didDeleteExpectation.fulfill()
+        }
+
+        dataSource.didChangeSectionIDs = { (inSectionIDs:Dictionary<String,Array<MockTVItem>>) -> Void in
+            sectionChangedExpectation.fulfill()
             XCTAssert(inSectionIDs.count == 1, "should be only one section")
 
             guard let rows = inSectionIDs["a"] else {

                return item.identifier
            })

            XCTAssert(mappedIDs == ["0","2","1"])
        }

        self.whenDataSource(dataSource, hasSectionIDs: ["a","b","c"])
        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 3, "...")

        dataSource.updateRows([MockTVItem(identifier:"0"),MockTVItem(identifier:"1"),MockTVItem(identifier:"2")], section: "a", animated: true)
        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 3, "...")

        dataSource.tableView(tableView, moveRowAtIndexPath: NSIndexPath(forRow: 2, inSection: 0), toIndexPath: NSIndexPath(forRow: 1, inSection: 0))
    }

    func testMoveBeyondLastItem() {
        let (tableView,dataSource) = self.whenDelegate()
        self.whenDataSource(dataSource, canMoveItemAtSectionID: "a", rowID: "1")

        let expectation = expectationWithDescription("sections changed callback")
        dataSource.didChangeSectionIDs = { (inSectionIDs:Dictionary<String,Array<MockTVItem>>) -> Void in
            expectation.fulfill()
            XCTAssert(inSectionIDs.count == 1, "should be only one section")

            guard let rows = inSectionIDs["a"] else {
                XCTFail("no rows?")
                return
            }

            let mappedIDs = rows.map({ (item) -> String in
                return item.identifier
            })

            XCTAssert(mappedIDs == ["0","2","1"])
        }

        self.whenDataSource(dataSource, hasSectionIDs: ["a","b","c"])
        XCTAssert(dataSource.numberOfSectionsInTableView(tableView) == 3, "...")

        self.whenDataSource(dataSource, hasRowIDs: ["0","1","2"], forSectionID: "a")
        XCTAssert(dataSource.tableView(tableView, numberOfRowsInSection: 0) == 3, "...")

        dataSource.tableView(tableView, moveRowAtIndexPath: NSIndexPath(forRow: 1, inSection: 0), toIndexPath: NSIndexPath(forRow: 3, inSection: 0))

        waitForExpectationsWithTimeout(10, handler: nil)
    }


    func testMoveAcrossSections() {
        let (tableView,dataSource) = self.whenDelegate()
        self.whenDataSource(dataSource, hasSectionIDs: ["a","b","c"])

        self.whenDataSource(dataSource, hasRowIDs: ["0","1","2","3"], forSectionID: "a")
        self.whenDataSource(dataSource, hasRowIDs: ["0","1","2"], forSectionID: "b")

        self.whenDataSource(dataSource, canMoveItemAtSectionID: "a", rowID: "3")

        let expectation = expectationWithDescription("sections changed callback")

        dataSource.didChangeSectionIDs = { (inSectionIDs:Dictionary<String,Array<MockTVItem>>) -> Void in
            expectation.fulfill()
            XCTAssert(inSectionIDs.count == 2, "should be only two sections")

            guard let rowsA = inSectionIDs["a"] else {
                XCTFail("no rows for a?")
                return
            }

            let mappedIDsA = rowsA.map({ (item) -> String in
                return item.identifier
            })

            XCTAssert(mappedIDsA == ["0","1","2"])

            guard let rowsB = inSectionIDs["b"] else {
                XCTFail("no rows for b?")
                return
            }

            let mappedIDsB = rowsB.map({ (item) -> String in
                return item.identifier
            })

            XCTAssert(mappedIDsB == ["0","1","3","2"])
        }

        dataSource.tableView(tableView, moveRowAtIndexPath: NSIndexPath(forRow: 3, inSection: 0), toIndexPath: NSIndexPath(forRow: 2, inSection: 1))
        waitForExpectationsWithTimeout(10, handler: nil)
    }

    func testMoveWithCorrectedTarget() {
        let (tableView,dataSource) = self.whenDelegate()
        self.whenDataSource(dataSource, hasSectionIDs: ["a","b","c"])

        self.whenDataSource(dataSource, hasRowIDs: ["0","1","2","3"], forSectionID: "a")
        self.whenDataSource(dataSource, hasRowIDs: ["0","1","2"], forSectionID: "b")

        self.whenDataSource(dataSource, canMoveItemAtSectionID: "a", rowID: "3")
        self.whenDataSource(dataSource, retargetsToLocation: LocationWithOptionalItem(tableView: tableView, sectionID:"a", item:MockTVItem(identifier: "1")))

        let indexPath = dataSource.tableView(tableView, targetIndexPathForMoveFromRowAtIndexPath: NSIndexPath(forRow: 3, inSection: 0), toProposedIndexPath: NSIndexPath(forRow: 2, inSection: 0))
        XCTAssert(indexPath.section == 0)
        XCTAssert(indexPath.row == 1)

    }

    // testing: optional func tableView(_ tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool
    func testCanEditItem() {
        let (tableView,dataSource) = self.whenDelegate()
        self.whenDataSource(dataSource, hasSectionIDs: ["a"])
        self.whenDataSource(dataSource, hasRowIDs: ["0","1","2","3"], forSectionID: "a")

        self.whenDataSource(dataSource, canEditItemAtSectionID: "a", rowID: "1")

        XCTAssert(dataSource.tableView(tableView, canEditRowAtIndexPath: NSIndexPath(forRow: 1, inSection: 0)) == true)
        XCTAssert(dataSource.tableView(tableView, canEditRowAtIndexPath: NSIndexPath(forRow: 0, inSection: 0)) == false)
        XCTAssert(dataSource.tableView(tableView, canEditRowAtIndexPath: NSIndexPath(forRow: 1000, inSection: 0)) == false)
        XCTAssert(dataSource.tableView(tableView, canEditRowAtIndexPath: NSIndexPath(forRow: 0, inSection: 1000)) == false)
    }

    func testDeleteItem() {
        let (tableView,dataSource) = self.whenDelegate()
        self.whenDataSource(dataSource, hasSectionIDs: ["a"])
        self.whenDataSource(dataSource, hasRowIDs: ["0","1","2","3"], forSectionID: "a")

        let willDeleteExpectation = expectationWithDescription("will delete callback")
        let didDeleteExpectation = expectationWithDescription("did delete callback")
        let sectionChangedExpectation = expectationWithDescription("sections changed callback")

        dataSource.willDelete = { (atLocation:Location<MockTVItem>) -> Void in
            XCTAssert(atLocation.sectionID == "a")
            XCTAssert(atLocation.item.identifier == "1")
            willDeleteExpectation.fulfill()
        }

        dataSource.didDelete = { (item: MockTVItem) -> Void in
            XCTAssert(item.identifier == "1")
            didDeleteExpectation.fulfill()
        }

        dataSource.didChangeSectionIDs = { (inSectionIDs:Dictionary<String,Array<MockTVItem>>) -> Void in
            sectionChangedExpectation.fulfill()
            XCTAssert(inSectionIDs.count == 1, "should be only one section")

            guard let rows = inSectionIDs["a"] else {
                XCTFail("no rows?")
                return
            }

            let mappedIDs = rows.map({ (item) -> String in
                return item.identifier
            })

            XCTAssert(mappedIDs == ["0","2","3"])

        }

        dataSource.tableView(tableView, commitEditingStyle: UITableViewCellEditingStyle.Delete, forRowAtIndexPath: NSIndexPath(forRow: 1, inSection: 0))
        waitForExpectationsWithTimeout(10, handler: nil)
    }

//  Created by Ruotger Deecke on 28.07.15.
//  Copyright © 2015 Deecke,Roddi. All rights reserved.
//
// swiftlint:disable file_length

import XCTest

