Skip to content

Commit

Permalink
Fix comparing unmanaged lists (#6845)
Browse files Browse the repository at this point in the history
  • Loading branch information
leemaguire authored Oct 12, 2020
1 parent 709425f commit c777ff5
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ x.y.z Release notes (yyyy-MM-dd)
* When using `Realm.write(withoutNotifying:)` there was a chance that the
supplied observation blocks would not be skipped when in a write transaction.
([Object Store #1103](https://github.com/realm/realm-object-store/pull/1103))
* Comparing two identical unmanaged `List<>`/`RLMArray` objects would fail.
([#5665](https://github.com/realm/realm-cocoa/issues/5665)).

<!-- ### Breaking Changes - ONLY INCLUDE FOR NEW MAJOR version -->

Expand Down
9 changes: 9 additions & 0 deletions Realm/RLMArray.mm
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,15 @@ - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes {
return [_backingArray objectsAtIndexes:indexes];
}

- (BOOL)isEqual:(id)object {
if (auto array = RLMDynamicCast<RLMArray>(object)) {
return !array.realm
&& ((_backingArray.count == 0 && array->_backingArray.count == 0)
|| [_backingArray isEqual:array->_backingArray]);
}
return NO;
}

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options context:(void *)context {
RLMValidateArrayObservationKey(keyPath, self);
Expand Down
10 changes: 10 additions & 0 deletions Realm/RLMListBase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ - (void)addObserver:(id)observer
[super addObserver:observer forKeyPath:keyPath options:options context:context];
}

- (BOOL)isEqual:(id)object {
if (auto array = RLMDynamicCast<RLMListBase>(object)) {
return !array._rlmArray.realm
&& ((self._rlmArray.count == 0 && array._rlmArray.count == 0) ||
[self._rlmArray isEqual:array._rlmArray]);
}
return NO;
}

@end

@implementation RLMLinkingObjectsHandle {
Expand Down Expand Up @@ -144,4 +153,5 @@ - (RLMResults *)results {
_realm = nil;
return _results;
}

@end
43 changes: 43 additions & 0 deletions Realm/Tests/ArrayPropertyTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,49 @@ - (void)testUnmanaged {
__unused ArrayPropertyObject *obj = [[ArrayPropertyObject alloc] initWithValue:@[@"n", @[], @[[[IntObject alloc] initWithValue:@[@1]]]]];
}

- (void)testUnmanagedComparision {
RLMRealm *realm = [self realmWithTestPath];

ArrayPropertyObject *array = [[ArrayPropertyObject alloc] init];
ArrayPropertyObject *array2 = [[ArrayPropertyObject alloc] init];

array.name = @"name";
array2.name = @"name2";
XCTAssertNotNil(array.array, @"RLMArray property should get created on access");
XCTAssertNotNil(array2.array, @"RLMArray property should get created on access");
XCTAssertTrue([array.array isEqual:array2.array], @"Empty arrays should be equal");

XCTAssertNil(array.array.firstObject, @"No objects added yet");
XCTAssertNil(array2.array.lastObject, @"No objects added yet");

StringObject *obj1 = [[StringObject alloc] init];
obj1.stringCol = @"a";
StringObject *obj2 = [[StringObject alloc] init];
obj2.stringCol = @"b";
StringObject *obj3 = [[StringObject alloc] init];
obj3.stringCol = @"c";
[array.array addObject:obj1];
[array.array addObject:obj2];
[array.array addObject:obj3];

[array2.array addObject:obj1];
[array2.array addObject:obj2];
[array2.array addObject:obj3];

XCTAssertTrue([array.array isEqual:array2.array], @"Arrays should be equal");
[array2.array removeLastObject];
XCTAssertFalse([array.array isEqual:array2.array], @"Arrays should not be equal");
[array2.array addObject:obj3];
XCTAssertTrue([array.array isEqual:array2.array], @"Arrays should be equal");

[realm beginWriteTransaction];
[realm addObject:array];
[realm commitWriteTransaction];

XCTAssertFalse([array.array isEqual:array2.array], @"Comparing a managed array to an unmanaged one should fail");
XCTAssertFalse([array2.array isEqual:array.array], @"Comparing a managed array to an unmanaged one should fail");
}

- (void)testUnmanagedPrimitive {
AllPrimitiveArrays *obj = [[AllPrimitiveArrays alloc] init];
XCTAssertTrue([obj.intObj isKindOfClass:[RLMArray class]]);
Expand Down
35 changes: 35 additions & 0 deletions RealmSwift/Tests/ListTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,41 @@ class ListTests: TestCase {
}
}
}

func testUnmanagedListComparison() {
let obj = SwiftIntObject()
obj.intCol = 5
let obj2 = SwiftIntObject()
obj2.intCol = 6
let obj3 = SwiftIntObject()
obj3.intCol = 8

let objects = [obj, obj2, obj3]
let objects2 = [obj, obj2]

let list1 = List<SwiftIntObject>()
let list2 = List<SwiftIntObject>()
XCTAssertEqual(list1, list2, "Empty instances should be equal by `==` operator")

list1.append(objectsIn: objects)
list2.append(objectsIn: objects)

let list3 = List<SwiftIntObject>()
list3.append(objectsIn: objects2)

XCTAssertTrue(list1 !== list2, "instances should not be identical")

XCTAssertEqual(list1, list2, "instances should be equal by `==` operator")
XCTAssertNotEqual(list1, list3, "instances should be equal by `==` operator")

XCTAssertTrue(list1.isEqual(list2), "instances should be equal by `isEqual` method")
XCTAssertTrue(!list1.isEqual(list3), "instances should be equal by `isEqual` method")

XCTAssertEqual(Array(list1), Array(list2), "instances converted to Swift.Array should be equal")
XCTAssertNotEqual(Array(list1), Array(list3), "instances converted to Swift.Array should be equal")
list3.append(obj3)
XCTAssertEqual(list1, list3, "instances should be equal by `==` operator")
}
}

class ListStandaloneTests: ListTests {
Expand Down

0 comments on commit c777ff5

Please sign in to comment.