SwiftObjectInterfaceTests.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2014 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 Realm
  20. import Foundation
  21. import RealmTestSupport
  22. class OuterClass {
  23. class InnerClass {
  24. }
  25. }
  26. class SwiftRLMStringObjectSubclass: SwiftRLMStringObject {
  27. @objc dynamic var stringCol2 = ""
  28. }
  29. class SwiftRLMSelfRefrencingSubclass: SwiftRLMStringObject {
  30. @objc dynamic var objects = RLMArray<SwiftRLMSelfRefrencingSubclass>(objectClassName: SwiftRLMSelfRefrencingSubclass.className())
  31. }
  32. class SwiftRLMDefaultObject: RLMObject {
  33. @objc dynamic var intCol = 1
  34. @objc dynamic var boolCol = true
  35. override class func defaultPropertyValues() -> [AnyHashable : Any]? {
  36. return ["intCol": 2]
  37. }
  38. }
  39. class SwiftRLMOptionalNumberObject: RLMObject {
  40. @objc dynamic var intCol: NSNumber? = 1
  41. @objc dynamic var floatCol: NSNumber? = 2.2 as Float as NSNumber
  42. @objc dynamic var doubleCol: NSNumber? = 3.3
  43. @objc dynamic var boolCol: NSNumber? = true
  44. }
  45. class SwiftRLMObjectInterfaceTests: RLMTestCase {
  46. // Swift models
  47. func testSwiftRLMObject() {
  48. let realm = realmWithTestPath()
  49. realm.beginWriteTransaction()
  50. let obj = SwiftRLMObject()
  51. realm.add(obj)
  52. obj.boolCol = true
  53. obj.intCol = 1234
  54. obj.floatCol = 1.1
  55. obj.doubleCol = 2.2
  56. obj.stringCol = "abcd"
  57. obj.binaryCol = "abcd".data(using: String.Encoding.utf8)
  58. obj.dateCol = Date(timeIntervalSince1970: 123)
  59. obj.objectCol = SwiftRLMBoolObject()
  60. obj.objectCol.boolCol = true
  61. obj.arrayCol.add(obj.objectCol)
  62. try! realm.commitWriteTransaction()
  63. let data = "abcd".data(using: String.Encoding.utf8)
  64. let firstObj = SwiftRLMObject.allObjects(in: realm).firstObject() as! SwiftRLMObject
  65. XCTAssertEqual(firstObj.boolCol, true, "should be true")
  66. XCTAssertEqual(firstObj.intCol, 1234, "should be 1234")
  67. XCTAssertEqual(firstObj.floatCol, Float(1.1), "should be 1.1")
  68. XCTAssertEqual(firstObj.doubleCol, 2.2, "should be 2.2")
  69. XCTAssertEqual(firstObj.stringCol, "abcd", "should be abcd")
  70. XCTAssertEqual(firstObj.binaryCol!, data!)
  71. XCTAssertEqual(firstObj.dateCol, Date(timeIntervalSince1970: 123), "should be epoch + 123")
  72. XCTAssertEqual(firstObj.objectCol.boolCol, true, "should be true")
  73. XCTAssertEqual(obj.arrayCol.count, UInt(1), "array count should be 1")
  74. XCTAssertEqual(obj.arrayCol.firstObject()!.boolCol, true, "should be true")
  75. }
  76. func testDefaultValueSwiftRLMObject() {
  77. let realm = realmWithTestPath()
  78. realm.beginWriteTransaction()
  79. realm.add(SwiftRLMObject())
  80. try! realm.commitWriteTransaction()
  81. let data = "a".data(using: String.Encoding.utf8)
  82. let firstObj = SwiftRLMObject.allObjects(in: realm).firstObject() as! SwiftRLMObject
  83. XCTAssertEqual(firstObj.boolCol, false, "should be false")
  84. XCTAssertEqual(firstObj.intCol, 123, "should be 123")
  85. XCTAssertEqual(firstObj.floatCol, Float(1.23), "should be 1.23")
  86. XCTAssertEqual(firstObj.doubleCol, 12.3, "should be 12.3")
  87. XCTAssertEqual(firstObj.stringCol, "a", "should be a")
  88. XCTAssertEqual(firstObj.binaryCol!, data!)
  89. XCTAssertEqual(firstObj.dateCol, Date(timeIntervalSince1970: 1), "should be epoch + 1")
  90. XCTAssertEqual(firstObj.objectCol.boolCol, false, "should be false")
  91. XCTAssertEqual(firstObj.arrayCol.count, UInt(0), "array count should be zero")
  92. }
  93. func testMergedDefaultValuesSwiftRLMObject() {
  94. let realm = self.realmWithTestPath()
  95. realm.beginWriteTransaction()
  96. _ = SwiftRLMDefaultObject.create(in: realm, withValue: NSDictionary())
  97. try! realm.commitWriteTransaction()
  98. let object = SwiftRLMDefaultObject.allObjects(in: realm).firstObject() as! SwiftRLMDefaultObject
  99. XCTAssertEqual(object.intCol, 2, "defaultPropertyValues should override native property default value")
  100. XCTAssertEqual(object.boolCol, true, "native property default value should be used if defaultPropertyValues doesn't contain that key")
  101. }
  102. func testSubclass() {
  103. // test className methods
  104. XCTAssertEqual("SwiftRLMStringObject", SwiftRLMStringObject.className())
  105. XCTAssertEqual("SwiftRLMStringObjectSubclass", SwiftRLMStringObjectSubclass.className())
  106. let realm = RLMRealm.default()
  107. realm.beginWriteTransaction()
  108. _ = SwiftRLMStringObject.createInDefaultRealm(withValue: ["string"])
  109. _ = SwiftRLMStringObjectSubclass.createInDefaultRealm(withValue: ["string", "string2"])
  110. try! realm.commitWriteTransaction()
  111. // ensure creation in proper table
  112. XCTAssertEqual(UInt(1), SwiftRLMStringObjectSubclass.allObjects().count)
  113. XCTAssertEqual(UInt(1), SwiftRLMStringObject.allObjects().count)
  114. try! realm.transaction {
  115. // create self referencing subclass
  116. let sub = SwiftRLMSelfRefrencingSubclass.createInDefaultRealm(withValue: ["string", []])
  117. let sub2 = SwiftRLMSelfRefrencingSubclass()
  118. sub.objects.add(sub2)
  119. }
  120. }
  121. func testOptionalNSNumberProperties() {
  122. let realm = realmWithTestPath()
  123. let no = SwiftRLMOptionalNumberObject()
  124. XCTAssertEqual([.int, .float, .double, .bool], no.objectSchema.properties.map { $0.type })
  125. XCTAssertEqual(1, no.intCol!)
  126. XCTAssertEqual(2.2 as Float as NSNumber, no.floatCol!)
  127. XCTAssertEqual(3.3, no.doubleCol!)
  128. XCTAssertEqual(true, no.boolCol!)
  129. try! realm.transaction {
  130. realm.add(no)
  131. no.intCol = nil
  132. no.floatCol = nil
  133. no.doubleCol = nil
  134. no.boolCol = nil
  135. }
  136. XCTAssertNil(no.intCol)
  137. XCTAssertNil(no.floatCol)
  138. XCTAssertNil(no.doubleCol)
  139. XCTAssertNil(no.boolCol)
  140. try! realm.transaction {
  141. no.intCol = 1.1
  142. no.floatCol = 2.2 as Float as NSNumber
  143. no.doubleCol = 3.3
  144. no.boolCol = false
  145. }
  146. XCTAssertEqual(1, no.intCol!)
  147. XCTAssertEqual(2.2 as Float as NSNumber, no.floatCol!)
  148. XCTAssertEqual(3.3, no.doubleCol!)
  149. XCTAssertEqual(false, no.boolCol!)
  150. }
  151. func testOptionalSwiftRLMProperties() {
  152. let realm = realmWithTestPath()
  153. try! realm.transaction { realm.add(SwiftRLMOptionalObject()) }
  154. let firstObj = SwiftRLMOptionalObject.allObjects(in: realm).firstObject() as! SwiftRLMOptionalObject
  155. XCTAssertNil(firstObj.optObjectCol)
  156. XCTAssertNil(firstObj.optStringCol)
  157. XCTAssertNil(firstObj.optNSStringCol)
  158. XCTAssertNil(firstObj.optBinaryCol)
  159. XCTAssertNil(firstObj.optDateCol)
  160. try! realm.transaction {
  161. firstObj.optObjectCol = SwiftRLMBoolObject()
  162. firstObj.optObjectCol!.boolCol = true
  163. firstObj.optStringCol = "Hi!"
  164. firstObj.optNSStringCol = "Hi!"
  165. firstObj.optBinaryCol = Data(bytes: "hi", count: 2)
  166. firstObj.optDateCol = Date(timeIntervalSinceReferenceDate: 10)
  167. }
  168. XCTAssertTrue(firstObj.optObjectCol!.boolCol)
  169. XCTAssertEqual(firstObj.optStringCol!, "Hi!")
  170. XCTAssertEqual(firstObj.optNSStringCol!, "Hi!")
  171. XCTAssertEqual(firstObj.optBinaryCol!, Data(bytes: "hi", count: 2))
  172. XCTAssertEqual(firstObj.optDateCol!, Date(timeIntervalSinceReferenceDate: 10))
  173. try! realm.transaction {
  174. firstObj.optObjectCol = nil
  175. firstObj.optStringCol = nil
  176. firstObj.optNSStringCol = nil
  177. firstObj.optBinaryCol = nil
  178. firstObj.optDateCol = nil
  179. }
  180. XCTAssertNil(firstObj.optObjectCol)
  181. XCTAssertNil(firstObj.optStringCol)
  182. XCTAssertNil(firstObj.optNSStringCol)
  183. XCTAssertNil(firstObj.optBinaryCol)
  184. XCTAssertNil(firstObj.optDateCol)
  185. }
  186. func testSwiftRLMClassNameIsDemangled() {
  187. XCTAssertEqual(SwiftRLMObject.className(), "SwiftRLMObject",
  188. "Calling className() on Swift class should return demangled name")
  189. }
  190. func testPrimitiveArray() {
  191. let obj = SwiftRLMPrimitiveArrayObject()
  192. let str = "str" as NSString
  193. let data = "str".data(using: .utf8)! as Data as NSData
  194. let date = NSDate()
  195. let str2 = "str2" as NSString
  196. let data2 = "str2".data(using: .utf8)! as Data as NSData
  197. let date2 = NSDate(timeIntervalSince1970: 0)
  198. obj.stringCol.add(str)
  199. XCTAssertEqual(obj.stringCol[0], str)
  200. XCTAssertEqual(obj.stringCol.index(of: str), 0)
  201. XCTAssertEqual(obj.stringCol.index(of: str2), UInt(NSNotFound))
  202. obj.dataCol.add(data)
  203. XCTAssertEqual(obj.dataCol[0], data)
  204. XCTAssertEqual(obj.dataCol.index(of: data), 0)
  205. XCTAssertEqual(obj.dataCol.index(of: data2), UInt(NSNotFound))
  206. obj.dateCol.add(date)
  207. XCTAssertEqual(obj.dateCol[0], date)
  208. XCTAssertEqual(obj.dateCol.index(of: date), 0)
  209. XCTAssertEqual(obj.dateCol.index(of: date2), UInt(NSNotFound))
  210. obj.optStringCol.add(str)
  211. XCTAssertEqual(obj.optStringCol[0], str)
  212. obj.optDataCol.add(data)
  213. XCTAssertEqual(obj.optDataCol[0], data)
  214. obj.optDateCol.add(date)
  215. XCTAssertEqual(obj.optDateCol[0], date)
  216. obj.optStringCol.add(NSNull())
  217. XCTAssertEqual(obj.optStringCol[1], NSNull())
  218. obj.optDataCol.add(NSNull())
  219. XCTAssertEqual(obj.optDataCol[1], NSNull())
  220. obj.optDateCol.add(NSNull())
  221. XCTAssertEqual(obj.optDateCol[1], NSNull())
  222. assertThrowsWithReasonMatching(obj.optDataCol.add(str), ".*")
  223. }
  224. // Objective-C models
  225. // Note: Swift doesn't support custom accessor names
  226. // so we test to make sure models with custom accessors can still be accessed
  227. func testCustomAccessors() {
  228. let realm = realmWithTestPath()
  229. realm.beginWriteTransaction()
  230. let ca = CustomAccessorsObject.create(in: realm, withValue: ["name", 2])
  231. XCTAssertEqual(ca.name!, "name", "name property should be name.")
  232. ca.age = 99
  233. XCTAssertEqual(ca.age, Int32(99), "age property should be 99")
  234. try! realm.commitWriteTransaction()
  235. }
  236. func testClassExtension() {
  237. let realm = realmWithTestPath()
  238. realm.beginWriteTransaction()
  239. let bObject = BaseClassStringObject()
  240. bObject.intCol = 1
  241. bObject.stringCol = "stringVal"
  242. realm.add(bObject)
  243. try! realm.commitWriteTransaction()
  244. let objectFromRealm = BaseClassStringObject.allObjects(in: realm)[0] as! BaseClassStringObject
  245. XCTAssertEqual(objectFromRealm.intCol, Int32(1), "Should be 1")
  246. XCTAssertEqual(objectFromRealm.stringCol!, "stringVal", "Should be stringVal")
  247. }
  248. func testCreateOrUpdate() {
  249. let realm = RLMRealm.default()
  250. realm.beginWriteTransaction()
  251. _ = SwiftRLMPrimaryStringObject.createOrUpdateInDefaultRealm(withValue: ["string", 1])
  252. let objects = SwiftRLMPrimaryStringObject.allObjects()
  253. XCTAssertEqual(objects.count, UInt(1), "Should have 1 object")
  254. XCTAssertEqual((objects[0] as! SwiftRLMPrimaryStringObject).intCol, 1, "Value should be 1")
  255. _ = SwiftRLMPrimaryStringObject.createOrUpdateInDefaultRealm(withValue: ["stringCol": "string2", "intCol": 2])
  256. XCTAssertEqual(objects.count, UInt(2), "Should have 2 objects")
  257. _ = SwiftRLMPrimaryStringObject.createOrUpdateInDefaultRealm(withValue: ["string", 3])
  258. XCTAssertEqual(objects.count, UInt(2), "Should have 2 objects")
  259. XCTAssertEqual((objects[0] as! SwiftRLMPrimaryStringObject).intCol, 3, "Value should be 3")
  260. try! realm.commitWriteTransaction()
  261. }
  262. func testObjectForPrimaryKey() {
  263. let realm = RLMRealm.default()
  264. realm.beginWriteTransaction()
  265. _ = SwiftRLMPrimaryStringObject.createOrUpdateInDefaultRealm(withValue: ["string", 1])
  266. let obj = SwiftRLMPrimaryStringObject.object(forPrimaryKey: "string")
  267. XCTAssertNotNil(obj!)
  268. XCTAssertEqual(obj!.intCol, 1)
  269. realm.cancelWriteTransaction()
  270. }
  271. // if this fails (and you haven't changed the test module name), the checks
  272. // for swift class names and the demangling logic need to be updated
  273. func testNSStringFromClassDemangledTopLevelClassNames() {
  274. #if SWIFT_PACKAGE
  275. XCTAssertEqual(NSStringFromClass(OuterClass.self), "RealmObjcSwiftTests.OuterClass")
  276. #else
  277. XCTAssertEqual(NSStringFromClass(OuterClass.self), "Tests.OuterClass")
  278. #endif
  279. }
  280. // if this fails (and you haven't changed the test module name), the prefix
  281. // check in RLMSchema initialization needs to be updated
  282. func testNestedClassNameMangling() {
  283. #if SWIFT_PACKAGE
  284. XCTAssertEqual(NSStringFromClass(OuterClass.InnerClass.self), "_TtCC19RealmObjcSwiftTests10OuterClass10InnerClass")
  285. #else
  286. XCTAssertEqual(NSStringFromClass(OuterClass.InnerClass.self), "_TtCC5Tests10OuterClass10InnerClass")
  287. #endif
  288. }
  289. }