ObjectTests.swift 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2015 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. import XCTest
  19. import RealmSwift
  20. import Foundation
  21. private var dynamicDefaultSeed = 0
  22. private func nextDynamicDefaultSeed() -> Int {
  23. dynamicDefaultSeed += 1
  24. return dynamicDefaultSeed
  25. }
  26. class SwiftDynamicDefaultObject: Object {
  27. @objc dynamic var intCol = nextDynamicDefaultSeed()
  28. @objc dynamic var floatCol = Float(nextDynamicDefaultSeed())
  29. @objc dynamic var doubleCol = Double(nextDynamicDefaultSeed())
  30. @objc dynamic var dateCol = Date(timeIntervalSinceReferenceDate: TimeInterval(nextDynamicDefaultSeed()))
  31. @objc dynamic var stringCol = UUID().uuidString
  32. @objc dynamic var binaryCol = UUID().uuidString.data(using: .utf8)
  33. override static func primaryKey() -> String? {
  34. return "intCol"
  35. }
  36. }
  37. class ObjectTests: TestCase {
  38. // init() Tests are in ObjectCreationTests.swift
  39. // init(value:) tests are in ObjectCreationTests.swift
  40. func testRealm() {
  41. let standalone = SwiftStringObject()
  42. XCTAssertNil(standalone.realm)
  43. let realm = try! Realm()
  44. var persisted: SwiftStringObject!
  45. try! realm.write {
  46. persisted = realm.create(SwiftStringObject.self, value: [:])
  47. XCTAssertNotNil(persisted.realm)
  48. XCTAssertEqual(realm, persisted.realm!)
  49. }
  50. XCTAssertNotNil(persisted.realm)
  51. XCTAssertEqual(realm, persisted.realm!)
  52. dispatchSyncNewThread {
  53. autoreleasepool {
  54. XCTAssertNotEqual(try! Realm(), persisted.realm!)
  55. }
  56. }
  57. }
  58. func testObjectSchema() {
  59. let object = SwiftObject()
  60. let schema = object.objectSchema
  61. XCTAssert(schema as AnyObject is ObjectSchema)
  62. XCTAssert(schema.properties as AnyObject is [Property])
  63. XCTAssertEqual(schema.className, "SwiftObject")
  64. XCTAssertEqual(schema.properties.map { $0.name },
  65. ["boolCol", "intCol", "floatCol", "doubleCol", "stringCol", "binaryCol", "dateCol", "objectCol", "arrayCol"]
  66. )
  67. }
  68. func testObjectSchemaForObjectWithConvenienceInitializer() {
  69. let object = SwiftConvenienceInitializerObject(stringCol: "abc")
  70. let schema = object.objectSchema
  71. XCTAssert(schema as AnyObject is ObjectSchema)
  72. XCTAssert(schema.properties as AnyObject is [Property])
  73. XCTAssertEqual(schema.className, "SwiftConvenienceInitializerObject")
  74. XCTAssertEqual(schema.properties.map { $0.name }, ["stringCol"])
  75. }
  76. func testSharedSchemaUnmanaged() {
  77. let object = SwiftObject()
  78. XCTAssertEqual(type(of: object).sharedSchema(), SwiftObject.sharedSchema())
  79. }
  80. func testSharedSchemaManaged() {
  81. let object = SwiftObject()
  82. XCTAssertEqual(type(of: object).sharedSchema(), SwiftObject.sharedSchema())
  83. }
  84. func testInvalidated() {
  85. let object = SwiftObject()
  86. XCTAssertFalse(object.isInvalidated)
  87. let realm = try! Realm()
  88. try! realm.write {
  89. realm.add(object)
  90. XCTAssertFalse(object.isInvalidated)
  91. }
  92. try! realm.write {
  93. realm.deleteAll()
  94. XCTAssertTrue(object.isInvalidated)
  95. }
  96. XCTAssertTrue(object.isInvalidated)
  97. }
  98. func testDescription() {
  99. let object = SwiftObject()
  100. // swiftlint:disable line_length
  101. assertMatches(object.description, "SwiftObject \\{\n\tboolCol = 0;\n\tintCol = 123;\n\tfloatCol = 1\\.23;\n\tdoubleCol = 12\\.3;\n\tstringCol = a;\n\tbinaryCol = <.*61.*>;\n\tdateCol = 1970-01-01 00:00:01 \\+0000;\n\tobjectCol = SwiftBoolObject \\{\n\t\tboolCol = 0;\n\t\\};\n\tarrayCol = List<SwiftBoolObject> <0x[0-9a-f]+> \\(\n\t\n\t\\);\n\\}")
  102. let recursiveObject = SwiftRecursiveObject()
  103. recursiveObject.objects.append(recursiveObject)
  104. assertMatches(recursiveObject.description, "SwiftRecursiveObject \\{\n\tobjects = List<SwiftRecursiveObject> <0x[0-9a-f]+> \\(\n\t\t\\[0\\] SwiftRecursiveObject \\{\n\t\t\tobjects = List<SwiftRecursiveObject> <0x[0-9a-f]+> \\(\n\t\t\t\t\\[0\\] SwiftRecursiveObject \\{\n\t\t\t\t\tobjects = <Maximum depth exceeded>;\n\t\t\t\t\\}\n\t\t\t\\);\n\t\t\\}\n\t\\);\n\\}")
  105. let renamedObject = LinkToSwiftRenamedProperties1()
  106. renamedObject.linkA = SwiftRenamedProperties1()
  107. assertMatches(renamedObject.description, "LinkToSwiftRenamedProperties1 \\{\n\tlinkA = SwiftRenamedProperties1 \\{\n\t\tpropA = 0;\n\t\tpropB = ;\n\t\\};\n\tlinkB = \\(null\\);\n\tarray1 = List<SwiftRenamedProperties1> <0x[0-9a-f]+> \\(\n\t\n\t\\);\n\\}")
  108. assertMatches(renamedObject.linkA!.linking1.description, "LinkingObjects<LinkToSwiftRenamedProperties1> <0x[0-9a-f]+> \\(\n\n\\)")
  109. let realm = try! Realm()
  110. try! realm.write { realm.add(renamedObject) }
  111. assertMatches(renamedObject.description, "LinkToSwiftRenamedProperties1 \\{\n\tlinkA = SwiftRenamedProperties1 \\{\n\t\tpropA = 0;\n\t\tpropB = ;\n\t\\};\n\tlinkB = \\(null\\);\n\tarray1 = List<SwiftRenamedProperties1> <0x[0-9a-f]+> \\(\n\t\n\t\\);\n\\}")
  112. assertMatches(renamedObject.linkA!.linking1.description, "LinkingObjects<LinkToSwiftRenamedProperties1> <0x[0-9a-f]+> \\(\n\t\\[0\\] LinkToSwiftRenamedProperties1 \\{\n\t\tlinkA = SwiftRenamedProperties1 \\{\n\t\t\tpropA = 0;\n\t\t\tpropB = ;\n\t\t\\};\n\t\tlinkB = \\(null\\);\n\t\tarray1 = List<SwiftRenamedProperties1> <0x[0-9a-f]+> \\(\n\t\t\n\t\t\\);\n\t\\}\n\\)")
  113. // swiftlint:enable line_length
  114. }
  115. func testSchemaHasPrimaryKey() {
  116. XCTAssertNil(Object.primaryKey(), "primary key should default to nil")
  117. XCTAssertNil(SwiftStringObject.primaryKey())
  118. XCTAssertNil(SwiftStringObject().objectSchema.primaryKeyProperty)
  119. XCTAssertEqual(SwiftPrimaryStringObject.primaryKey()!, "stringCol")
  120. XCTAssertEqual(SwiftPrimaryStringObject().objectSchema.primaryKeyProperty!.name, "stringCol")
  121. }
  122. func testCannotUpdatePrimaryKey() {
  123. let realm = self.realmWithTestPath()
  124. let primaryKeyReason = "Primary key can't be changed .*after an object is inserted."
  125. let intObj = SwiftPrimaryIntObject()
  126. intObj.intCol = 1
  127. intObj.intCol = 0; // can change primary key unattached
  128. XCTAssertEqual(0, intObj.intCol)
  129. let optionalIntObj = SwiftPrimaryOptionalIntObject()
  130. optionalIntObj.intCol.value = 1
  131. optionalIntObj.intCol.value = 0; // can change primary key unattached
  132. XCTAssertEqual(0, optionalIntObj.intCol.value)
  133. let stringObj = SwiftPrimaryStringObject()
  134. stringObj.stringCol = "a"
  135. stringObj.stringCol = "b" // can change primary key unattached
  136. XCTAssertEqual("b", stringObj.stringCol)
  137. try! realm.write {
  138. realm.add(intObj)
  139. assertThrows(intObj.intCol = 2, reasonMatching: primaryKeyReason)
  140. assertThrows(intObj["intCol"] = 2, reasonMatching: primaryKeyReason)
  141. assertThrows(intObj.setValue(2, forKey: "intCol"), reasonMatching: primaryKeyReason)
  142. realm.add(optionalIntObj)
  143. assertThrows(optionalIntObj.intCol.value = 2, reasonMatching: "Cannot modify primary key")
  144. assertThrows(optionalIntObj["intCol"] = 2, reasonMatching: primaryKeyReason)
  145. assertThrows(optionalIntObj.setValue(2, forKey: "intCol"), reasonMatching: "Cannot modify primary key")
  146. realm.add(stringObj)
  147. assertThrows(stringObj.stringCol = "c", reasonMatching: primaryKeyReason)
  148. assertThrows(stringObj["stringCol"] = "c", reasonMatching: primaryKeyReason)
  149. assertThrows(stringObj.setValue("c", forKey: "stringCol"), reasonMatching: primaryKeyReason)
  150. }
  151. }
  152. func testIgnoredProperties() {
  153. XCTAssertEqual(Object.ignoredProperties(), [], "ignored properties should default to []")
  154. XCTAssertEqual(SwiftIgnoredPropertiesObject.ignoredProperties().count, 2)
  155. XCTAssertNil(SwiftIgnoredPropertiesObject().objectSchema["runtimeProperty"])
  156. }
  157. func testIndexedProperties() {
  158. XCTAssertEqual(Object.indexedProperties(), [], "indexed properties should default to []")
  159. XCTAssertEqual(SwiftIndexedPropertiesObject.indexedProperties().count, 8)
  160. let objectSchema = SwiftIndexedPropertiesObject().objectSchema
  161. XCTAssertTrue(objectSchema["stringCol"]!.isIndexed)
  162. XCTAssertTrue(objectSchema["intCol"]!.isIndexed)
  163. XCTAssertTrue(objectSchema["int8Col"]!.isIndexed)
  164. XCTAssertTrue(objectSchema["int16Col"]!.isIndexed)
  165. XCTAssertTrue(objectSchema["int32Col"]!.isIndexed)
  166. XCTAssertTrue(objectSchema["int64Col"]!.isIndexed)
  167. XCTAssertTrue(objectSchema["boolCol"]!.isIndexed)
  168. XCTAssertTrue(objectSchema["dateCol"]!.isIndexed)
  169. XCTAssertFalse(objectSchema["floatCol"]!.isIndexed)
  170. XCTAssertFalse(objectSchema["doubleCol"]!.isIndexed)
  171. XCTAssertFalse(objectSchema["dataCol"]!.isIndexed)
  172. }
  173. func testIndexedOptionalProperties() {
  174. XCTAssertEqual(Object.indexedProperties(), [], "indexed properties should default to []")
  175. XCTAssertEqual(SwiftIndexedOptionalPropertiesObject.indexedProperties().count, 8)
  176. XCTAssertTrue(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalStringCol"]!.isIndexed)
  177. XCTAssertTrue(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalDateCol"]!.isIndexed)
  178. XCTAssertTrue(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalBoolCol"]!.isIndexed)
  179. XCTAssertTrue(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalIntCol"]!.isIndexed)
  180. XCTAssertTrue(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalInt8Col"]!.isIndexed)
  181. XCTAssertTrue(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalInt16Col"]!.isIndexed)
  182. XCTAssertTrue(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalInt32Col"]!.isIndexed)
  183. XCTAssertTrue(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalInt64Col"]!.isIndexed)
  184. XCTAssertFalse(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalDataCol"]!.isIndexed)
  185. XCTAssertFalse(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalFloatCol"]!.isIndexed)
  186. XCTAssertFalse(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalDoubleCol"]!.isIndexed)
  187. }
  188. func testDynamicDefaultPropertyValues() {
  189. func assertDifferentPropertyValues(_ obj1: SwiftDynamicDefaultObject, _ obj2: SwiftDynamicDefaultObject) {
  190. XCTAssertNotEqual(obj1.intCol, obj2.intCol)
  191. XCTAssertNotEqual(obj1.floatCol, obj2.floatCol)
  192. XCTAssertNotEqual(obj1.doubleCol, obj2.doubleCol)
  193. XCTAssertNotEqual(obj1.dateCol.timeIntervalSinceReferenceDate, obj2.dateCol.timeIntervalSinceReferenceDate,
  194. accuracy: 0.01)
  195. XCTAssertNotEqual(obj1.stringCol, obj2.stringCol)
  196. XCTAssertNotEqual(obj1.binaryCol, obj2.binaryCol)
  197. }
  198. assertDifferentPropertyValues(SwiftDynamicDefaultObject(), SwiftDynamicDefaultObject())
  199. let realm = try! Realm()
  200. try! realm.write {
  201. assertDifferentPropertyValues(realm.create(SwiftDynamicDefaultObject.self),
  202. realm.create(SwiftDynamicDefaultObject.self))
  203. }
  204. }
  205. func testValueForKey() {
  206. let test: (SwiftObject) -> Void = { object in
  207. XCTAssertEqual(object.value(forKey: "boolCol") as! Bool?, false)
  208. XCTAssertEqual(object.value(forKey: "intCol") as! Int?, 123)
  209. XCTAssertEqual(object.value(forKey: "floatCol") as! Float?, 1.23 as Float)
  210. XCTAssertEqual(object.value(forKey: "doubleCol") as! Double?, 12.3)
  211. XCTAssertEqual(object.value(forKey: "stringCol") as! String?, "a")
  212. let expected = object.value(forKey: "binaryCol") as! Data
  213. let actual = "a".data(using: String.Encoding.utf8)!
  214. XCTAssertTrue(expected == actual)
  215. XCTAssertEqual(object.value(forKey: "dateCol") as! Date?, Date(timeIntervalSince1970: 1))
  216. XCTAssertEqual((object.value(forKey: "objectCol")! as! SwiftBoolObject).boolCol, false)
  217. XCTAssert(object.value(forKey: "arrayCol")! is List<SwiftBoolObject>)
  218. }
  219. test(SwiftObject())
  220. try! Realm().write {
  221. let persistedObject = try! Realm().create(SwiftObject.self, value: [:])
  222. test(persistedObject)
  223. }
  224. }
  225. func testSettingUnmanagedObjectValuesWithSwiftDictionary() {
  226. let json: [String: Any] = ["name": "foo", "array": [["stringCol": "bar"]], "intArray": [["intCol": 50]]]
  227. let object = SwiftArrayPropertyObject()
  228. json.keys.forEach { key in
  229. object.setValue(json[key], forKey: key)
  230. }
  231. XCTAssertEqual(object.name, "foo")
  232. XCTAssertEqual(object.array[0].stringCol, "bar")
  233. XCTAssertEqual(object.intArray[0].intCol, 50)
  234. }
  235. func testSettingUnmanagedObjectValuesWithBadSwiftDictionary() {
  236. let json: [String: Any] = ["name": "foo", "array": [["stringCol": NSObject()]], "intArray": [["intCol": 50]]]
  237. let object = SwiftArrayPropertyObject()
  238. assertThrows({ json.keys.forEach { key in object.setValue(json[key], forKey: key) } }())
  239. }
  240. func setAndTestAllTypes(_ setter: (SwiftObject, Any?, String) -> Void,
  241. getter: (SwiftObject, String) -> (Any?), object: SwiftObject) {
  242. setter(object, true, "boolCol")
  243. XCTAssertEqual(getter(object, "boolCol") as! Bool?, true)
  244. setter(object, 321, "intCol")
  245. XCTAssertEqual(getter(object, "intCol") as! Int?, 321)
  246. setter(object, NSNumber(value: 32.1 as Float), "floatCol")
  247. XCTAssertEqual(getter(object, "floatCol") as! Float?, 32.1 as Float)
  248. setter(object, 3.21, "doubleCol")
  249. XCTAssertEqual(getter(object, "doubleCol") as! Double?, 3.21)
  250. setter(object, "z", "stringCol")
  251. XCTAssertEqual(getter(object, "stringCol") as! String?, "z")
  252. setter(object, "z".data(using: String.Encoding.utf8)! as Data, "binaryCol")
  253. let gotData = getter(object, "binaryCol") as! Data
  254. XCTAssertTrue(gotData == "z".data(using: String.Encoding.utf8)!)
  255. setter(object, Date(timeIntervalSince1970: 333), "dateCol")
  256. XCTAssertEqual(getter(object, "dateCol") as! Date?, Date(timeIntervalSince1970: 333))
  257. let boolObject = SwiftBoolObject(value: [true])
  258. setter(object, boolObject, "objectCol")
  259. assertEqual(getter(object, "objectCol") as? SwiftBoolObject, boolObject)
  260. XCTAssertEqual((getter(object, "objectCol") as! SwiftBoolObject).boolCol, true)
  261. let list = List<SwiftBoolObject>()
  262. list.append(boolObject)
  263. setter(object, list, "arrayCol")
  264. XCTAssertEqual((getter(object, "arrayCol") as! List<SwiftBoolObject>).count, 1)
  265. assertEqual((getter(object, "arrayCol") as! List<SwiftBoolObject>).first!, boolObject)
  266. list.removeAll()
  267. setter(object, list, "arrayCol")
  268. XCTAssertEqual((getter(object, "arrayCol") as! List<SwiftBoolObject>).count, 0)
  269. setter(object, [boolObject], "arrayCol")
  270. XCTAssertEqual((getter(object, "arrayCol") as! List<SwiftBoolObject>).count, 1)
  271. assertEqual((getter(object, "arrayCol") as! List<SwiftBoolObject>).first!, boolObject)
  272. setter(object, nil, "arrayCol")
  273. XCTAssertEqual((getter(object, "arrayCol") as! List<SwiftBoolObject>).count, 0)
  274. setter(object, [boolObject], "arrayCol")
  275. setter(object, NSNull(), "arrayCol")
  276. XCTAssertEqual((getter(object, "arrayCol") as! List<SwiftBoolObject>).count, 0)
  277. }
  278. func dynamicSetAndTestAllTypes(_ setter: (DynamicObject, Any?, String) -> Void,
  279. getter: (DynamicObject, String) -> (Any?), object: DynamicObject,
  280. boolObject: DynamicObject) {
  281. setter(object, true, "boolCol")
  282. XCTAssertEqual((getter(object, "boolCol") as! Bool), true)
  283. setter(object, 321, "intCol")
  284. XCTAssertEqual((getter(object, "intCol") as! Int), 321)
  285. setter(object, NSNumber(value: 32.1 as Float), "floatCol")
  286. XCTAssertEqual((getter(object, "floatCol") as! Float), 32.1 as Float)
  287. setter(object, 3.21, "doubleCol")
  288. XCTAssertEqual((getter(object, "doubleCol") as! Double), 3.21)
  289. setter(object, "z", "stringCol")
  290. XCTAssertEqual((getter(object, "stringCol") as! String), "z")
  291. setter(object, "z".data(using: String.Encoding.utf8)! as Data, "binaryCol")
  292. let gotData = getter(object, "binaryCol") as! Data
  293. XCTAssertTrue(gotData == "z".data(using: String.Encoding.utf8)!)
  294. setter(object, Date(timeIntervalSince1970: 333), "dateCol")
  295. XCTAssertEqual((getter(object, "dateCol") as! Date), Date(timeIntervalSince1970: 333))
  296. setter(object, boolObject, "objectCol")
  297. assertEqual((getter(object, "objectCol") as! DynamicObject), boolObject)
  298. XCTAssertEqual(((getter(object, "objectCol") as! DynamicObject)["boolCol"] as! Bool), true)
  299. setter(object, [boolObject], "arrayCol")
  300. XCTAssertEqual((getter(object, "arrayCol") as! List<DynamicObject>).count, 1)
  301. assertEqual((getter(object, "arrayCol") as! List<DynamicObject>).first!, boolObject)
  302. let list = getter(object, "arrayCol") as! List<DynamicObject>
  303. list.removeAll()
  304. setter(object, list, "arrayCol")
  305. XCTAssertEqual((getter(object, "arrayCol") as! List<DynamicObject>).count, 0)
  306. setter(object, [boolObject], "arrayCol")
  307. XCTAssertEqual((getter(object, "arrayCol") as! List<DynamicObject>).count, 1)
  308. assertEqual((getter(object, "arrayCol") as! List<DynamicObject>).first!, boolObject)
  309. setter(object, nil, "arrayCol")
  310. XCTAssertEqual((getter(object, "arrayCol") as! List<DynamicObject>).count, 0)
  311. }
  312. // Yields a read-write migration `SwiftObject` to the given block
  313. private func withMigrationObject(block: @escaping ((MigrationObject, Migration) -> Void)) {
  314. autoreleasepool {
  315. let realm = self.realmWithTestPath()
  316. try! realm.write {
  317. _ = realm.create(SwiftObject.self)
  318. }
  319. }
  320. autoreleasepool {
  321. var enumerated = false
  322. let configuration = Realm.Configuration(schemaVersion: 1, migrationBlock: { migration, _ in
  323. migration.enumerateObjects(ofType: SwiftObject.className()) { _, newObject in
  324. if let newObject = newObject {
  325. block(newObject, migration)
  326. enumerated = true
  327. }
  328. }
  329. })
  330. self.realmWithTestPath(configuration: configuration)
  331. XCTAssert(enumerated)
  332. }
  333. }
  334. func testSetValueForKey() {
  335. let setter: (Object, Any?, String) -> Void = { object, value, key in
  336. object.setValue(value, forKey: key)
  337. return
  338. }
  339. let getter: (Object, String) -> (Any?) = { object, key in
  340. object.value(forKey: key)
  341. }
  342. withMigrationObject { migrationObject, migration in
  343. let boolObject = migration.create("SwiftBoolObject", value: [true])
  344. self.dynamicSetAndTestAllTypes(setter, getter: getter, object: migrationObject, boolObject: boolObject)
  345. }
  346. setAndTestAllTypes(setter, getter: getter, object: SwiftObject())
  347. try! Realm().write {
  348. let persistedObject = try! Realm().create(SwiftObject.self, value: [:])
  349. self.setAndTestAllTypes(setter, getter: getter, object: persistedObject)
  350. }
  351. }
  352. func testSubscript() {
  353. let setter: (Object, Any?, String) -> Void = { object, value, key in
  354. object[key] = value
  355. return
  356. }
  357. let getter: (Object, String) -> (Any?) = { object, key in
  358. object[key]
  359. }
  360. withMigrationObject { migrationObject, migration in
  361. let boolObject = migration.create("SwiftBoolObject", value: [true])
  362. self.dynamicSetAndTestAllTypes(setter, getter: getter, object: migrationObject, boolObject: boolObject)
  363. }
  364. setAndTestAllTypes(setter, getter: getter, object: SwiftObject())
  365. try! Realm().write {
  366. let persistedObject = try! Realm().create(SwiftObject.self, value: [:])
  367. self.setAndTestAllTypes(setter, getter: getter, object: persistedObject)
  368. }
  369. }
  370. func testDynamicList() {
  371. let realm = try! Realm()
  372. let arrayObject = SwiftArrayPropertyObject()
  373. let str1 = SwiftStringObject()
  374. let str2 = SwiftStringObject()
  375. arrayObject.array.append(objectsIn: [str1, str2])
  376. try! realm.write {
  377. realm.add(arrayObject)
  378. }
  379. let dynamicArray = arrayObject.dynamicList("array")
  380. XCTAssertEqual(dynamicArray.count, 2)
  381. assertEqual(dynamicArray[0], str1)
  382. assertEqual(dynamicArray[1], str2)
  383. XCTAssertEqual(arrayObject.dynamicList("intArray").count, 0)
  384. assertThrows(arrayObject.dynamicList("noSuchList"))
  385. }
  386. func testObjectiveCTypeProperties() {
  387. let realm = try! Realm()
  388. var object: SwiftObjectiveCTypesObject!
  389. let now = NSDate()
  390. let data = "fizzbuzz".data(using: .utf8)! as Data as NSData
  391. try! realm.write {
  392. object = SwiftObjectiveCTypesObject()
  393. realm.add(object)
  394. object.stringCol = "Hello world!"
  395. object.dateCol = now
  396. object.dataCol = data
  397. object.numCol = 42
  398. }
  399. XCTAssertEqual("Hello world!", object.stringCol)
  400. XCTAssertEqual(now, object.dateCol)
  401. XCTAssertEqual(data, object.dataCol)
  402. XCTAssertEqual(42, object.numCol)
  403. }
  404. func testDeleteObservedObject() {
  405. let realm = try! Realm()
  406. realm.beginWrite()
  407. let object = realm.create(SwiftIntObject.self, value: [0])
  408. try! realm.commitWrite()
  409. let exp = expectation(description: "")
  410. let token = object.observe { change in
  411. if case .deleted = change {
  412. } else {
  413. XCTFail("expected .deleted, got \(change)")
  414. }
  415. exp.fulfill()
  416. }
  417. realm.beginWrite()
  418. realm.delete(object)
  419. try! realm.commitWrite()
  420. waitForExpectations(timeout: 2)
  421. token.invalidate()
  422. }
  423. func expectChange<T: Equatable, U: Equatable>(_ name: String, _ old: T?, _ new: U?) -> ((ObjectChange) -> Void) {
  424. let exp = expectation(description: "")
  425. return { change in
  426. if case .change(let properties) = change {
  427. XCTAssertEqual(properties.count, 1)
  428. if let prop = properties.first {
  429. XCTAssertEqual(prop.name, name)
  430. XCTAssertEqual(prop.oldValue as? T, old)
  431. XCTAssertEqual(prop.newValue as? U, new)
  432. }
  433. } else {
  434. XCTFail("expected .change, got \(change)")
  435. }
  436. exp.fulfill()
  437. }
  438. }
  439. func testModifyObservedObjectLocally() {
  440. let realm = try! Realm()
  441. realm.beginWrite()
  442. let object = realm.create(SwiftIntObject.self, value: [1])
  443. try! realm.commitWrite()
  444. let token = object.observe(expectChange("intCol", Int?.none, 2))
  445. try! realm.write {
  446. object.intCol = 2
  447. }
  448. waitForExpectations(timeout: 2)
  449. token.invalidate()
  450. }
  451. func testModifyObservedObjectRemotely() {
  452. let realm = try! Realm()
  453. realm.beginWrite()
  454. let object = realm.create(SwiftIntObject.self, value: [1])
  455. try! realm.commitWrite()
  456. let token = object.observe(expectChange("intCol", 1, 2))
  457. dispatchSyncNewThread {
  458. let realm = try! Realm()
  459. try! realm.write {
  460. realm.objects(SwiftIntObject.self).first!.intCol = 2
  461. }
  462. }
  463. realm.refresh()
  464. waitForExpectations(timeout: 0)
  465. token.invalidate()
  466. }
  467. func testListPropertyNotifications() {
  468. let realm = try! Realm()
  469. realm.beginWrite()
  470. let object = realm.create(SwiftRecursiveObject.self, value: [[]])
  471. try! realm.commitWrite()
  472. let token = object.observe(expectChange("objects", Int?.none, Int?.none))
  473. dispatchSyncNewThread {
  474. let realm = try! Realm()
  475. try! realm.write {
  476. let obj = realm.objects(SwiftRecursiveObject.self).first!
  477. obj.objects.append(obj)
  478. }
  479. }
  480. waitForExpectations(timeout: 2)
  481. token.invalidate()
  482. }
  483. func testOptionalPropertyNotifications() {
  484. let realm = try! Realm()
  485. let object = SwiftOptionalDefaultValuesObject()
  486. try! realm.write {
  487. realm.add(object)
  488. }
  489. var token = object.observe(expectChange("optIntCol", 1, 2))
  490. dispatchSyncNewThread {
  491. let realm = try! Realm()
  492. try! realm.write {
  493. realm.objects(SwiftOptionalDefaultValuesObject.self).first!.optIntCol.value = 2
  494. }
  495. }
  496. realm.refresh()
  497. waitForExpectations(timeout: 0)
  498. token.invalidate()
  499. token = object.observe(expectChange("optIntCol", 2, Int?.none))
  500. dispatchSyncNewThread {
  501. let realm = try! Realm()
  502. try! realm.write {
  503. realm.objects(SwiftOptionalDefaultValuesObject.self).first!.optIntCol.value = nil
  504. }
  505. }
  506. realm.refresh()
  507. waitForExpectations(timeout: 0)
  508. token.invalidate()
  509. token = object.observe(expectChange("optIntCol", Int?.none, 3))
  510. dispatchSyncNewThread {
  511. let realm = try! Realm()
  512. try! realm.write {
  513. realm.objects(SwiftOptionalDefaultValuesObject.self).first!.optIntCol.value = 3
  514. }
  515. }
  516. realm.refresh()
  517. waitForExpectations(timeout: 0)
  518. token.invalidate()
  519. }
  520. func testEqualityForObjectTypeWithPrimaryKey() {
  521. let realm = try! Realm()
  522. let pk = "123456"
  523. let testObject = SwiftPrimaryStringObject()
  524. testObject.stringCol = pk
  525. testObject.intCol = 12345
  526. let unmanaged = SwiftPrimaryStringObject()
  527. unmanaged.stringCol = pk
  528. unmanaged.intCol = 12345
  529. let otherObject = SwiftPrimaryStringObject()
  530. otherObject.stringCol = "not" + pk
  531. otherObject.intCol = 12345
  532. try! realm.write {
  533. realm.add([testObject, otherObject])
  534. }
  535. // Should not match an object that's not equal.
  536. XCTAssertNotEqual(testObject, otherObject)
  537. // Should not match an object whose fields are equal if it's not the same row in the database.
  538. XCTAssertNotEqual(testObject, unmanaged)
  539. // Should match an object that represents the same row.
  540. let retrievedObject = realm.object(ofType: SwiftPrimaryStringObject.self, forPrimaryKey: pk)!
  541. XCTAssertEqual(testObject, retrievedObject)
  542. XCTAssertEqual(testObject.hash, retrievedObject.hash)
  543. XCTAssertTrue(testObject.isSameObject(as: retrievedObject))
  544. }
  545. func testEqualityForObjectTypeWithoutPrimaryKey() {
  546. let realm = try! Realm()
  547. let pk = "123456"
  548. XCTAssertNil(SwiftStringObject.primaryKey())
  549. let testObject = SwiftStringObject()
  550. testObject.stringCol = pk
  551. let alias = testObject
  552. try! realm.write {
  553. realm.add(testObject)
  554. }
  555. XCTAssertEqual(testObject, alias)
  556. // Should not match an object even if it represents the same row.
  557. let retrievedObject = realm.objects(SwiftStringObject.self).first!
  558. XCTAssertNotEqual(testObject, retrievedObject)
  559. // Should be able to use `isSameObject(as:)` to check if same row in the database.
  560. XCTAssertTrue(testObject.isSameObject(as: retrievedObject))
  561. }
  562. func testRetrievingObjectWithRuntimeType() {
  563. let realm = try! Realm()
  564. let unmanagedStringObject = SwiftPrimaryStringObject()
  565. unmanagedStringObject.stringCol = UUID().uuidString
  566. let managedStringObject = SwiftPrimaryStringObject()
  567. managedStringObject.stringCol = UUID().uuidString
  568. // Add the object.
  569. try! realm.write {
  570. realm.add(managedStringObject)
  571. }
  572. // Shouldn't throw when using type(of:).
  573. XCTAssertNotNil(realm.object(ofType: type(of: unmanagedStringObject),
  574. forPrimaryKey: managedStringObject.stringCol))
  575. // Shouldn't throw when using type(of:).
  576. XCTAssertNotNil(realm.object(ofType: type(of: managedStringObject),
  577. forPrimaryKey: managedStringObject.stringCol))
  578. }
  579. func testRetrievingObjectsWithRuntimeType() {
  580. let realm = try! Realm()
  581. let unmanagedStringObject = SwiftStringObject()
  582. unmanagedStringObject.stringCol = "foo"
  583. let managedStringObject = SwiftStringObject()
  584. managedStringObject.stringCol = "bar"
  585. // Add the object.
  586. try! realm.write {
  587. realm.add(managedStringObject)
  588. }
  589. // Shouldn't throw when using type(of:).
  590. XCTAssertEqual(realm.objects(type(of: unmanagedStringObject)).count, 1)
  591. // Shouldn't throw when using type(of:).
  592. XCTAssertEqual(realm.objects(type(of: managedStringObject)).count, 1)
  593. }
  594. }