 extension String: Diffable {
     var diffIdentifier: AnyHashable {
         return self
+    }
+}
+
+class TestObject : Diffable, Equatable {
+    let diffIdentifier: AnyHashable
+    let value: Int
+    
+    init(diffIdentifier: AnyHashable, value: Int) {
+        self.diffIdentifier = diffIdentifier
+        self.value = value
+    }
+    
+    static func ==(lhs: TestObject, rhs: TestObject) -> Bool {
+        return (lhs === rhs) || (lhs.diffIdentifier == rhs.diffIdentifier && lhs.value == rhs.value)
+    }
+}
+
+class TestObjectRef : Diffable, Equatable {
+    let diffIdentifier: AnyHashable
+    let value: Int
+    
+    init(diffIdentifier: AnyHashable, value: Int) {
+        self.diffIdentifier = diffIdentifier
+        self.value = value
+    }
+    
+    static func ==(lhs: TestObjectRef, rhs: TestObjectRef) -> Bool {
+        return lhs === rhs
+    }
+}
+
+extension NSObject : Diffable {
+    var diffIdentifier: AnyHashable {
+        return self.hash
     }
 }
 

        XCTAssertEqual(result.moves, [List.MoveIndex(from: 7, to: 4), List.MoveIndex(from: 5, to: 7)])
    }
    
    func test_whenDeletingObjects_withArrayOfEqualObjects_thatChangeCountMatches() {
        let o = Array<String>(arrayLiteral: "dog", "dog", "dog", "dog")
        let n = Array<String>(arrayLiteral: "dog", "dog")

        XCTAssertEqual(o.count + result.inserts.count - result.deletes.count, 4)
    }
    
    func test_whenInsertingObject_withOldArrayHavingMultiples_thatChangeCountMatches() {
        let o: [NSObject] = [
            NSObject(),
            NSObject(),
            NSObject(),
            NSNumber(integerLiteral: 49),
            NSNumber(integerLiteral: 33),
            NSString(string: "cat"),
            NSString(string: "cat"),
            NSNumber(integerLiteral: 0),
            NSNumber(integerLiteral: 14),
        ]
        var n = o
        n.insert(NSString(string: "cat"), at: 5)
        let result = List.diffing(oldArray: o, newArray: n)
        XCTAssertTrue(result.hasChanges)
        XCTAssertEqual(o.count + result.inserts.count - result.deletes.count, n.count)
    }
    
    func test_whenMovingDuplicateObjects_thatChangeCountMatches() {
        let o: [NSObject] = [
            NSNumber(integerLiteral: 1),
            NSNumber(integerLiteral: 20),
            NSNumber(integerLiteral: 14),
            NSObject(),
            NSString(string: "cat"),
            NSObject(),
            NSNumber(integerLiteral: 4),
            NSString(string: "dog"),
            NSString(string: "cat"),
            NSString(string: "cat"),
            NSString(string: "fish"),
            NSObject(),
            NSString(string: "fish"),
            NSObject(),
        ]
        let n: [NSObject] = [
            NSNumber(integerLiteral: 1),
            NSNumber(integerLiteral: 28),
            NSNumber(integerLiteral: 14),
            NSString(string: "cat"),
            NSString(string: "cat"),
            NSNumber(integerLiteral: 4),
            NSString(string: "dog"),
            o[3],
            NSString(string: "cat"),
            NSString(string: "fish"),
            o[11],
            NSString(string: "fish"),
            o[13],
        ]
        let result = List.diffing(oldArray: o, newArray: n)
        XCTAssertTrue(result.hasChanges)
        XCTAssertEqual(o.count + result.inserts.count - result.deletes.count, n.count)
    }
    
    func test_whenDiffingDuplicatesAtTail_withDuplicateAtHead_thatResultHasNoChanges() {
        let o: [NSObject] = [
            NSString(string: "cat"),
            NSNumber(integerLiteral: 1),
            NSNumber(integerLiteral: 2),
            NSNumber(integerLiteral: 3),
            NSString(string: "cat"),
        ]
        let n: [NSObject] = [
            NSString(string: "cat"),
            NSNumber(integerLiteral: 1),
            NSNumber(integerLiteral: 2),
            NSNumber(integerLiteral: 3),
            NSString(string: "cat"),
        ]
        let result = List.diffing(oldArray: o, newArray: n)
        XCTAssertFalse(result.hasChanges)
    }
    
    func test_whenDuplicateObjects_thatMovesAreUnique() {
        let o: [NSObject] = [
            NSString(string: "cat"),
            NSObject(),
            NSString(string: "dog"),
            NSString(string: "dog"),
            NSObject(),
            NSObject(),
            NSString(string: "cat"),
            NSNumber(integerLiteral: 65),
        ]
        let n: [NSObject] = [
            NSString(string: "cat"),
            o[1],
            NSString(string: "dog"),
            o[4],
            NSString(string: "dog"),
            o[5],
            NSString(string: "cat"),
            NSString(string: "cat"),
            NSString(string: "fish"),
            NSNumber(integerLiteral: 65),
        ]
        let result = List.diffing(oldArray: o, newArray: n)
        XCTAssertTrue(result.hasChanges)
        XCTAssertEqual(Set(result.moves.map { $0.from }).count, result.moves.count)
    }
    
    func test_whenMovingObjectShiftsOthers_thatMovesContainRequiredMoves() {
        let o = Array<Int>(arrayLiteral: 1, 2, 3, 4, 5, 6, 7)
