ObjectCreationTests.swift 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  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 Realm.Private
  21. class ObjectWithPrivateOptionals: Object {
  22. private var nilInt: Int?
  23. private var nilFloat: Float?
  24. private var nilString: String?
  25. private var int: Int? = 123
  26. private var float: Float? = 1.23
  27. private var string: String? = "123"
  28. @objc dynamic var value = 5
  29. }
  30. class ObjectCreationTests: TestCase {
  31. // MARK: Init tests
  32. func testInitWithDefaults() {
  33. // test all properties are defaults
  34. let object = SwiftObject()
  35. XCTAssertNil(object.realm)
  36. // test defaults values
  37. verifySwiftObjectWithDictionaryLiteral(object, dictionary: SwiftObject.defaultValues(), boolObjectValue: false,
  38. boolObjectListValues: [])
  39. // test realm properties are nil for standalone
  40. XCTAssertNil(object.realm)
  41. XCTAssertNil(object.objectCol!.realm)
  42. XCTAssertNil(object.arrayCol.realm)
  43. }
  44. func testInitWithOptionalWithoutDefaults() {
  45. let object = SwiftOptionalObject()
  46. for prop in object.objectSchema.properties {
  47. let value = object[prop.name]
  48. if let value = value as? RLMOptionalBase {
  49. XCTAssertNil(RLMGetOptional(value))
  50. } else {
  51. XCTAssertNil(value)
  52. }
  53. }
  54. }
  55. func testInitWithOptionalDefaults() {
  56. let object = SwiftOptionalDefaultValuesObject()
  57. verifySwiftOptionalObjectWithDictionaryLiteral(object, dictionary:
  58. SwiftOptionalDefaultValuesObject.defaultValues(), boolObjectValue: true)
  59. }
  60. func testInitWithDictionary() {
  61. // dictionary with all values specified
  62. let baselineValues: [String: Any] =
  63. ["boolCol": true,
  64. "intCol": 1,
  65. "floatCol": 1.1 as Float,
  66. "doubleCol": 11.1,
  67. "stringCol": "b",
  68. "binaryCol": "b".data(using: String.Encoding.utf8)!,
  69. "dateCol": Date(timeIntervalSince1970: 2),
  70. "objectCol": SwiftBoolObject(value: [true]),
  71. "arrayCol": [SwiftBoolObject(value: [true]), SwiftBoolObject()]
  72. ]
  73. // test with valid dictionary literals
  74. let props = try! Realm().schema["SwiftObject"]!.properties
  75. for propNum in 0..<props.count {
  76. for validValue in validValuesForSwiftObjectType(props[propNum].type, props[propNum].isArray) {
  77. // update dict with valid value and init
  78. var values = baselineValues
  79. values[props[propNum].name] = validValue
  80. let object = SwiftObject(value: values)
  81. verifySwiftObjectWithDictionaryLiteral(object, dictionary: values, boolObjectValue: true,
  82. boolObjectListValues: [true, false])
  83. }
  84. }
  85. // test with invalid dictionary literals
  86. for propNum in 0..<props.count {
  87. for invalidValue in invalidValuesForSwiftObjectType(props[propNum].type, props[propNum].isArray) {
  88. // update dict with invalid value and init
  89. var values = baselineValues
  90. values[props[propNum].name] = invalidValue
  91. assertThrows(SwiftObject(value: values), "Invalid property value")
  92. }
  93. }
  94. }
  95. func testInitWithDefaultsAndDictionary() {
  96. // test with dictionary with mix of default and one specified value
  97. let object = SwiftObject(value: ["intCol": 200])
  98. let valueDict = defaultSwiftObjectValuesWithReplacements(["intCol": 200])
  99. verifySwiftObjectWithDictionaryLiteral(object, dictionary: valueDict, boolObjectValue: false,
  100. boolObjectListValues: [])
  101. }
  102. func testInitWithArray() {
  103. // array with all values specified
  104. let baselineValues: [Any] = [true, 1, 1.1 as Float, 11.1, "b", "b".data(using: String.Encoding.utf8)!,
  105. Date(timeIntervalSince1970: 2), ["boolCol": true], [[true], [false]]]
  106. // test with valid dictionary literals
  107. let props = try! Realm().schema["SwiftObject"]!.properties
  108. for propNum in 0..<props.count {
  109. for validValue in validValuesForSwiftObjectType(props[propNum].type, props[propNum].isArray) {
  110. // update dict with valid value and init
  111. var values = baselineValues
  112. values[propNum] = validValue
  113. let object = SwiftObject(value: values)
  114. verifySwiftObjectWithArrayLiteral(object, array: values, boolObjectValue: true,
  115. boolObjectListValues: [true, false])
  116. }
  117. }
  118. // test with invalid dictionary literals
  119. for propNum in 0..<props.count {
  120. for invalidValue in invalidValuesForSwiftObjectType(props[propNum].type, props[propNum].isArray) {
  121. // update dict with invalid value and init
  122. var values = baselineValues
  123. values[propNum] = invalidValue
  124. assertThrows(SwiftObject(value: values), "Invalid property value")
  125. }
  126. }
  127. }
  128. func testInitWithKVCObject() {
  129. // test with kvc object
  130. let objectWithInt = SwiftObject(value: ["intCol": 200])
  131. let objectWithKVCObject = SwiftObject(value: objectWithInt)
  132. let valueDict = defaultSwiftObjectValuesWithReplacements(["intCol": 200])
  133. verifySwiftObjectWithDictionaryLiteral(objectWithKVCObject, dictionary: valueDict, boolObjectValue: false,
  134. boolObjectListValues: [])
  135. }
  136. func testGenericInit() {
  137. func createObject<T: Object>() -> T {
  138. return T()
  139. }
  140. let obj1: SwiftBoolObject = createObject()
  141. let obj2 = SwiftBoolObject()
  142. XCTAssertEqual(obj1.boolCol, obj2.boolCol,
  143. "object created via generic initializer should equal object created by calling initializer directly")
  144. }
  145. func testInitWithObjcName() {
  146. // Test that init doesn't crash going into non-swift init logic for renamed Swift classes.
  147. _ = SwiftObjcRenamedObject()
  148. _ = SwiftObjcArbitrarilyRenamedObject()
  149. }
  150. // MARK: Creation tests
  151. func testCreateWithDefaults() {
  152. let realm = try! Realm()
  153. assertThrows(realm.create(SwiftObject.self), "Must be in write transaction")
  154. var object: SwiftObject!
  155. let objects = realm.objects(SwiftObject.self)
  156. XCTAssertEqual(0, objects.count)
  157. try! realm.write {
  158. // test create with all defaults
  159. object = realm.create(SwiftObject.self)
  160. return
  161. }
  162. verifySwiftObjectWithDictionaryLiteral(object, dictionary: SwiftObject.defaultValues(), boolObjectValue: false,
  163. boolObjectListValues: [])
  164. // test realm properties are populated correctly
  165. XCTAssertEqual(object.realm!, realm)
  166. XCTAssertEqual(object.objectCol!.realm!, realm)
  167. XCTAssertEqual(object.arrayCol.realm!, realm)
  168. }
  169. func testCreateWithOptionalWithoutDefaults() {
  170. let realm = try! Realm()
  171. try! realm.write {
  172. let object = realm.create(SwiftOptionalObject.self)
  173. for prop in object.objectSchema.properties {
  174. XCTAssertNil(object[prop.name])
  175. }
  176. }
  177. }
  178. func testCreateWithOptionalDefaults() {
  179. let realm = try! Realm()
  180. try! realm.write {
  181. let object = realm.create(SwiftOptionalDefaultValuesObject.self)
  182. self.verifySwiftOptionalObjectWithDictionaryLiteral(object,
  183. dictionary: SwiftOptionalDefaultValuesObject.defaultValues(), boolObjectValue: true)
  184. }
  185. }
  186. func testCreateWithOptionalIgnoredProperties() {
  187. let realm = try! Realm()
  188. try! realm.write {
  189. let object = realm.create(SwiftOptionalIgnoredPropertiesObject.self)
  190. let properties = object.objectSchema.properties
  191. XCTAssertEqual(properties.count, 1)
  192. XCTAssertEqual(properties[0].name, "id")
  193. }
  194. }
  195. func testCreateWithDictionary() {
  196. // dictionary with all values specified
  197. let baselineValues: [String: Any] = [
  198. "boolCol": true,
  199. "intCol": 1,
  200. "floatCol": 1.1 as Float,
  201. "doubleCol": 11.1,
  202. "stringCol": "b",
  203. "binaryCol": "b".data(using: String.Encoding.utf8)!,
  204. "dateCol": Date(timeIntervalSince1970: 2),
  205. "objectCol": SwiftBoolObject(value: [true]),
  206. "arrayCol": [SwiftBoolObject(value: [true]), SwiftBoolObject()]
  207. ]
  208. // test with valid dictionary literals
  209. let props = try! Realm().schema["SwiftObject"]!.properties
  210. for propNum in 0..<props.count {
  211. for validValue in validValuesForSwiftObjectType(props[propNum].type, props[propNum].isArray) {
  212. // update dict with valid value and init
  213. var values = baselineValues
  214. values[props[propNum].name] = validValue
  215. try! Realm().beginWrite()
  216. let object = try! Realm().create(SwiftObject.self, value: values)
  217. verifySwiftObjectWithDictionaryLiteral(object, dictionary: values, boolObjectValue: true,
  218. boolObjectListValues: [true, false])
  219. try! Realm().commitWrite()
  220. verifySwiftObjectWithDictionaryLiteral(object, dictionary: values, boolObjectValue: true,
  221. boolObjectListValues: [true, false])
  222. }
  223. }
  224. // test with invalid dictionary literals
  225. for propNum in 0..<props.count {
  226. for invalidValue in invalidValuesForSwiftObjectType(props[propNum].type, props[propNum].isArray) {
  227. // update dict with invalid value and init
  228. var values = baselineValues
  229. values[props[propNum].name] = invalidValue
  230. try! Realm().beginWrite()
  231. assertThrows(try! Realm().create(SwiftObject.self, value: values), "Invalid property value")
  232. try! Realm().cancelWrite()
  233. }
  234. }
  235. }
  236. func testCreateWithDefaultsAndDictionary() {
  237. // test with dictionary with mix of default and one specified value
  238. let realm = try! Realm()
  239. realm.beginWrite()
  240. let objectWithInt = realm.create(SwiftObject.self, value: ["intCol": 200])
  241. try! realm.commitWrite()
  242. let valueDict = defaultSwiftObjectValuesWithReplacements(["intCol": 200])
  243. verifySwiftObjectWithDictionaryLiteral(objectWithInt, dictionary: valueDict, boolObjectValue: false,
  244. boolObjectListValues: [])
  245. }
  246. func testCreateWithArray() {
  247. // array with all values specified
  248. let baselineValues: [Any] = [true, 1, 1.1 as Float, 11.1, "b", "b".data(using: String.Encoding.utf8)!,
  249. Date(timeIntervalSince1970: 2), ["boolCol": true], [[true], [false]]]
  250. // test with valid dictionary literals
  251. let props = try! Realm().schema["SwiftObject"]!.properties
  252. for propNum in 0..<props.count {
  253. for validValue in validValuesForSwiftObjectType(props[propNum].type, props[propNum].isArray) {
  254. // update dict with valid value and init
  255. var values = baselineValues
  256. values[propNum] = validValue
  257. try! Realm().beginWrite()
  258. let object = try! Realm().create(SwiftObject.self, value: values)
  259. verifySwiftObjectWithArrayLiteral(object, array: values, boolObjectValue: true,
  260. boolObjectListValues: [true, false])
  261. try! Realm().commitWrite()
  262. verifySwiftObjectWithArrayLiteral(object, array: values, boolObjectValue: true,
  263. boolObjectListValues: [true, false])
  264. }
  265. }
  266. // test with invalid array literals
  267. for propNum in 0..<props.count {
  268. for invalidValue in invalidValuesForSwiftObjectType(props[propNum].type, props[propNum].isArray) {
  269. // update dict with invalid value and init
  270. var values = baselineValues
  271. values[propNum] = invalidValue
  272. try! Realm().beginWrite()
  273. assertThrows(try! Realm().create(SwiftObject.self, value: values),
  274. "Invalid property value '\(invalidValue)' for property number \(propNum)")
  275. try! Realm().cancelWrite()
  276. }
  277. }
  278. }
  279. func testCreateWithKVCObject() {
  280. // test with kvc object
  281. try! Realm().beginWrite()
  282. let objectWithInt = try! Realm().create(SwiftObject.self, value: ["intCol": 200])
  283. let objectWithKVCObject = try! Realm().create(SwiftObject.self, value: objectWithInt)
  284. let valueDict = defaultSwiftObjectValuesWithReplacements(["intCol": 200])
  285. try! Realm().commitWrite()
  286. verifySwiftObjectWithDictionaryLiteral(objectWithKVCObject, dictionary: valueDict, boolObjectValue: false,
  287. boolObjectListValues: [])
  288. XCTAssertEqual(try! Realm().objects(SwiftObject.self).count, 2, "Object should have been copied")
  289. }
  290. func testCreateWithNestedObjects() {
  291. let standalone = SwiftPrimaryStringObject(value: ["p0", 11])
  292. try! Realm().beginWrite()
  293. let objectWithNestedObjects = try! Realm().create(SwiftLinkToPrimaryStringObject.self, value: ["p1", ["p1", 11],
  294. [standalone]])
  295. try! Realm().commitWrite()
  296. let stringObjects = try! Realm().objects(SwiftPrimaryStringObject.self)
  297. XCTAssertEqual(stringObjects.count, 2)
  298. let persistedObject = stringObjects.first!
  299. // standalone object should be copied into the realm, not added directly
  300. XCTAssertNotEqual(standalone, persistedObject)
  301. XCTAssertEqual(objectWithNestedObjects.object!, persistedObject)
  302. XCTAssertEqual(objectWithNestedObjects.objects.first!, stringObjects.last!)
  303. let standalone1 = SwiftPrimaryStringObject(value: ["p3", 11])
  304. try! Realm().beginWrite()
  305. assertThrows(try! Realm().create(SwiftLinkToPrimaryStringObject.self, value: ["p3", ["p3", 11], [standalone1]]),
  306. "Should throw with duplicate primary key")
  307. try! Realm().commitWrite()
  308. }
  309. func testUpdateWithNestedObjects() {
  310. let standalone = SwiftPrimaryStringObject(value: ["primary", 11])
  311. try! Realm().beginWrite()
  312. let object = try! Realm().create(SwiftLinkToPrimaryStringObject.self, value: ["otherPrimary", ["primary", 12],
  313. [["primary", 12]]], update: true)
  314. try! Realm().commitWrite()
  315. let stringObjects = try! Realm().objects(SwiftPrimaryStringObject.self)
  316. XCTAssertEqual(stringObjects.count, 1)
  317. let persistedObject = object.object!
  318. XCTAssertEqual(persistedObject.intCol, 12)
  319. XCTAssertNil(standalone.realm) // the standalone object should be copied, rather than added, to the realm
  320. XCTAssertEqual(object.object!, persistedObject)
  321. XCTAssertEqual(object.objects.first!, persistedObject)
  322. }
  323. func testCreateWithObjectsFromAnotherRealm() {
  324. let values: [String: Any] = [
  325. "boolCol": true,
  326. "intCol": 1,
  327. "floatCol": 1.1 as Float,
  328. "doubleCol": 11.1,
  329. "stringCol": "b",
  330. "binaryCol": "b".data(using: String.Encoding.utf8)!,
  331. "dateCol": Date(timeIntervalSince1970: 2),
  332. "objectCol": SwiftBoolObject(value: [true]),
  333. "arrayCol": [SwiftBoolObject(value: [true]), SwiftBoolObject()]
  334. ]
  335. realmWithTestPath().beginWrite()
  336. let otherRealmObject = realmWithTestPath().create(SwiftObject.self, value: values)
  337. try! realmWithTestPath().commitWrite()
  338. try! Realm().beginWrite()
  339. let object = try! Realm().create(SwiftObject.self, value: otherRealmObject)
  340. try! Realm().commitWrite()
  341. XCTAssertNotEqual(otherRealmObject, object)
  342. verifySwiftObjectWithDictionaryLiteral(object, dictionary: values, boolObjectValue: true,
  343. boolObjectListValues: [true, false])
  344. }
  345. func testCreateWithDeeplyNestedObjectsFromAnotherRealm() {
  346. let values: [String: Any] = [
  347. "boolCol": true,
  348. "intCol": 1,
  349. "floatCol": 1.1 as Float,
  350. "doubleCol": 11.1,
  351. "stringCol": "b",
  352. "binaryCol": "b".data(using: String.Encoding.utf8)!,
  353. "dateCol": Date(timeIntervalSince1970: 2),
  354. "objectCol": SwiftBoolObject(value: [true]),
  355. "arrayCol": [SwiftBoolObject(value: [true]), SwiftBoolObject()]
  356. ]
  357. let realmA = realmWithTestPath()
  358. let realmB = try! Realm()
  359. var realmAObject: SwiftListOfSwiftObject!
  360. try! realmA.write {
  361. let array = [SwiftObject(value: values), SwiftObject(value: values)]
  362. realmAObject = realmA.create(SwiftListOfSwiftObject.self, value: ["array": array])
  363. }
  364. var realmBObject: SwiftListOfSwiftObject!
  365. try! realmB.write {
  366. realmBObject = realmB.create(SwiftListOfSwiftObject.self, value: realmAObject)
  367. }
  368. XCTAssertNotEqual(realmAObject, realmBObject)
  369. XCTAssertEqual(realmBObject.array.count, 2)
  370. for swiftObject in realmBObject.array {
  371. verifySwiftObjectWithDictionaryLiteral(swiftObject, dictionary: values, boolObjectValue: true,
  372. boolObjectListValues: [true, false])
  373. }
  374. }
  375. func testUpdateWithObjectsFromAnotherRealm() {
  376. realmWithTestPath().beginWrite()
  377. let otherRealmObject = realmWithTestPath().create(SwiftLinkToPrimaryStringObject.self,
  378. value: ["primary", NSNull(), [["2", 2], ["4", 4]]])
  379. try! realmWithTestPath().commitWrite()
  380. try! Realm().beginWrite()
  381. try! Realm().create(SwiftLinkToPrimaryStringObject.self, value: ["primary", ["10", 10], [["11", 11]]])
  382. let object = try! Realm().create(SwiftLinkToPrimaryStringObject.self, value: otherRealmObject, update: true)
  383. try! Realm().commitWrite()
  384. XCTAssertNotEqual(otherRealmObject, object) // the object from the other realm should be copied into this realm
  385. XCTAssertEqual(try! Realm().objects(SwiftLinkToPrimaryStringObject.self).count, 1)
  386. XCTAssertEqual(try! Realm().objects(SwiftPrimaryStringObject.self).count, 4)
  387. }
  388. func testCreateWithNSNullLinks() {
  389. let values: [String: Any] = [
  390. "boolCol": true,
  391. "intCol": 1,
  392. "floatCol": 1.1,
  393. "doubleCol": 11.1,
  394. "stringCol": "b",
  395. "binaryCol": "b".data(using: String.Encoding.utf8)!,
  396. "dateCol": Date(timeIntervalSince1970: 2),
  397. "objectCol": NSNull(),
  398. "arrayCol": NSNull()
  399. ]
  400. realmWithTestPath().beginWrite()
  401. let object = realmWithTestPath().create(SwiftObject.self, value: values)
  402. try! realmWithTestPath().commitWrite()
  403. XCTAssert(object.objectCol == nil) // XCTAssertNil caused a NULL deref inside _swift_getClass
  404. XCTAssertEqual(object.arrayCol.count, 0)
  405. }
  406. func testCreateWithObjcName() {
  407. let realm = try! Realm()
  408. try! realm.write {
  409. let object = realm.create(SwiftObjcRenamedObject.self)
  410. object.stringCol = "string"
  411. }
  412. XCTAssertEqual(realm.objects(SwiftObjcRenamedObject.self).count, 1)
  413. try! realm.write {
  414. realm.delete(realm.objects(SwiftObjcRenamedObject.self))
  415. }
  416. }
  417. func testCreateWithDifferentObjcName() {
  418. let realm = try! Realm()
  419. try! realm.write {
  420. let object = realm.create(SwiftObjcArbitrarilyRenamedObject.self)
  421. object.boolCol = true
  422. }
  423. XCTAssertEqual(realm.objects(SwiftObjcArbitrarilyRenamedObject.self).count, 1)
  424. try! realm.write {
  425. realm.delete(realm.objects(SwiftObjcArbitrarilyRenamedObject.self))
  426. }
  427. }
  428. func testCreateOrUpdateNil() {
  429. let realm = try! Realm()
  430. realm.beginWrite()
  431. // Create with all fields nil
  432. let object = realm.create(SwiftOptionalPrimaryObject.self, value: SwiftOptionalPrimaryObject(), update: true)
  433. XCTAssertNil(object.id.value)
  434. XCTAssertNil(object.optIntCol.value)
  435. XCTAssertNil(object.optInt8Col.value)
  436. XCTAssertNil(object.optInt16Col.value)
  437. XCTAssertNil(object.optInt32Col.value)
  438. XCTAssertNil(object.optInt64Col.value)
  439. XCTAssertNil(object.optBoolCol.value)
  440. XCTAssertNil(object.optFloatCol.value)
  441. XCTAssertNil(object.optDoubleCol.value)
  442. XCTAssertNil(object.optDateCol)
  443. XCTAssertNil(object.optStringCol)
  444. XCTAssertNil(object.optNSStringCol)
  445. XCTAssertNil(object.optBinaryCol)
  446. XCTAssertNil(object.optObjectCol)
  447. // Try to switch to non-nil
  448. let object2 = SwiftOptionalPrimaryObject()
  449. object2.optIntCol.value = 1
  450. object2.optInt8Col.value = 1
  451. object2.optInt16Col.value = 1
  452. object2.optInt32Col.value = 1
  453. object2.optInt64Col.value = 1
  454. object2.optFloatCol.value = 1
  455. object2.optDoubleCol.value = 1
  456. object2.optBoolCol.value = true
  457. object2.optDateCol = Date()
  458. object2.optStringCol = ""
  459. object2.optNSStringCol = ""
  460. object2.optBinaryCol = Data()
  461. object2.optObjectCol = SwiftBoolObject()
  462. realm.create(SwiftOptionalPrimaryObject.self, value: object2, update: true)
  463. XCTAssertNil(object.id.value)
  464. XCTAssertNotNil(object.optIntCol.value)
  465. XCTAssertNotNil(object.optInt8Col.value)
  466. XCTAssertNotNil(object.optInt16Col.value)
  467. XCTAssertNotNil(object.optInt32Col.value)
  468. XCTAssertNotNil(object.optInt64Col.value)
  469. XCTAssertNotNil(object.optBoolCol.value)
  470. XCTAssertNotNil(object.optFloatCol.value)
  471. XCTAssertNotNil(object.optDoubleCol.value)
  472. XCTAssertNotNil(object.optDateCol)
  473. XCTAssertNotNil(object.optStringCol)
  474. XCTAssertNotNil(object.optNSStringCol)
  475. XCTAssertNotNil(object.optBinaryCol)
  476. XCTAssertNotNil(object.optObjectCol)
  477. // Try to switch back to nil
  478. realm.create(SwiftOptionalPrimaryObject.self, value: SwiftOptionalPrimaryObject(), update: true)
  479. XCTAssertNil(object.id.value)
  480. XCTAssertNil(object.optIntCol.value)
  481. XCTAssertNil(object.optInt8Col.value)
  482. XCTAssertNil(object.optInt16Col.value)
  483. XCTAssertNil(object.optInt32Col.value)
  484. XCTAssertNil(object.optInt64Col.value)
  485. XCTAssertNil(object.optBoolCol.value)
  486. XCTAssertNil(object.optFloatCol.value)
  487. XCTAssertNil(object.optDoubleCol.value)
  488. XCTAssertNil(object.optDateCol)
  489. XCTAssertNil(object.optStringCol)
  490. XCTAssertNil(object.optNSStringCol)
  491. XCTAssertNil(object.optBinaryCol)
  492. XCTAssertNil(object.optObjectCol)
  493. realm.cancelWrite()
  494. }
  495. func testCreateOrUpdateDynamicUnmanagedType() {
  496. let realm = try! Realm()
  497. let unmanagedValue = SwiftOptionalPrimaryObject()
  498. // Shouldn't throw.
  499. realm.beginWrite()
  500. _ = realm.create(type(of: unmanagedValue), value: unmanagedValue, update: true)
  501. realm.cancelWrite()
  502. }
  503. func testCreateOrUpdateDynamicManagedType() {
  504. let realm = try! Realm()
  505. let managedValue = SwiftOptionalPrimaryObject()
  506. try! realm.write {
  507. realm.add(managedValue)
  508. }
  509. // Shouldn't throw.
  510. realm.beginWrite()
  511. _ = realm.create(type(of: managedValue), value: managedValue, update: true)
  512. realm.cancelWrite()
  513. }
  514. // test null object
  515. // test null list
  516. // MARK: Add tests
  517. func testAddWithExisingNestedObjects() {
  518. try! Realm().beginWrite()
  519. let existingObject = try! Realm().create(SwiftBoolObject.self)
  520. try! Realm().commitWrite()
  521. try! Realm().beginWrite()
  522. let object = SwiftObject(value: ["objectCol": existingObject])
  523. try! Realm().add(object)
  524. try! Realm().commitWrite()
  525. XCTAssertNotNil(object.realm)
  526. assertEqual(object.objectCol, existingObject)
  527. }
  528. func testAddAndUpdateWithExisingNestedObjects() {
  529. try! Realm().beginWrite()
  530. let existingObject = try! Realm().create(SwiftPrimaryStringObject.self, value: ["primary", 1])
  531. try! Realm().commitWrite()
  532. try! Realm().beginWrite()
  533. let object = SwiftLinkToPrimaryStringObject(value: ["primary", ["primary", 2], []])
  534. try! Realm().add(object, update: true)
  535. try! Realm().commitWrite()
  536. XCTAssertNotNil(object.realm)
  537. XCTAssertEqual(object.object!, existingObject) // the existing object should be updated
  538. XCTAssertEqual(existingObject.intCol, 2)
  539. }
  540. func testAddObjectCycle() {
  541. weak var weakObj1: SwiftCircleObject? = nil, weakObj2: SwiftCircleObject? = nil
  542. autoreleasepool {
  543. let obj1 = SwiftCircleObject(value: [])
  544. let obj2 = SwiftCircleObject(value: [obj1, [obj1]])
  545. obj1.obj = obj2
  546. obj1.array.append(obj2)
  547. weakObj1 = obj1
  548. weakObj2 = obj2
  549. let realm = try! Realm()
  550. try! realm.write {
  551. realm.add(obj1)
  552. }
  553. XCTAssertEqual(obj1.realm, realm)
  554. XCTAssertEqual(obj2.realm, realm)
  555. }
  556. XCTAssertNil(weakObj1)
  557. XCTAssertNil(weakObj2)
  558. }
  559. func testAddOrUpdateNil() {
  560. let realm = try! Realm()
  561. realm.beginWrite()
  562. // Create with all fields nil
  563. let object = SwiftOptionalPrimaryObject()
  564. realm.add(object)
  565. XCTAssertNil(object.id.value)
  566. XCTAssertNil(object.optIntCol.value)
  567. XCTAssertNil(object.optInt8Col.value)
  568. XCTAssertNil(object.optInt16Col.value)
  569. XCTAssertNil(object.optInt32Col.value)
  570. XCTAssertNil(object.optInt64Col.value)
  571. XCTAssertNil(object.optBoolCol.value)
  572. XCTAssertNil(object.optFloatCol.value)
  573. XCTAssertNil(object.optDoubleCol.value)
  574. XCTAssertNil(object.optDateCol)
  575. XCTAssertNil(object.optStringCol)
  576. XCTAssertNil(object.optNSStringCol)
  577. XCTAssertNil(object.optBinaryCol)
  578. XCTAssertNil(object.optObjectCol)
  579. // Try to switch to non-nil
  580. let object2 = SwiftOptionalPrimaryObject()
  581. object2.optIntCol.value = 1
  582. object2.optInt8Col.value = 1
  583. object2.optInt16Col.value = 1
  584. object2.optInt32Col.value = 1
  585. object2.optInt64Col.value = 1
  586. object2.optFloatCol.value = 1
  587. object2.optDoubleCol.value = 1
  588. object2.optBoolCol.value = true
  589. object2.optDateCol = Date()
  590. object2.optStringCol = ""
  591. object2.optNSStringCol = ""
  592. object2.optBinaryCol = Data()
  593. object2.optObjectCol = SwiftBoolObject()
  594. realm.add(object2, update: true)
  595. XCTAssertNil(object.id.value)
  596. XCTAssertNotNil(object.optIntCol.value)
  597. XCTAssertNotNil(object.optInt8Col.value)
  598. XCTAssertNotNil(object.optInt16Col.value)
  599. XCTAssertNotNil(object.optInt32Col.value)
  600. XCTAssertNotNil(object.optInt64Col.value)
  601. XCTAssertNotNil(object.optBoolCol.value)
  602. XCTAssertNotNil(object.optFloatCol.value)
  603. XCTAssertNotNil(object.optDoubleCol.value)
  604. XCTAssertNotNil(object.optDateCol)
  605. XCTAssertNotNil(object.optStringCol)
  606. XCTAssertNotNil(object.optNSStringCol)
  607. XCTAssertNotNil(object.optBinaryCol)
  608. XCTAssertNotNil(object.optObjectCol)
  609. // Try to switch back to nil
  610. let object3 = SwiftOptionalPrimaryObject()
  611. realm.add(object3, update: true)
  612. XCTAssertNil(object.id.value)
  613. XCTAssertNil(object.optIntCol.value)
  614. XCTAssertNil(object.optInt8Col.value)
  615. XCTAssertNil(object.optInt16Col.value)
  616. XCTAssertNil(object.optInt32Col.value)
  617. XCTAssertNil(object.optInt64Col.value)
  618. XCTAssertNil(object.optBoolCol.value)
  619. XCTAssertNil(object.optFloatCol.value)
  620. XCTAssertNil(object.optDoubleCol.value)
  621. XCTAssertNil(object.optDateCol)
  622. XCTAssertNil(object.optStringCol)
  623. XCTAssertNil(object.optNSStringCol)
  624. XCTAssertNil(object.optBinaryCol)
  625. XCTAssertNil(object.optObjectCol)
  626. realm.cancelWrite()
  627. }
  628. /// If a Swift class declares generic properties before non-generic ones, the properties
  629. /// should be registered in order and creation from an array of values should work.
  630. func testProperOrderingOfProperties() {
  631. let v: [Any] = [
  632. // Superclass's columns
  633. [["intCol": 42], ["intCol": 9001]],
  634. 100,
  635. 200,
  636. // Class's columns
  637. 1,
  638. [["stringCol": "hello"], ["stringCol": "world"]],
  639. 2,
  640. [["stringCol": "goodbye"], ["stringCol": "cruel"], ["stringCol": "world"]],
  641. NSNull(),
  642. 3,
  643. 300]
  644. let object = SwiftGenericPropsOrderingObject(value: v)
  645. XCTAssertEqual(object.firstNumber, 1)
  646. XCTAssertEqual(object.secondNumber, 2)
  647. XCTAssertEqual(object.thirdNumber, 3)
  648. XCTAssertTrue(object.firstArray.count == 2)
  649. XCTAssertEqual(object.firstArray[0].stringCol, "hello")
  650. XCTAssertEqual(object.firstArray[1].stringCol, "world")
  651. XCTAssertTrue(object.secondArray.count == 3)
  652. XCTAssertEqual(object.secondArray[0].stringCol, "goodbye")
  653. XCTAssertEqual(object.secondArray[1].stringCol, "cruel")
  654. XCTAssertEqual(object.secondArray[2].stringCol, "world")
  655. XCTAssertEqual(object.firstOptionalNumber.value, nil)
  656. XCTAssertEqual(object.secondOptionalNumber.value, 300)
  657. XCTAssertTrue(object.parentFirstList.count == 2)
  658. XCTAssertEqual(object.parentFirstList[0].intCol, 42)
  659. XCTAssertEqual(object.parentFirstList[1].intCol, 9001)
  660. XCTAssertEqual(object.parentFirstNumber, 100)
  661. XCTAssertEqual(object.parentSecondNumber, 200)
  662. XCTAssertTrue(object.firstLinking.count == 0)
  663. XCTAssertTrue(object.secondLinking.count == 0)
  664. }
  665. func testPrivateOptionalNonobjcString() {
  666. let realm = try! Realm()
  667. try! realm.write {
  668. let obj = ObjectWithPrivateOptionals()
  669. obj.value = 5
  670. realm.add(obj)
  671. XCTAssertEqual(realm.objects(ObjectWithPrivateOptionals.self).first!.value, 5)
  672. }
  673. }
  674. // MARK: Private utilities
  675. private func verifySwiftObjectWithArrayLiteral(_ object: SwiftObject, array: [Any], boolObjectValue: Bool,
  676. boolObjectListValues: [Bool]) {
  677. XCTAssertEqual(object.boolCol, (array[0] as! Bool))
  678. XCTAssertEqual(object.intCol, (array[1] as! Int))
  679. //XCTAssertEqual(object.floatCol, (array[2] as! Float)) // FIXME: crashes with swift 3.2
  680. XCTAssertEqual(object.doubleCol, (array[3] as! Double))
  681. XCTAssertEqual(object.stringCol, (array[4] as! String))
  682. XCTAssertEqual(object.binaryCol, (array[5] as! Data))
  683. XCTAssertEqual(object.dateCol, (array[6] as! Date))
  684. XCTAssertEqual(object.objectCol!.boolCol, boolObjectValue)
  685. XCTAssertEqual(object.arrayCol.count, boolObjectListValues.count)
  686. for i in 0..<boolObjectListValues.count {
  687. XCTAssertEqual(object.arrayCol[i].boolCol, boolObjectListValues[i])
  688. }
  689. }
  690. private func verifySwiftObjectWithDictionaryLiteral(_ object: SwiftObject, dictionary: [String: Any],
  691. boolObjectValue: Bool, boolObjectListValues: [Bool]) {
  692. XCTAssertEqual(object.boolCol, (dictionary["boolCol"] as! Bool))
  693. XCTAssertEqual(object.intCol, (dictionary["intCol"] as! Int))
  694. //XCTAssertEqual(object.floatCol, (dictionary["floatCol"] as! Float)) // FIXME: crashes with swift 3.2
  695. XCTAssertEqual(object.doubleCol, (dictionary["doubleCol"] as! Double))
  696. XCTAssertEqual(object.stringCol, (dictionary["stringCol"] as! String))
  697. XCTAssertEqual(object.binaryCol, (dictionary["binaryCol"] as! Data))
  698. XCTAssertEqual(object.dateCol, (dictionary["dateCol"] as! Date))
  699. XCTAssertEqual(object.objectCol!.boolCol, boolObjectValue)
  700. XCTAssertEqual(object.arrayCol.count, boolObjectListValues.count)
  701. for i in 0..<boolObjectListValues.count {
  702. XCTAssertEqual(object.arrayCol[i].boolCol, boolObjectListValues[i])
  703. }
  704. }
  705. private func verifySwiftOptionalObjectWithDictionaryLiteral(_ object: SwiftOptionalDefaultValuesObject,
  706. dictionary: [String: Any],
  707. boolObjectValue: Bool?) {
  708. XCTAssertEqual(object.optBoolCol.value, (dictionary["optBoolCol"] as! Bool?))
  709. XCTAssertEqual(object.optIntCol.value, (dictionary["optIntCol"] as! Int?))
  710. XCTAssertEqual(object.optInt8Col.value,
  711. ((dictionary["optInt8Col"] as! NSNumber?)?.int8Value).map({Int8($0)}))
  712. XCTAssertEqual(object.optInt16Col.value,
  713. ((dictionary["optInt16Col"] as! NSNumber?)?.int16Value).map({Int16($0)}))
  714. XCTAssertEqual(object.optInt32Col.value,
  715. ((dictionary["optInt32Col"] as! NSNumber?)?.int32Value).map({Int32($0)}))
  716. XCTAssertEqual(object.optInt64Col.value, (dictionary["optInt64Col"] as! NSNumber?)?.int64Value)
  717. XCTAssertEqual(object.optFloatCol.value, (dictionary["optFloatCol"] as! Float?))
  718. XCTAssertEqual(object.optDoubleCol.value, (dictionary["optDoubleCol"] as! Double?))
  719. XCTAssertEqual(object.optStringCol, (dictionary["optStringCol"] as! String?))
  720. XCTAssertEqual(object.optNSStringCol, (dictionary["optNSStringCol"] as! NSString))
  721. XCTAssertEqual(object.optBinaryCol, (dictionary["optBinaryCol"] as! Data?))
  722. XCTAssertEqual(object.optDateCol, (dictionary["optDateCol"] as! Date?))
  723. XCTAssertEqual(object.optObjectCol?.boolCol, boolObjectValue)
  724. }
  725. private func defaultSwiftObjectValuesWithReplacements(_ replace: [String: Any]) -> [String: Any] {
  726. var valueDict = SwiftObject.defaultValues()
  727. for (key, value) in replace {
  728. valueDict[key] = value
  729. }
  730. return valueDict
  731. }
  732. // return an array of valid values that can be used to initialize each type
  733. // swiftlint:disable:next cyclomatic_complexity
  734. private func validValuesForSwiftObjectType(_ type: PropertyType, _ array: Bool) -> [Any] {
  735. try! Realm().beginWrite()
  736. let persistedObject = try! Realm().create(SwiftBoolObject.self, value: [true])
  737. try! Realm().commitWrite()
  738. if array {
  739. return [
  740. [[true], [false]],
  741. [["boolCol": true], ["boolCol": false]],
  742. [SwiftBoolObject(value: [true]), SwiftBoolObject(value: [false])],
  743. [persistedObject, [false]]
  744. ]
  745. }
  746. switch type {
  747. case .bool: return [true, NSNumber(value: 0 as Int), NSNumber(value: 1 as Int)]
  748. case .int: return [NSNumber(value: 1 as Int)]
  749. case .float: return [NSNumber(value: 1 as Int), NSNumber(value: 1.1 as Float), NSNumber(value: 11.1 as Double)]
  750. case .double: return [NSNumber(value: 1 as Int), NSNumber(value: 1.1 as Float), NSNumber(value: 11.1 as Double)]
  751. case .string: return ["b"]
  752. case .data: return ["b".data(using: String.Encoding.utf8, allowLossyConversion: false)!]
  753. case .date: return [Date(timeIntervalSince1970: 2)]
  754. case .object: return [[true], ["boolCol": true], SwiftBoolObject(value: [true]), persistedObject]
  755. case .any: XCTFail("not supported")
  756. case .linkingObjects: XCTFail("not supported")
  757. }
  758. return []
  759. }
  760. // swiftlint:disable:next cyclomatic_complexity
  761. private func invalidValuesForSwiftObjectType(_ type: PropertyType, _ array: Bool) -> [Any] {
  762. try! Realm().beginWrite()
  763. let persistedObject = try! Realm().create(SwiftIntObject.self)
  764. try! Realm().commitWrite()
  765. if array {
  766. return ["invalid", [["a"]], [["boolCol": "a"]], [[SwiftIntObject()]], [[persistedObject]]]
  767. }
  768. switch type {
  769. case .bool: return ["invalid", NSNumber(value: 2 as Int), NSNumber(value: 1.1 as Float), NSNumber(value: 11.1 as Double)]
  770. case .int: return ["invalid", NSNumber(value: 1.1 as Float), NSNumber(value: 11.1 as Double)]
  771. case .float: return ["invalid", true, false]
  772. case .double: return ["invalid", true, false]
  773. case .string: return [0x197A71D, true, false]
  774. case .data: return ["invalid"]
  775. case .date: return ["invalid"]
  776. case .object: return ["invalid", ["a"], ["boolCol": "a"], SwiftIntObject()]
  777. case .any: XCTFail("not supported")
  778. case .linkingObjects: XCTFail("not supported")
  779. }
  780. return []
  781. }
  782. }