An amazing project that generates micro reports from tournament results
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pa-tournament-stats/Carthage/Checkouts/realm-cocoa/Realm/Tests/PrimitiveArrayPropertyTests...

830 lines
38 KiB

////////////////////////////////////////////////////////////////////////////
//
// Copyright 2017 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#import "RLMTestCase.h"
@interface PrimitiveArrayPropertyTests : RLMTestCase
@end
@implementation PrimitiveArrayPropertyTests {
AllPrimitiveArrays *unmanaged;
AllPrimitiveArrays *managed;
AllOptionalPrimitiveArrays *optUnmanaged;
AllOptionalPrimitiveArrays *optManaged;
RLMRealm *realm;
}
- (void)setUp {
unmanaged = [[AllPrimitiveArrays alloc] init];
optUnmanaged = [[AllOptionalPrimitiveArrays alloc] init];
realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
managed = [AllPrimitiveArrays createInRealm:realm withValue:@[]];
optManaged = [AllOptionalPrimitiveArrays createInRealm:realm withValue:@[]];
}
- (void)tearDown {
if (realm.inWriteTransaction) {
[realm cancelWriteTransaction];
}
}
- (void)testCount {
XCTAssertEqual(unmanaged.intObj.count, 0U);
[unmanaged.intObj addObject:@1];
XCTAssertEqual(unmanaged.intObj.count, 1U);
}
- (void)testType {
XCTAssertEqual(unmanaged.boolObj.type, RLMPropertyTypeBool);
XCTAssertEqual(unmanaged.intObj.type, RLMPropertyTypeInt);
XCTAssertEqual(unmanaged.floatObj.type, RLMPropertyTypeFloat);
XCTAssertEqual(unmanaged.doubleObj.type, RLMPropertyTypeDouble);
XCTAssertEqual(unmanaged.stringObj.type, RLMPropertyTypeString);
XCTAssertEqual(unmanaged.dataObj.type, RLMPropertyTypeData);
XCTAssertEqual(unmanaged.dateObj.type, RLMPropertyTypeDate);
XCTAssertEqual(optUnmanaged.boolObj.type, RLMPropertyTypeBool);
XCTAssertEqual(optUnmanaged.intObj.type, RLMPropertyTypeInt);
XCTAssertEqual(optUnmanaged.floatObj.type, RLMPropertyTypeFloat);
XCTAssertEqual(optUnmanaged.doubleObj.type, RLMPropertyTypeDouble);
XCTAssertEqual(optUnmanaged.stringObj.type, RLMPropertyTypeString);
XCTAssertEqual(optUnmanaged.dataObj.type, RLMPropertyTypeData);
XCTAssertEqual(optUnmanaged.dateObj.type, RLMPropertyTypeDate);
}
- (void)testOptional {
XCTAssertFalse(unmanaged.boolObj.optional);
XCTAssertFalse(unmanaged.intObj.optional);
XCTAssertFalse(unmanaged.floatObj.optional);
XCTAssertFalse(unmanaged.doubleObj.optional);
XCTAssertFalse(unmanaged.stringObj.optional);
XCTAssertFalse(unmanaged.dataObj.optional);
XCTAssertFalse(unmanaged.dateObj.optional);
XCTAssertTrue(optUnmanaged.boolObj.optional);
XCTAssertTrue(optUnmanaged.intObj.optional);
XCTAssertTrue(optUnmanaged.floatObj.optional);
XCTAssertTrue(optUnmanaged.doubleObj.optional);
XCTAssertTrue(optUnmanaged.stringObj.optional);
XCTAssertTrue(optUnmanaged.dataObj.optional);
XCTAssertTrue(optUnmanaged.dateObj.optional);
}
- (void)testObjectClassName {
XCTAssertNil(unmanaged.boolObj.objectClassName);
XCTAssertNil(unmanaged.intObj.objectClassName);
XCTAssertNil(unmanaged.floatObj.objectClassName);
XCTAssertNil(unmanaged.doubleObj.objectClassName);
XCTAssertNil(unmanaged.stringObj.objectClassName);
XCTAssertNil(unmanaged.dataObj.objectClassName);
XCTAssertNil(unmanaged.dateObj.objectClassName);
XCTAssertNil(optUnmanaged.boolObj.objectClassName);
XCTAssertNil(optUnmanaged.intObj.objectClassName);
XCTAssertNil(optUnmanaged.floatObj.objectClassName);
XCTAssertNil(optUnmanaged.doubleObj.objectClassName);
XCTAssertNil(optUnmanaged.stringObj.objectClassName);
XCTAssertNil(optUnmanaged.dataObj.objectClassName);
XCTAssertNil(optUnmanaged.dateObj.objectClassName);
}
- (void)testRealm {
XCTAssertNil(unmanaged.boolObj.realm);
XCTAssertNil(unmanaged.intObj.realm);
XCTAssertNil(unmanaged.floatObj.realm);
XCTAssertNil(unmanaged.doubleObj.realm);
XCTAssertNil(unmanaged.stringObj.realm);
XCTAssertNil(unmanaged.dataObj.realm);
XCTAssertNil(unmanaged.dateObj.realm);
XCTAssertNil(optUnmanaged.boolObj.realm);
XCTAssertNil(optUnmanaged.intObj.realm);
XCTAssertNil(optUnmanaged.floatObj.realm);
XCTAssertNil(optUnmanaged.doubleObj.realm);
XCTAssertNil(optUnmanaged.stringObj.realm);
XCTAssertNil(optUnmanaged.dataObj.realm);
XCTAssertNil(optUnmanaged.dateObj.realm);
}
- (void)testInvalidated {
RLMArray *array;
@autoreleasepool {
AllPrimitiveArrays *obj = [[AllPrimitiveArrays alloc] init];
array = obj.intObj;
XCTAssertFalse(array.invalidated);
}
XCTAssertFalse(array.invalidated);
}
- (void)testDeleteObjectsInRealm {
RLMAssertThrowsWithReason([realm deleteObjects:$array], @"Cannot delete objects from RLMArray");
}
static NSDate *date(int i) {
return [NSDate dateWithTimeIntervalSince1970:i];
}
static NSData *data(int i) {
return [NSData dataWithBytesNoCopy:calloc(i, 1) length:i freeWhenDone:YES];
}
- (void)testObjectAtIndex {
RLMAssertThrowsWithReason([unmanaged.intObj objectAtIndex:0],
@"Index 0 is out of bounds (must be less than 0).");
[unmanaged.intObj addObject:@1];
XCTAssertEqualObjects([unmanaged.intObj objectAtIndex:0], @1);
}
- (void)testFirstObject {
XCTAssertNil($array.firstObject);
%r [$array addObjects:$values];
%r XCTAssertEqualObjects($array.firstObject, $first);
%o [$array addObject:NSNull.null];
%o XCTAssertEqualObjects($array.firstObject, NSNull.null);
%o [$array removeAllObjects];
%o [$array addObjects:$values];
%o XCTAssertEqualObjects($array.firstObject, $first);
}
- (void)testLastObject {
XCTAssertNil($array.lastObject);
[$array addObjects:$values];
XCTAssertEqualObjects($array.lastObject, $last);
%o [$array removeLastObject];
%o XCTAssertEqualObjects($array.lastObject, $v1);
}
- (void)testAddObject {
RLMAssertThrowsWithReason([$array addObject:$wrong], ^n @"Invalid value '$wdesc' of type '$wtype' for expected type '$type'");
%r RLMAssertThrowsWithReason([$array addObject:NSNull.null], ^n @"Invalid value '<null>' of type 'NSNull' for expected type '$type'");
[$array addObject:$v0];
XCTAssertEqualObjects($array[0], $v0);
%o [$array addObject:NSNull.null];
%o XCTAssertEqualObjects($array[1], NSNull.null);
}
- (void)testAddObjects {
RLMAssertThrowsWithReason([$array addObjects:@[$wrong]], ^n @"Invalid value '$wdesc' of type '$wtype' for expected type '$type'");
%r RLMAssertThrowsWithReason([$array addObjects:@[NSNull.null]], ^n @"Invalid value '<null>' of type 'NSNull' for expected type '$type'");
[$array addObjects:$values];
XCTAssertEqualObjects($array[0], $v0);
XCTAssertEqualObjects($array[1], $v1);
%o XCTAssertEqualObjects($array[2], NSNull.null);
}
- (void)testInsertObject {
RLMAssertThrowsWithReason([$array insertObject:$wrong atIndex:0], ^n @"Invalid value '$wdesc' of type '$wtype' for expected type '$type'");
%r RLMAssertThrowsWithReason([$array insertObject:NSNull.null atIndex:0], ^n @"Invalid value '<null>' of type 'NSNull' for expected type '$type'");
RLMAssertThrowsWithReason([$array insertObject:$v0 atIndex:1], ^n @"Index 1 is out of bounds (must be less than 1).");
[$array insertObject:$v0 atIndex:0];
XCTAssertEqualObjects($array[0], $v0);
[$array insertObject:$v1 atIndex:0];
XCTAssertEqualObjects($array[0], $v1);
XCTAssertEqualObjects($array[1], $v0);
%o [$array insertObject:NSNull.null atIndex:1];
%o XCTAssertEqualObjects($array[0], $v1);
%o XCTAssertEqualObjects($array[1], NSNull.null);
%o XCTAssertEqualObjects($array[2], $v0);
}
- (void)testRemoveObject {
RLMAssertThrowsWithReason([$array removeObjectAtIndex:0], ^n @"Index 0 is out of bounds (must be less than 0).");
[$array addObjects:$values];
%r XCTAssertEqual($array.count, 2U);
%o XCTAssertEqual($array.count, 3U);
%r RLMAssertThrowsWithReason([$array removeObjectAtIndex:2], ^n @"Index 2 is out of bounds (must be less than 2).");
%o RLMAssertThrowsWithReason([$array removeObjectAtIndex:3], ^n @"Index 3 is out of bounds (must be less than 3).");
[$array removeObjectAtIndex:0];
%r XCTAssertEqual($array.count, 1U);
%o XCTAssertEqual($array.count, 2U);
XCTAssertEqualObjects($array[0], $v1);
%o XCTAssertEqualObjects($array[1], NSNull.null);
}
- (void)testRemoveLastObject {
XCTAssertNoThrow([$array removeLastObject]);
[$array addObjects:$values];
%r XCTAssertEqual($array.count, 2U);
%o XCTAssertEqual($array.count, 3U);
[$array removeLastObject];
%r XCTAssertEqual($array.count, 1U);
%o XCTAssertEqual($array.count, 2U);
XCTAssertEqualObjects($array[0], $v0);
%o XCTAssertEqualObjects($array[1], $v1);
}
- (void)testReplace {
RLMAssertThrowsWithReason([$array replaceObjectAtIndex:0 withObject:$v0], ^n @"Index 0 is out of bounds (must be less than 0).");
[$array addObject:$v0]; ^nl [$array replaceObjectAtIndex:0 withObject:$v1]; ^nl XCTAssertEqualObjects($array[0], $v1); ^nl
%o [$array replaceObjectAtIndex:0 withObject:NSNull.null]; ^nl XCTAssertEqualObjects($array[0], NSNull.null);
RLMAssertThrowsWithReason([$array replaceObjectAtIndex:0 withObject:$wrong], ^n @"Invalid value '$wdesc' of type '$wtype' for expected type '$type'");
%r RLMAssertThrowsWithReason([$array replaceObjectAtIndex:0 withObject:NSNull.null], ^n @"Invalid value '<null>' of type 'NSNull' for expected type '$type'");
}
- (void)testMove {
RLMAssertThrowsWithReason([$array moveObjectAtIndex:0 toIndex:1], ^n @"Index 0 is out of bounds (must be less than 0).");
RLMAssertThrowsWithReason([$array moveObjectAtIndex:1 toIndex:0], ^n @"Index 1 is out of bounds (must be less than 0).");
[$array addObjects:@[$v0, $v1, $v0, $v1]];
[$array moveObjectAtIndex:2 toIndex:0];
XCTAssertEqualObjects([$array valueForKey:@"self"], ^n (@[$v0, $v0, $v1, $v1]));
}
- (void)testExchange {
RLMAssertThrowsWithReason([$array exchangeObjectAtIndex:0 withObjectAtIndex:1], ^n @"Index 0 is out of bounds (must be less than 0).");
RLMAssertThrowsWithReason([$array exchangeObjectAtIndex:1 withObjectAtIndex:0], ^n @"Index 1 is out of bounds (must be less than 0).");
[$array addObjects:@[$v0, $v1, $v0, $v1]];
[$array exchangeObjectAtIndex:2 withObjectAtIndex:1];
XCTAssertEqualObjects([$array valueForKey:@"self"], ^n (@[$v0, $v0, $v1, $v1]));
}
- (void)testIndexOfObject {
XCTAssertEqual(NSNotFound, [$array indexOfObject:$v0]);
RLMAssertThrowsWithReason([$array indexOfObject:$wrong], ^n @"Invalid value '$wdesc' of type '$wtype' for expected type '$type'");
%r RLMAssertThrowsWithReason([$array indexOfObject:NSNull.null], ^n @"Invalid value '<null>' of type 'NSNull' for expected type '$type'");
%o XCTAssertEqual(NSNotFound, [$array indexOfObject:NSNull.null]);
[$array addObjects:$values];
XCTAssertEqual(1U, [$array indexOfObject:$v1]);
}
- (void)testIndexOfObjectWhere {
%man RLMAssertThrowsWithReason([$array indexOfObjectWhere:@"TRUEPREDICATE"], @"implemented");
%man RLMAssertThrowsWithReason([[$array sortedResultsUsingKeyPath:@"self" ascending:NO] ^n indexOfObjectWhere:@"TRUEPREDICATE"], @"implemented");
%unman XCTAssertEqual(NSNotFound, [$array indexOfObjectWhere:@"TRUEPREDICATE"]);
%unman [$array addObjects:$values];
%unman XCTAssertEqual(0U, [$array indexOfObjectWhere:@"TRUEPREDICATE"]);
%unman XCTAssertEqual(NSNotFound, [$array indexOfObjectWhere:@"FALSEPREDICATE"]);
}
- (void)testIndexOfObjectWithPredicate {
%man RLMAssertThrowsWithReason([$array indexOfObjectWithPredicate:[NSPredicate predicateWithValue:YES]], @"implemented");
%man RLMAssertThrowsWithReason([[$array sortedResultsUsingKeyPath:@"self" ascending:NO] ^n indexOfObjectWithPredicate:[NSPredicate predicateWithValue:YES]], @"implemented");
%unman XCTAssertEqual(NSNotFound, [$array indexOfObjectWithPredicate:[NSPredicate predicateWithValue:YES]]);
%unman [$array addObjects:$values];
%unman XCTAssertEqual(0U, [$array indexOfObjectWithPredicate:[NSPredicate predicateWithValue:YES]]);
%unman XCTAssertEqual(NSNotFound, [$array indexOfObjectWithPredicate:[NSPredicate predicateWithValue:NO]]);
}
- (void)testSort {
%unman RLMAssertThrowsWithReason([$array sortedResultsUsingKeyPath:@"self" ascending:NO], ^n @"This method may only be called on RLMArray instances retrieved from an RLMRealm");
%unman RLMAssertThrowsWithReason([$array sortedResultsUsingDescriptors:@[]], ^n @"This method may only be called on RLMArray instances retrieved from an RLMRealm");
%man RLMAssertThrowsWithReason([$array sortedResultsUsingKeyPath:@"not self" ascending:NO], ^n @"can only be sorted on 'self'");
%man %r [$array addObjects:@[$v0, $v1, $v0]];
%man %o [$array addObjects:@[$v0, $v1, NSNull.null, $v1, $v0]];
%man %r XCTAssertEqualObjects([[$array sortedResultsUsingDescriptors:@[]] valueForKey:@"self"], ^n (@[$v0, $v1, $v0]));
%man %o XCTAssertEqualObjects([[$array sortedResultsUsingDescriptors:@[]] valueForKey:@"self"], ^n (@[$v0, $v1, NSNull.null, $v1, $v0]));
%man %r XCTAssertEqualObjects([[$array sortedResultsUsingKeyPath:@"self" ascending:NO] valueForKey:@"self"], ^n (@[$v1, $v0, $v0]));
%man %o XCTAssertEqualObjects([[$array sortedResultsUsingKeyPath:@"self" ascending:NO] valueForKey:@"self"], ^n (@[$v1, $v1, $v0, $v0, NSNull.null]));
%man %r XCTAssertEqualObjects([[$array sortedResultsUsingKeyPath:@"self" ascending:YES] valueForKey:@"self"], ^n (@[$v0, $v0, $v1]));
%man %o XCTAssertEqualObjects([[$array sortedResultsUsingKeyPath:@"self" ascending:YES] valueForKey:@"self"], ^n (@[NSNull.null, $v0, $v0, $v1, $v1]));
}
- (void)testFilter {
%unman RLMAssertThrowsWithReason([$array objectsWhere:@"TRUEPREDICATE"], ^n @"This method may only be called on RLMArray instances retrieved from an RLMRealm");
%unman RLMAssertThrowsWithReason([$array objectsWithPredicate:[NSPredicate predicateWithValue:YES]], ^n @"This method may only be called on RLMArray instances retrieved from an RLMRealm");
%man RLMAssertThrowsWithReason([$array objectsWhere:@"TRUEPREDICATE"], ^n @"implemented");
%man RLMAssertThrowsWithReason([$array objectsWithPredicate:[NSPredicate predicateWithValue:YES]], ^n @"implemented");
%man RLMAssertThrowsWithReason([[$array sortedResultsUsingKeyPath:@"self" ascending:NO] ^n objectsWhere:@"TRUEPREDICATE"], @"implemented");
%man RLMAssertThrowsWithReason([[$array sortedResultsUsingKeyPath:@"self" ascending:NO] ^n objectsWithPredicate:[NSPredicate predicateWithValue:YES]], @"implemented");
}
- (void)testNotifications {
%unman RLMAssertThrowsWithReason([$array addNotificationBlock:^(__unused id a, __unused id c, __unused id e) { }], ^n @"This method may only be called on RLMArray instances retrieved from an RLMRealm");
}
- (void)testMin {
%nominmax %unman RLMAssertThrowsWithReason([$array minOfProperty:@"self"], ^n @"minOfProperty: is not supported for $type array");
%nominmax %man RLMAssertThrowsWithReason([$array minOfProperty:@"self"], ^n @"minOfProperty: is not supported for $type array '$class.$prop'");
%minmax XCTAssertNil([$array minOfProperty:@"self"]);
%minmax [$array addObjects:$values];
%minmax XCTAssertEqualObjects([$array minOfProperty:@"self"], $v0);
}
- (void)testMax {
%nominmax %unman RLMAssertThrowsWithReason([$array maxOfProperty:@"self"], ^n @"maxOfProperty: is not supported for $type array");
%nominmax %man RLMAssertThrowsWithReason([$array maxOfProperty:@"self"], ^n @"maxOfProperty: is not supported for $type array '$class.$prop'");
%minmax XCTAssertNil([$array maxOfProperty:@"self"]);
%minmax [$array addObjects:$values];
%minmax XCTAssertEqualObjects([$array maxOfProperty:@"self"], $v1);
}
- (void)testSum {
%nosum %unman RLMAssertThrowsWithReason([$array sumOfProperty:@"self"], ^n @"sumOfProperty: is not supported for $type array");
%nosum %man RLMAssertThrowsWithReason([$array sumOfProperty:@"self"], ^n @"sumOfProperty: is not supported for $type array '$class.$prop'");
%sum XCTAssertEqualObjects([$array sumOfProperty:@"self"], @0);
%sum [$array addObjects:$values];
%sum XCTAssertEqualObjects([$array sumOfProperty:@"self"], @($s0 + $s1));
}
- (void)testAverage {
%noavg %unman RLMAssertThrowsWithReason([$array averageOfProperty:@"self"], ^n @"averageOfProperty: is not supported for $type array");
%noavg %man RLMAssertThrowsWithReason([$array averageOfProperty:@"self"], ^n @"averageOfProperty: is not supported for $type array '$class.$prop'");
%avg XCTAssertNil([$array averageOfProperty:@"self"]);
%avg [$array addObjects:$values];
%avg XCTAssertEqualWithAccuracy([$array averageOfProperty:@"self"].doubleValue, ($s0 + $s1) / 2.0, .001);
}
- (void)testFastEnumeration {
for (int i = 0; i < 10; ++i) {
[$array addObjects:$values];
}
{ ^nl NSUInteger i = 0; ^nl NSArray *values = $values; ^nl for (id value in $array) { ^nl XCTAssertEqualObjects(values[i++ % values.count], value); ^nl } ^nl XCTAssertEqual(i, $array.count); ^nl } ^nl
}
- (void)testValueForKeySelf {
XCTAssertEqualObjects([$array valueForKey:@"self"], @[]);
[$array addObjects:$values];
XCTAssertEqualObjects([$array valueForKey:@"self"], ($values));
}
- (void)testValueForKeyNumericAggregates {
%minmax XCTAssertNil([$array valueForKeyPath:@"@min.self"]);
%minmax XCTAssertNil([$array valueForKeyPath:@"@max.self"]);
%sum XCTAssertEqualObjects([$array valueForKeyPath:@"@sum.self"], @0);
%avg XCTAssertNil([$array valueForKeyPath:@"@avg.self"]);
[$array addObjects:$values];
%minmax XCTAssertEqualObjects([$array valueForKeyPath:@"@min.self"], $v0);
%minmax XCTAssertEqualObjects([$array valueForKeyPath:@"@max.self"], $v1);
%sum XCTAssertEqualObjects([$array valueForKeyPath:@"@sum.self"], @($s0 + $s1));
%avg XCTAssertEqualWithAccuracy([[$array valueForKeyPath:@"@avg.self"] doubleValue], ($s0 + $s1) / 2.0, .001);
}
// Sort the distinct results to match the order used in values, as it
// doesn't preserve the order naturally
static NSArray *sortedDistinctUnion(id array, NSString *type, NSString *prop) {
return [[array valueForKeyPath:[NSString stringWithFormat:@"@distinctUnionOf%@.%@", type, prop]]
sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
bool aIsNull = a == NSNull.null;
bool bIsNull = b == NSNull.null;
if (aIsNull && bIsNull) {
return 0;
}
if (aIsNull) {
return 1;
}
if (bIsNull) {
return -1;
}
if ([a isKindOfClass:[NSData class]]) {
if ([a length] != [b length]) {
return [a length] < [b length] ? -1 : 1;
}
int result = memcmp([a bytes], [b bytes], [a length]);
if (!result) {
return 0;
}
return result < 0 ? -1 : 1;
}
return [a compare:b];
}];
}
- (void)testUnionOfObjects {
XCTAssertEqualObjects([$array valueForKeyPath:@"@unionOfObjects.self"], @[]);
XCTAssertEqualObjects([$array valueForKeyPath:@"@distinctUnionOfObjects.self"], @[]);
[$array addObjects:$values2];
XCTAssertEqualObjects([$array valueForKeyPath:@"@unionOfObjects.self"], ^n ($values2));
XCTAssertEqualObjects(sortedDistinctUnion($array, @"Objects", @"self"), ^n ($values));
}
- (void)testUnionOfArrays {
RLMResults *allRequired = [AllPrimitiveArrays allObjectsInRealm:realm];
RLMResults *allOptional = [AllOptionalPrimitiveArrays allObjectsInRealm:realm];
%man %r XCTAssertEqualObjects([allRequired valueForKeyPath:@"@unionOfArrays.$prop"], @[]);
%man %o XCTAssertEqualObjects([allOptional valueForKeyPath:@"@unionOfArrays.$prop"], @[]);
%man %r XCTAssertEqualObjects([allRequired valueForKeyPath:@"@distinctUnionOfArrays.$prop"], @[]);
%man %o XCTAssertEqualObjects([allOptional valueForKeyPath:@"@distinctUnionOfArrays.$prop"], @[]);
[$array addObjects:$values];
[AllPrimitiveArrays createInRealm:realm withValue:managed];
[AllOptionalPrimitiveArrays createInRealm:realm withValue:optManaged];
%man %r XCTAssertEqualObjects([allRequired valueForKeyPath:@"@unionOfArrays.$prop"], ^n ($values2));
%man %o XCTAssertEqualObjects([allOptional valueForKeyPath:@"@unionOfArrays.$prop"], ^n ($values2));
%man %r XCTAssertEqualObjects(sortedDistinctUnion(allRequired, @"Arrays", @"$prop"), ^n ($values));
%man %o XCTAssertEqualObjects(sortedDistinctUnion(allOptional, @"Arrays", @"$prop"), ^n ($values));
}
- (void)testSetValueForKey {
RLMAssertThrowsWithReason([$array setValue:@0 forKey:@"not self"], ^n @"this class is not key value coding-compliant for the key not self.");
RLMAssertThrowsWithReason([$array setValue:$wrong forKey:@"self"], ^n @"Invalid value '$wdesc' of type '$wtype' for expected type '$type'");
%r RLMAssertThrowsWithReason([$array setValue:NSNull.null forKey:@"self"], ^n @"Invalid value '<null>' of type 'NSNull' for expected type '$type'");
[$array addObjects:$values];
[$array setValue:$v0 forKey:@"self"];
XCTAssertEqualObjects($array[0], $v0);
XCTAssertEqualObjects($array[1], $v0);
%o XCTAssertEqualObjects($array[2], $v0);
%o [$array setValue:NSNull.null forKey:@"self"];
%o XCTAssertEqualObjects($array[0], NSNull.null);
}
- (void)testAssignment {
$array = (id)@[$v1]; ^nl XCTAssertEqualObjects($array[0], $v1);
// Should replace and not append
$array = (id)$values; ^nl XCTAssertEqualObjects([$array valueForKey:@"self"], ($values)); ^nl
// Should not clear the array
$array = $array; ^nl XCTAssertEqualObjects([$array valueForKey:@"self"], ($values)); ^nl
[unmanaged.intObj removeAllObjects];
unmanaged.intObj = managed.intObj;
XCTAssertEqualObjects([unmanaged.intObj valueForKey:@"self"], (@[@2, @3]));
[managed.intObj removeAllObjects];
managed.intObj = unmanaged.intObj;
XCTAssertEqualObjects([managed.intObj valueForKey:@"self"], (@[@2, @3]));
}
- (void)testDynamicAssignment {
$obj[@"$prop"] = (id)@[$v1]; ^nl XCTAssertEqualObjects($obj[@"$prop"][0], $v1);
// Should replace and not append
$obj[@"$prop"] = (id)$values; ^nl XCTAssertEqualObjects([$obj[@"$prop"] valueForKey:@"self"], ($values)); ^nl
// Should not clear the array
$obj[@"$prop"] = $obj[@"$prop"]; ^nl XCTAssertEqualObjects([$obj[@"$prop"] valueForKey:@"self"], ($values)); ^nl
[unmanaged[@"intObj"] removeAllObjects];
unmanaged[@"intObj"] = managed.intObj;
XCTAssertEqualObjects([unmanaged[@"intObj"] valueForKey:@"self"], (@[@2, @3]));
[managed[@"intObj"] removeAllObjects];
managed[@"intObj"] = unmanaged.intObj;
XCTAssertEqualObjects([managed[@"intObj"] valueForKey:@"self"], (@[@2, @3]));
}
- (void)testInvalidAssignment {
RLMAssertThrowsWithReason(unmanaged.intObj = (id)@[NSNull.null],
@"Invalid value '<null>' of type 'NSNull' for 'int' array property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(unmanaged.intObj = (id)@[@"a"],
@"Invalid value 'a' of type '__NSCFConstantString' for 'int' array property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(unmanaged.intObj = (id)(@[@1, @"a"]),
@"Invalid value 'a' of type '__NSCFConstantString' for 'int' array property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(unmanaged.intObj = (id)unmanaged.floatObj,
@"RLMArray<float> does not match expected type 'int' for property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(unmanaged.intObj = (id)optUnmanaged.intObj,
@"RLMArray<int?> does not match expected type 'int' for property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(unmanaged[@"intObj"] = unmanaged[@"floatObj"],
@"RLMArray<float> does not match expected type 'int' for property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(unmanaged[@"intObj"] = optUnmanaged[@"intObj"],
@"RLMArray<int?> does not match expected type 'int' for property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(managed.intObj = (id)@[NSNull.null],
@"Invalid value '<null>' of type 'NSNull' for 'int' array property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(managed.intObj = (id)@[@"a"],
@"Invalid value 'a' of type '__NSCFConstantString' for 'int' array property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(managed.intObj = (id)(@[@1, @"a"]),
@"Invalid value 'a' of type '__NSCFConstantString' for 'int' array property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(managed.intObj = (id)managed.floatObj,
@"RLMArray<float> does not match expected type 'int' for property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(managed.intObj = (id)optManaged.intObj,
@"RLMArray<int?> does not match expected type 'int' for property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(managed[@"intObj"] = (id)managed[@"floatObj"],
@"RLMArray<float> does not match expected type 'int' for property 'AllPrimitiveArrays.intObj'.");
RLMAssertThrowsWithReason(managed[@"intObj"] = (id)optManaged[@"intObj"],
@"RLMArray<int?> does not match expected type 'int' for property 'AllPrimitiveArrays.intObj'.");
}
- (void)testAllMethodsCheckThread {
RLMArray *array = managed.intObj;
[self dispatchAsyncAndWait:^{
RLMAssertThrowsWithReason([array count], @"thread");
RLMAssertThrowsWithReason([array objectAtIndex:0], @"thread");
RLMAssertThrowsWithReason([array firstObject], @"thread");
RLMAssertThrowsWithReason([array lastObject], @"thread");
RLMAssertThrowsWithReason([array addObject:@0], @"thread");
RLMAssertThrowsWithReason([array addObjects:@[@0]], @"thread");
RLMAssertThrowsWithReason([array insertObject:@0 atIndex:0], @"thread");
RLMAssertThrowsWithReason([array removeObjectAtIndex:0], @"thread");
RLMAssertThrowsWithReason([array removeLastObject], @"thread");
RLMAssertThrowsWithReason([array removeAllObjects], @"thread");
RLMAssertThrowsWithReason([array replaceObjectAtIndex:0 withObject:@0], @"thread");
RLMAssertThrowsWithReason([array moveObjectAtIndex:0 toIndex:1], @"thread");
RLMAssertThrowsWithReason([array exchangeObjectAtIndex:0 withObjectAtIndex:1], @"thread");
RLMAssertThrowsWithReason([array indexOfObject:@1], @"thread");
/* RLMAssertThrowsWithReason([array indexOfObjectWhere:@"TRUEPREDICATE"], @"thread"); */
/* RLMAssertThrowsWithReason([array indexOfObjectWithPredicate:[NSPredicate predicateWithValue:NO]], @"thread"); */
/* RLMAssertThrowsWithReason([array objectsWhere:@"TRUEPREDICATE"], @"thread"); */
/* RLMAssertThrowsWithReason([array objectsWithPredicate:[NSPredicate predicateWithValue:NO]], @"thread"); */
RLMAssertThrowsWithReason([array sortedResultsUsingKeyPath:@"self" ascending:YES], @"thread");
RLMAssertThrowsWithReason([array sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:@"self" ascending:YES]]], @"thread");
RLMAssertThrowsWithReason(array[0], @"thread");
RLMAssertThrowsWithReason(array[0] = @0, @"thread");
RLMAssertThrowsWithReason([array valueForKey:@"self"], @"thread");
RLMAssertThrowsWithReason([array setValue:@1 forKey:@"self"], @"thread");
RLMAssertThrowsWithReason({for (__unused id obj in array);}, @"thread");
}];
}
- (void)testAllMethodsCheckForInvalidation {
RLMArray *array = managed.intObj;
[realm cancelWriteTransaction];
[realm invalidate];
XCTAssertNoThrow([array objectClassName]);
XCTAssertNoThrow([array realm]);
XCTAssertNoThrow([array isInvalidated]);
RLMAssertThrowsWithReason([array count], @"invalidated");
RLMAssertThrowsWithReason([array objectAtIndex:0], @"invalidated");
RLMAssertThrowsWithReason([array firstObject], @"invalidated");
RLMAssertThrowsWithReason([array lastObject], @"invalidated");
RLMAssertThrowsWithReason([array addObject:@0], @"invalidated");
RLMAssertThrowsWithReason([array addObjects:@[@0]], @"invalidated");
RLMAssertThrowsWithReason([array insertObject:@0 atIndex:0], @"invalidated");
RLMAssertThrowsWithReason([array removeObjectAtIndex:0], @"invalidated");
RLMAssertThrowsWithReason([array removeLastObject], @"invalidated");
RLMAssertThrowsWithReason([array removeAllObjects], @"invalidated");
RLMAssertThrowsWithReason([array replaceObjectAtIndex:0 withObject:@0], @"invalidated");
RLMAssertThrowsWithReason([array moveObjectAtIndex:0 toIndex:1], @"invalidated");
RLMAssertThrowsWithReason([array exchangeObjectAtIndex:0 withObjectAtIndex:1], @"invalidated");
RLMAssertThrowsWithReason([array indexOfObject:@1], @"invalidated");
/* RLMAssertThrowsWithReason([array indexOfObjectWhere:@"TRUEPREDICATE"], @"invalidated"); */
/* RLMAssertThrowsWithReason([array indexOfObjectWithPredicate:[NSPredicate predicateWithValue:YES]], @"invalidated"); */
/* RLMAssertThrowsWithReason([array objectsWhere:@"TRUEPREDICATE"], @"invalidated"); */
/* RLMAssertThrowsWithReason([array objectsWithPredicate:[NSPredicate predicateWithValue:YES]], @"invalidated"); */
RLMAssertThrowsWithReason([array sortedResultsUsingKeyPath:@"self" ascending:YES], @"invalidated");
RLMAssertThrowsWithReason([array sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:@"self" ascending:YES]]], @"invalidated");
RLMAssertThrowsWithReason(array[0], @"invalidated");
RLMAssertThrowsWithReason(array[0] = @0, @"invalidated");
RLMAssertThrowsWithReason([array valueForKey:@"self"], @"invalidated");
RLMAssertThrowsWithReason([array setValue:@1 forKey:@"self"], @"invalidated");
RLMAssertThrowsWithReason({for (__unused id obj in array);}, @"invalidated");
[realm beginWriteTransaction];
}
- (void)testMutatingMethodsCheckForWriteTransaction {
RLMArray *array = managed.intObj;
[array addObject:@0];
[realm commitWriteTransaction];
XCTAssertNoThrow([array objectClassName]);
XCTAssertNoThrow([array realm]);
XCTAssertNoThrow([array isInvalidated]);
XCTAssertNoThrow([array count]);
XCTAssertNoThrow([array objectAtIndex:0]);
XCTAssertNoThrow([array firstObject]);
XCTAssertNoThrow([array lastObject]);
XCTAssertNoThrow([array indexOfObject:@1]);
/* XCTAssertNoThrow([array indexOfObjectWhere:@"TRUEPREDICATE"]); */
/* XCTAssertNoThrow([array indexOfObjectWithPredicate:[NSPredicate predicateWithValue:YES]]); */
/* XCTAssertNoThrow([array objectsWhere:@"TRUEPREDICATE"]); */
/* XCTAssertNoThrow([array objectsWithPredicate:[NSPredicate predicateWithValue:YES]]); */
XCTAssertNoThrow([array sortedResultsUsingKeyPath:@"self" ascending:YES]);
XCTAssertNoThrow([array sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:@"self" ascending:YES]]]);
XCTAssertNoThrow(array[0]);
XCTAssertNoThrow([array valueForKey:@"self"]);
XCTAssertNoThrow({for (__unused id obj in array);});
RLMAssertThrowsWithReason([array addObject:@0], @"write transaction");
RLMAssertThrowsWithReason([array addObjects:@[@0]], @"write transaction");
RLMAssertThrowsWithReason([array insertObject:@0 atIndex:0], @"write transaction");
RLMAssertThrowsWithReason([array removeObjectAtIndex:0], @"write transaction");
RLMAssertThrowsWithReason([array removeLastObject], @"write transaction");
RLMAssertThrowsWithReason([array removeAllObjects], @"write transaction");
RLMAssertThrowsWithReason([array replaceObjectAtIndex:0 withObject:@0], @"write transaction");
RLMAssertThrowsWithReason([array moveObjectAtIndex:0 toIndex:1], @"write transaction");
RLMAssertThrowsWithReason([array exchangeObjectAtIndex:0 withObjectAtIndex:1], @"write transaction");
RLMAssertThrowsWithReason(array[0] = @0, @"write transaction");
RLMAssertThrowsWithReason([array setValue:@1 forKey:@"self"], @"write transaction");
}
- (void)testDeleteOwningObject {
RLMArray *array = managed.intObj;
XCTAssertFalse(array.isInvalidated);
[realm deleteObject:managed];
XCTAssertTrue(array.isInvalidated);
}
#pragma clang diagnostic ignored "-Warc-retain-cycles"
- (void)testNotificationSentInitially {
[realm commitWriteTransaction];
id expectation = [self expectationWithDescription:@""];
id token = [managed.intObj addNotificationBlock:^(RLMArray *array, RLMCollectionChange *change, NSError *error) {
XCTAssertNotNil(array);
XCTAssertNil(change);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
[(RLMNotificationToken *)token invalidate];
}
- (void)testNotificationSentAfterCommit {
[realm commitWriteTransaction];
__block bool first = true;
__block id expectation = [self expectationWithDescription:@""];
id token = [managed.intObj addNotificationBlock:^(RLMArray *array, RLMCollectionChange *change, NSError *error) {
XCTAssertNotNil(array);
XCTAssertNil(error);
if (first) {
XCTAssertNil(change);
}
else {
XCTAssertEqualObjects(change.insertions, @[@0]);
}
first = false;
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
expectation = [self expectationWithDescription:@""];
[self dispatchAsyncAndWait:^{
RLMRealm *r = [RLMRealm defaultRealm];
[r transactionWithBlock:^{
RLMArray *array = [(AllPrimitiveArrays *)[AllPrimitiveArrays allObjectsInRealm:r].firstObject intObj];
[array addObject:@0];
}];
}];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
[(RLMNotificationToken *)token invalidate];
}
- (void)testNotificationNotSentForUnrelatedChange {
[realm commitWriteTransaction];
id expectation = [self expectationWithDescription:@""];
id token = [managed.intObj addNotificationBlock:^(__unused RLMArray *array, __unused RLMCollectionChange *change, __unused NSError *error) {
// will throw if it's incorrectly called a second time due to the
// unrelated write transaction
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
// All notification blocks are called as part of a single runloop event, so
// waiting for this one also waits for the above one to get a chance to run
[self waitForNotification:RLMRealmDidChangeNotification realm:realm block:^{
[self dispatchAsyncAndWait:^{
RLMRealm *r = [RLMRealm defaultRealm];
[r transactionWithBlock:^{
[AllPrimitiveArrays createInRealm:r withValue:@[]];
}];
}];
}];
[(RLMNotificationToken *)token invalidate];
}
- (void)testNotificationSentOnlyForActualRefresh {
[realm commitWriteTransaction];
__block id expectation = [self expectationWithDescription:@""];
id token = [managed.intObj addNotificationBlock:^(RLMArray *array, __unused RLMCollectionChange *change, NSError *error) {
XCTAssertNotNil(array);
XCTAssertNil(error);
// will throw if it's called a second time before we create the new
// expectation object immediately before manually refreshing
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
// Turn off autorefresh, so the background commit should not result in a notification
realm.autorefresh = NO;
// All notification blocks are called as part of a single runloop event, so
// waiting for this one also waits for the above one to get a chance to run
[self waitForNotification:RLMRealmRefreshRequiredNotification realm:realm block:^{
[self dispatchAsyncAndWait:^{
RLMRealm *r = [RLMRealm defaultRealm];
[r transactionWithBlock:^{
RLMArray *array = [(AllPrimitiveArrays *)[AllPrimitiveArrays allObjectsInRealm:r].firstObject intObj];
[array addObject:@0];
}];
}];
}];
expectation = [self expectationWithDescription:@""];
[realm refresh];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
[(RLMNotificationToken *)token invalidate];
}
- (void)testDeletingObjectWithNotificationsRegistered {
[managed.intObj addObjects:@[@10, @20]];
[realm commitWriteTransaction];
__block bool first = true;
__block id expectation = [self expectationWithDescription:@""];
id token = [managed.intObj addNotificationBlock:^(RLMArray *array, RLMCollectionChange *change, NSError *error) {
XCTAssertNotNil(array);
XCTAssertNil(error);
if (first) {
XCTAssertNil(change);
first = false;
}
else {
XCTAssertEqualObjects(change.deletions, (@[@0, @1]));
}
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
[realm beginWriteTransaction];
[realm deleteObject:managed];
[realm commitWriteTransaction];
expectation = [self expectationWithDescription:@""];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
[(RLMNotificationToken *)token invalidate];
}
@end