123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- ////////////////////////////////////////////////////////////////////////////
- //
- // 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];
- [DynamicTestObject createInRealm:realm withValue:@[@"column1", @1]];
- [DynamicTestObject 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[@"DynamicTestObject"];
- XCTAssertNotNil(dynSchema, @"Should be able to get object schema dynamically");
- XCTAssertEqual(dynSchema.properties.count, (NSUInteger)2, @"DynamicTestObject 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:@"DynamicTestObject"];
- XCTAssertEqual(results.count, (NSUInteger)2, @"Array should have 2 elements");
- XCTAssertNotEqual(results.objectClassName, DynamicTestObject.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];
- [DynamicTestObject createInRealm:realm withValue:@[@"column1", @1]];
- [DynamicTestObject createInRealm:realm withValue:@[@"column2", @2]];
- [realm commitWriteTransaction];
- }
- // verify properties
- RLMRealm *dyrealm = [self realmWithTestPathAndSchema:nil];
- RLMResults *results = [dyrealm allObjects:@"DynamicTestObject"];
- 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
|