//////////////////////////////////////////////////////////////////////////// // // Copyright 2015 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 XCTest import RealmSwift import Realm.Private class ObjectWithPrivateOptionals: Object { private var nilInt: Int? private var nilFloat: Float? private var nilString: String? private var int: Int? = 123 private var float: Float? = 1.23 private var string: String? = "123" @objc dynamic var value = 5 } class ObjectCreationTests: TestCase { // MARK: Init tests func testInitWithDefaults() { // test all properties are defaults let object = SwiftObject() XCTAssertNil(object.realm) // test defaults values verifySwiftObjectWithDictionaryLiteral(object, dictionary: SwiftObject.defaultValues(), boolObjectValue: false, boolObjectListValues: []) // test realm properties are nil for standalone XCTAssertNil(object.realm) XCTAssertNil(object.objectCol!.realm) XCTAssertNil(object.arrayCol.realm) } func testInitWithOptionalWithoutDefaults() { let object = SwiftOptionalObject() for prop in object.objectSchema.properties { let value = object[prop.name] if let value = value as? RLMOptionalBase { XCTAssertNil(RLMGetOptional(value)) } else { XCTAssertNil(value) } } } func testInitWithOptionalDefaults() { let object = SwiftOptionalDefaultValuesObject() verifySwiftOptionalObjectWithDictionaryLiteral(object, dictionary: SwiftOptionalDefaultValuesObject.defaultValues(), boolObjectValue: true) } func testInitWithDictionary() { // dictionary with all values specified let baselineValues: [String: Any] = ["boolCol": true, "intCol": 1, "floatCol": 1.1 as Float, "doubleCol": 11.1, "stringCol": "b", "binaryCol": "b".data(using: String.Encoding.utf8)!, "dateCol": Date(timeIntervalSince1970: 2), "objectCol": SwiftBoolObject(value: [true]), "arrayCol": [SwiftBoolObject(value: [true]), SwiftBoolObject()] ] // test with valid dictionary literals let props = try! Realm().schema["SwiftObject"]!.properties for propNum in 0..() -> T { return T() } let obj1: SwiftBoolObject = createObject() let obj2 = SwiftBoolObject() XCTAssertEqual(obj1.boolCol, obj2.boolCol, "object created via generic initializer should equal object created by calling initializer directly") } func testInitWithObjcName() { // Test that init doesn't crash going into non-swift init logic for renamed Swift classes. _ = SwiftObjcRenamedObject() _ = SwiftObjcArbitrarilyRenamedObject() } // MARK: Creation tests func testCreateWithDefaults() { let realm = try! Realm() assertThrows(realm.create(SwiftObject.self), "Must be in write transaction") var object: SwiftObject! let objects = realm.objects(SwiftObject.self) XCTAssertEqual(0, objects.count) try! realm.write { // test create with all defaults object = realm.create(SwiftObject.self) return } verifySwiftObjectWithDictionaryLiteral(object, dictionary: SwiftObject.defaultValues(), boolObjectValue: false, boolObjectListValues: []) // test realm properties are populated correctly XCTAssertEqual(object.realm!, realm) XCTAssertEqual(object.objectCol!.realm!, realm) XCTAssertEqual(object.arrayCol.realm!, realm) } func testCreateWithOptionalWithoutDefaults() { let realm = try! Realm() try! realm.write { let object = realm.create(SwiftOptionalObject.self) for prop in object.objectSchema.properties { XCTAssertNil(object[prop.name]) } } } func testCreateWithOptionalDefaults() { let realm = try! Realm() try! realm.write { let object = realm.create(SwiftOptionalDefaultValuesObject.self) self.verifySwiftOptionalObjectWithDictionaryLiteral(object, dictionary: SwiftOptionalDefaultValuesObject.defaultValues(), boolObjectValue: true) } } func testCreateWithOptionalIgnoredProperties() { let realm = try! Realm() try! realm.write { let object = realm.create(SwiftOptionalIgnoredPropertiesObject.self) let properties = object.objectSchema.properties XCTAssertEqual(properties.count, 1) XCTAssertEqual(properties[0].name, "id") } } func testCreateWithDictionary() { // dictionary with all values specified let baselineValues: [String: Any] = [ "boolCol": true, "intCol": 1, "floatCol": 1.1 as Float, "doubleCol": 11.1, "stringCol": "b", "binaryCol": "b".data(using: String.Encoding.utf8)!, "dateCol": Date(timeIntervalSince1970: 2), "objectCol": SwiftBoolObject(value: [true]), "arrayCol": [SwiftBoolObject(value: [true]), SwiftBoolObject()] ] // test with valid dictionary literals let props = try! Realm().schema["SwiftObject"]!.properties for propNum in 0.. [String: Any] { var valueDict = SwiftObject.defaultValues() for (key, value) in replace { valueDict[key] = value } return valueDict } // return an array of valid values that can be used to initialize each type // swiftlint:disable:next cyclomatic_complexity private func validValuesForSwiftObjectType(_ type: PropertyType, _ array: Bool) -> [Any] { try! Realm().beginWrite() let persistedObject = try! Realm().create(SwiftBoolObject.self, value: [true]) try! Realm().commitWrite() if array { return [ [[true], [false]], [["boolCol": true], ["boolCol": false]], [SwiftBoolObject(value: [true]), SwiftBoolObject(value: [false])], [persistedObject, [false]] ] } switch type { case .bool: return [true, NSNumber(value: 0 as Int), NSNumber(value: 1 as Int)] case .int: return [NSNumber(value: 1 as Int)] case .float: return [NSNumber(value: 1 as Int), NSNumber(value: 1.1 as Float), NSNumber(value: 11.1 as Double)] case .double: return [NSNumber(value: 1 as Int), NSNumber(value: 1.1 as Float), NSNumber(value: 11.1 as Double)] case .string: return ["b"] case .data: return ["b".data(using: String.Encoding.utf8, allowLossyConversion: false)!] case .date: return [Date(timeIntervalSince1970: 2)] case .object: return [[true], ["boolCol": true], SwiftBoolObject(value: [true]), persistedObject] case .any: XCTFail("not supported") case .linkingObjects: XCTFail("not supported") } return [] } // swiftlint:disable:next cyclomatic_complexity private func invalidValuesForSwiftObjectType(_ type: PropertyType, _ array: Bool) -> [Any] { try! Realm().beginWrite() let persistedObject = try! Realm().create(SwiftIntObject.self) try! Realm().commitWrite() if array { return ["invalid", [["a"]], [["boolCol": "a"]], [[SwiftIntObject()]], [[persistedObject]]] } switch type { case .bool: return ["invalid", NSNumber(value: 2 as Int), NSNumber(value: 1.1 as Float), NSNumber(value: 11.1 as Double)] case .int: return ["invalid", NSNumber(value: 1.1 as Float), NSNumber(value: 11.1 as Double)] case .float: return ["invalid", true, false] case .double: return ["invalid", true, false] case .string: return [0x197A71D, true, false] case .data: return ["invalid"] case .date: return ["invalid"] case .object: return ["invalid", ["a"], ["boolCol": "a"], SwiftIntObject()] case .any: XCTFail("not supported") case .linkingObjects: XCTFail("not supported") } return [] } }