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.

364 lines
15 KiB

////////////////////////////////////////////////////////////////////////////
//
// Copyright 2014 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"
#import "RLMRealm_Dynamic.h"
#import "RLMRealm_Private.h"
#import "RLMProperty_Private.h"
#import "RLMObjectSchema_Private.h"
#import "RLMSchema_Private.h"
@interface DynamicTests : RLMTestCase
@end
@implementation DynamicTests
#pragma mark - Tests
- (void)testDynamicRealmExists {
@autoreleasepool {
// open realm in autoreleasepool to create tables and then dispose
RLMRealm *realm = [RLMRealm realmWithURL:RLMTestRealmURL()];
[realm beginWriteTransaction];
[DynamicObject createInRealm:realm withValue:@[@"column1", @1]];
[DynamicObject createInRealm:realm withValue:@[@"column2", @2]];
[realm commitWriteTransaction];
}
RLMRealm *dyrealm = [self realmWithTestPathAndSchema:nil];
XCTAssertNotNil(dyrealm, @"realm should not be nil");
// verify schema
RLMObjectSchema *dynSchema = dyrealm.schema[@"DynamicObject"];
XCTAssertNotNil(dynSchema, @"Should be able to get object schema dynamically");
XCTAssertEqual(dynSchema.properties.count, (NSUInteger)2, @"DynamicObject should have 2 properties");
XCTAssertEqualObjects([dynSchema.properties[0] name], @"stringCol", @"Invalid property name");
XCTAssertEqual([(RLMProperty *)dynSchema.properties[1] type], RLMPropertyTypeInt, @"Invalid type");
// verify object type
RLMResults *results = [dyrealm allObjects:@"DynamicObject"];
XCTAssertEqual(results.count, (NSUInteger)2, @"Array should have 2 elements");
XCTAssertNotEqual(results.objectClassName, DynamicObject.className,
@"Array class should by a dynamic object class");
}
- (void)testDynamicObjectRetrieval {
@autoreleasepool {
// open realm in autoreleasepool to create tables and then dispose
RLMRealm *realm = [self realmWithTestPath];
[realm beginWriteTransaction];
[PrimaryStringObject createInRealm:realm withValue:@[@"key", @1]];
[realm commitWriteTransaction];
}
RLMRealm *testRealm = [self realmWithTestPath];
RLMObject *object = [testRealm objectWithClassName:@"PrimaryStringObject" forPrimaryKey:@"key"];
XCTAssertNotNil(object, @"Should be able to retrieve object by primary key dynamically");
XCTAssert([[object valueForKey:@"stringCol"] isEqualToString:@"key"],@"stringCol should equal 'key'");
XCTAssert([[[object class] className] isEqualToString:@"PrimaryStringObject"],@"Object class name should equal 'PrimaryStringObject'");
XCTAssert([object isKindOfClass:[PrimaryStringObject class]], @"Object should be of class 'PrimaryStringObject'");
}
- (void)testDynamicSchemaMatchesRegularSchema {
RLMSchema *expectedSchema = nil;
@autoreleasepool {
expectedSchema = self.realmWithTestPath.schema;
}
XCTAssertNotNil(expectedSchema);
RLMRealmConfiguration *config = [RLMRealmConfiguration new];
config.fileURL = RLMTestRealmURL();
config.dynamic = YES;
NSError *error = nil;
RLMSchema *dynamicSchema = [[RLMRealm realmWithConfiguration:config error:&error] schema];
XCTAssertNil(error);
for (RLMObjectSchema *expectedObjectSchema in expectedSchema.objectSchema) {
Class cls = expectedObjectSchema.objectClass;
if ([cls _realmObjectName] || [cls _realmColumnNames]) {
// Class overrides names, so the dynamic schema for it shoudn't match
continue;
}
if (expectedObjectSchema.primaryKeyProperty.index != 0) {
// The dynamic schema will always put the primary key first, so it
// won't match if the static schema doesn't have it there
continue;
}
RLMObjectSchema *dynamicObjectSchema = dynamicSchema[expectedObjectSchema.className];
XCTAssertEqual(dynamicObjectSchema.properties.count, expectedObjectSchema.properties.count);
for (NSUInteger propertyIndex = 0; propertyIndex < expectedObjectSchema.properties.count; propertyIndex++) {
RLMProperty *dynamicProperty = dynamicObjectSchema.properties[propertyIndex];
RLMProperty *expectedProperty = expectedObjectSchema.properties[propertyIndex];
XCTAssertEqualObjects(dynamicProperty, expectedProperty);
}
}
}
- (void)testDynamicSchema {
RLMSchema *schema = [[RLMSchema alloc] init];
RLMProperty *prop = [[RLMProperty alloc] initWithName:@"a"
type:RLMPropertyTypeInt
objectClassName:nil
linkOriginPropertyName:nil
indexed:NO
optional:NO];
RLMObjectSchema *objectSchema = [[RLMObjectSchema alloc] initWithClassName:@"TrulyDynamicObject"
objectClass:RLMObject.class
properties:@[prop]];
schema.objectSchema = @[objectSchema];
RLMRealm *dyrealm = [self realmWithTestPathAndSchema:schema];
XCTAssertNotNil(dyrealm, @"dynamic realm shouldn't be nil");
}
- (void)testDynamicProperties {
@autoreleasepool {
// open realm in autoreleasepool to create tables and then dispose
RLMRealm *realm = [RLMRealm realmWithURL:RLMTestRealmURL()];
[realm beginWriteTransaction];
[DynamicObject createInRealm:realm withValue:@[@"column1", @1]];
[DynamicObject createInRealm:realm withValue:@[@"column2", @2]];
[realm commitWriteTransaction];
}
// verify properties
RLMRealm *dyrealm = [self realmWithTestPathAndSchema:nil];
RLMResults *results = [dyrealm allObjects:@"DynamicObject"];
RLMObject *o1 = results[0], *o2 = results[1];
XCTAssertEqualObjects(o1[@"intCol"], @1);
XCTAssertEqualObjects(o2[@"stringCol"], @"column2");
RLMAssertThrowsWithReason(o1[@"invalid"], @"Invalid property name");
RLMAssertThrowsWithReason(o1[@"invalid"] = nil, @"Invalid property name");
}
- (void)testDynamicTypes {
NSDate *now = [NSDate dateWithTimeIntervalSince1970:100000];
id obj1 = @[@YES, @1, @1.1f, @1.11, @"string", [NSData dataWithBytes:"a" length:1],
now, @YES, @11, NSNull.null];
StringObject *obj = [[StringObject alloc] init];
obj.stringCol = @"string";
id obj2 = @[@NO, @2, @2.2f, @2.22, @"string2", [NSData dataWithBytes:"b" length:1],
now, @NO, @22, obj];
@autoreleasepool {
// open realm in autoreleasepool to create tables and then dispose
RLMRealm *realm = [RLMRealm realmWithURL:RLMTestRealmURL()];
[realm beginWriteTransaction];
[AllTypesObject createInRealm:realm withValue:obj1];
[AllTypesObject createInRealm:realm withValue:obj2];
[realm commitWriteTransaction];
}
// verify properties
RLMRealm *dyrealm = [self realmWithTestPathAndSchema:nil];
RLMResults<RLMObject *> *results = [dyrealm allObjects:AllTypesObject.className];
XCTAssertEqual(results.count, (NSUInteger)2, @"Should have 2 objects");
RLMObjectSchema *schema = dyrealm.schema[AllTypesObject.className];
for (int i = 0; i < 9; i++) {
NSString *propName = [schema.properties[i] name];
XCTAssertEqualObjects(obj1[i], results[0][propName]);
XCTAssertEqualObjects(obj2[i], results[1][propName]);
}
// check sub object type
XCTAssertEqualObjects([schema.properties[9] objectClassName], @"StringObject",
@"Sub-object type in schema should be 'StringObject'");
// check object equality
XCTAssertNil(results[0][@"objectCol"], @"object should be nil");
XCTAssertEqualObjects(results[1][@"objectCol"][@"stringCol"], @"string",
@"Child object should have string value 'string'");
[dyrealm beginWriteTransaction];
RLMObject *o = results[0];
for (int i = 0; i < 9; i++) {
RLMProperty *prop = schema.properties[i];
id value = prop.type == RLMPropertyTypeString ? @1 : @"";
RLMAssertThrowsWithReason(o[prop.name] = value,
@"Invalid value '");
RLMAssertThrowsWithReason(o[prop.name] = NSNull.null,
@"Invalid value '<null>' of type 'NSNull' for");
RLMAssertThrowsWithReason(o[prop.name] = nil,
@"Invalid value '(null)' of type '(null)' for");
}
RLMProperty *prop = schema.properties[9];
RLMAssertThrowsWithReason(o[prop.name] = @"str",
@"Invalid value 'str' of type '__NSCFConstantString' for 'StringObject?' property 'AllTypesObject.objectCol'.");
XCTAssertNoThrow(o[prop.name] = nil);
XCTAssertNoThrow(o[prop.name] = NSNull.null);
id otherObjectType = [dyrealm createObject:IntObject.className withValue:@[@1]];
RLMAssertThrowsWithReason(o[prop.name] = otherObjectType,
@"Invalid value 'IntObject");
[dyrealm cancelWriteTransaction];
}
- (void)testDynamicAdd {
@autoreleasepool {
// open realm in autoreleasepool to create tables and then dispose
[RLMRealm realmWithURL:RLMTestRealmURL()];
}
RLMRealm *dyrealm = [self realmWithTestPathAndSchema:nil];
[dyrealm beginWriteTransaction];
RLMObject *stringObject = [dyrealm createObject:StringObject.className withValue:@[@"string"]];
[dyrealm createObject:AllTypesObject.className withValue:@[@NO, @2, @2.2f, @2.22, @"string2",
[NSData dataWithBytes:"b" length:1], NSDate.date, @NO, @22, stringObject]];
[dyrealm commitWriteTransaction];
XCTAssertEqual(1U, [dyrealm allObjects:StringObject.className].count);
XCTAssertEqual(1U, [dyrealm allObjects:AllTypesObject.className].count);
}
- (void)testDynamicArray {
@autoreleasepool {
// open realm in autoreleasepool to create tables and then dispose
[RLMRealm realmWithURL:RLMTestRealmURL()];
}
RLMRealm *dyrealm = [self realmWithTestPathAndSchema:nil];
[dyrealm beginWriteTransaction];
RLMObject *stringObject = [dyrealm createObject:StringObject.className withValue:@[@"string"]];
RLMObject *stringObject1 = [dyrealm createObject:StringObject.className withValue:@[@"string1"]];
[dyrealm createObject:ArrayPropertyObject.className withValue:@[@"name", @[stringObject, stringObject1], @[]]];
RLMResults<RLMObject *> *results = [dyrealm allObjects:ArrayPropertyObject.className];
XCTAssertEqual(1U, results.count);
RLMObject *arrayObj = results.firstObject;
RLMArray<RLMObject *> *array = arrayObj[@"array"];
XCTAssertEqual(2U, array.count);
XCTAssertEqualObjects(array[0][@"stringCol"], stringObject[@"stringCol"]);
[array removeObjectAtIndex:0];
[array addObject:stringObject];
XCTAssertEqual(2U, array.count);
XCTAssertEqualObjects(array[0][@"stringCol"], stringObject1[@"stringCol"]);
XCTAssertEqualObjects(array[1][@"stringCol"], stringObject[@"stringCol"]);
arrayObj[@"array"] = NSNull.null;
XCTAssertEqual(0U, array.count);
[array addObject:stringObject];
XCTAssertEqual(1U, array.count);
arrayObj[@"array"] = nil;
XCTAssertEqual(0U, array.count);
arrayObj[@"array"] = @[stringObject, stringObject1];
XCTAssertEqualObjects(array[0][@"stringCol"], stringObject[@"stringCol"]);
XCTAssertEqualObjects(array[1][@"stringCol"], stringObject1[@"stringCol"]);
[dyrealm commitWriteTransaction];
}
- (void)testOptionalProperties {
@autoreleasepool {
// open realm in autoreleasepool to create tables and then dispose
[RLMRealm realmWithURL:RLMTestRealmURL()];
}
RLMRealm *dyrealm = [self realmWithTestPathAndSchema:nil];
[dyrealm beginWriteTransaction];
RLMObject *object = [dyrealm createObject:AllOptionalTypes.className withValue:@[]];
XCTAssertNil(object[@"intObj"]);
XCTAssertNil(object[@"floatObj"]);
XCTAssertNil(object[@"doubleObj"]);
XCTAssertNil(object[@"boolObj"]);
XCTAssertNil(object[@"string"]);
XCTAssertNil(object[@"data"]);
XCTAssertNil(object[@"date"]);
NSDate *date = [NSDate date];
NSData *data = [NSData data];
object[@"intObj"] = @1;
object[@"floatObj"] = @2.2f;
object[@"doubleObj"] = @3.3;
object[@"boolObj"] = @YES;
object[@"string"] = @"str";
object[@"date"] = date;
object[@"data"] = data;
XCTAssertEqualObjects(object[@"intObj"], @1);
XCTAssertEqualObjects(object[@"floatObj"], @2.2f);
XCTAssertEqualObjects(object[@"doubleObj"], @3.3);
XCTAssertEqualObjects(object[@"boolObj"], @YES);
XCTAssertEqualObjects(object[@"string"], @"str");
XCTAssertEqualObjects(object[@"date"], date);
XCTAssertEqualObjects(object[@"data"], data);
object[@"intObj"] = NSNull.null;
object[@"floatObj"] = NSNull.null;
object[@"doubleObj"] = NSNull.null;
object[@"boolObj"] = NSNull.null;
object[@"string"] = NSNull.null;
object[@"date"] = NSNull.null;
object[@"data"] = NSNull.null;
XCTAssertNil(object[@"intObj"]);
XCTAssertNil(object[@"floatObj"]);
XCTAssertNil(object[@"doubleObj"]);
XCTAssertNil(object[@"boolObj"]);
XCTAssertNil(object[@"string"]);
XCTAssertNil(object[@"data"]);
XCTAssertNil(object[@"date"]);
object[@"intObj"] = nil;
object[@"floatObj"] = nil;
object[@"doubleObj"] = nil;
object[@"boolObj"] = nil;
object[@"string"] = nil;
object[@"date"] = nil;
object[@"data"] = nil;
XCTAssertNil(object[@"intObj"]);
XCTAssertNil(object[@"floatObj"]);
XCTAssertNil(object[@"doubleObj"]);
XCTAssertNil(object[@"boolObj"]);
XCTAssertNil(object[@"string"]);
XCTAssertNil(object[@"data"]);
XCTAssertNil(object[@"date"]);
[dyrealm commitWriteTransaction];
}
- (void)testLinkingObjects {
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
RLMObject *person = [realm createObject:PersonObject.className
withValue:@[@"parent", @10, @[@[@"child", @5, @[]]]]];
XCTAssertEqual([person[@"parents"] count], 0U);
RLMObject *child = [person[@"children"] firstObject];
XCTAssertEqual([child[@"parents"] count], 1U);
XCTAssertTrue([person isEqualToObject:[child[@"parents"] firstObject]]);
RLMAssertThrowsWithReason(person[@"parents"] = @[],
@"Cannot modify read-only property 'PersonObject.parents'");
[realm commitWriteTransaction];
}
@end