TestCase.swift 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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 Foundation
  19. import Realm
  20. import Realm.Dynamic
  21. import RealmSwift
  22. import XCTest
  23. func inMemoryRealm(_ inMememoryIdentifier: String) -> Realm {
  24. return try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: inMememoryIdentifier))
  25. }
  26. class TestCase: XCTestCase {
  27. var exceptionThrown = false
  28. var testDir: String! = nil
  29. let queue = DispatchQueue(label: "background")
  30. @discardableResult
  31. func realmWithTestPath(configuration: Realm.Configuration = Realm.Configuration()) -> Realm {
  32. var configuration = configuration
  33. configuration.fileURL = testRealmURL()
  34. return try! Realm(configuration: configuration)
  35. }
  36. override class func setUp() {
  37. super.setUp()
  38. #if DEBUG || arch(i386) || arch(x86_64)
  39. // Disable actually syncing anything to the disk to greatly speed up the
  40. // tests, but only when not running on device because it can't be
  41. // re-enabled and we need it enabled for performance tests
  42. RLMDisableSyncToDisk()
  43. #endif
  44. do {
  45. // Clean up any potentially lingering Realm files from previous runs
  46. try FileManager.default.removeItem(atPath: RLMRealmPathForFile(""))
  47. } catch {
  48. // The directory might not actually already exist, so not an error
  49. }
  50. }
  51. override class func tearDown() {
  52. RLMRealm.resetRealmState()
  53. super.tearDown()
  54. }
  55. override func invokeTest() {
  56. testDir = RLMRealmPathForFile(realmFilePrefix())
  57. do {
  58. try FileManager.default.removeItem(atPath: testDir)
  59. } catch {
  60. // The directory shouldn't actually already exist, so not an error
  61. }
  62. try! FileManager.default.createDirectory(at: URL(fileURLWithPath: testDir, isDirectory: true),
  63. withIntermediateDirectories: true, attributes: nil)
  64. let config = Realm.Configuration(fileURL: defaultRealmURL())
  65. Realm.Configuration.defaultConfiguration = config
  66. exceptionThrown = false
  67. autoreleasepool { super.invokeTest() }
  68. if !exceptionThrown {
  69. XCTAssertFalse(RLMHasCachedRealmForPath(defaultRealmURL().path))
  70. XCTAssertFalse(RLMHasCachedRealmForPath(testRealmURL().path))
  71. }
  72. resetRealmState()
  73. do {
  74. try FileManager.default.removeItem(atPath: testDir)
  75. } catch {
  76. XCTFail("Unable to delete realm files")
  77. }
  78. // Verify that there are no remaining realm files after the test
  79. let parentDir = (testDir as NSString).deletingLastPathComponent
  80. for url in FileManager.default.enumerator(atPath: parentDir)! {
  81. let url = url as! NSString
  82. XCTAssertNotEqual(url.pathExtension, "realm", "Lingering realm file at \(parentDir)/\(url)")
  83. assert(url.pathExtension != "realm")
  84. }
  85. }
  86. func resetRealmState() {
  87. RLMRealm.resetRealmState()
  88. }
  89. func dispatchSyncNewThread(block: @escaping () -> Void) {
  90. queue.async {
  91. autoreleasepool {
  92. block()
  93. }
  94. }
  95. queue.sync { }
  96. }
  97. /// Check whether two test objects are equal (refer to the same row in the same Realm), even if their models
  98. /// don't define a primary key.
  99. func assertEqual<O: Object>(_ o1: O?, _ o2: O?, fileName: StaticString = #file, lineNumber: UInt = #line) {
  100. if o1 == nil && o2 == nil {
  101. return
  102. }
  103. if let o1 = o1, let o2 = o2, o1.isSameObject(as: o2) {
  104. return
  105. }
  106. XCTFail("Objects expected to be equal, but weren't. First: \(String(describing: o1)), "
  107. + "second: \(String(describing: o2))", file: fileName, line: lineNumber)
  108. }
  109. /// Check whether two collections containing Realm objects are equal.
  110. func assertEqual<C: Collection>(_ c1: C, _ c2: C, fileName: StaticString = #file, lineNumber: UInt = #line)
  111. where C.Iterator.Element: Object {
  112. XCTAssertEqual(c1.count, c2.count, "Collection counts were incorrect", file: fileName, line: lineNumber)
  113. for (o1, o2) in zip(c1, c2) {
  114. assertEqual(o1, o2, fileName: fileName, lineNumber: lineNumber)
  115. }
  116. }
  117. func assertEqual<T: Equatable>(_ expected: [T?], _ actual: [T?], file: StaticString = #file, line: UInt = #line) {
  118. if expected.count != actual.count {
  119. XCTFail("assertEqual failed: (\"\(expected)\") is not equal to (\"\(actual)\")",
  120. file: file, line: line)
  121. return
  122. }
  123. XCTAssertEqual(expected.count, actual.count, "Collection counts were incorrect", file: file, line: line)
  124. for (e, a) in zip(expected, actual) where e != a {
  125. XCTFail("assertEqual failed: (\"\(expected)\") is not equal to (\"\(actual)\")",
  126. file: file, line: line)
  127. return
  128. }
  129. }
  130. func assertThrows<T>(_ block: @autoclosure () -> T, named: String? = RLMExceptionName,
  131. _ message: String? = nil, fileName: String = #file, lineNumber: UInt = #line) {
  132. exceptionThrown = true
  133. RLMAssertThrowsWithName(self, { _ = block() }, named, message, fileName, lineNumber)
  134. }
  135. func assertThrows<T>(_ block: @autoclosure () -> T, reason: String,
  136. _ message: String? = nil, fileName: String = #file, lineNumber: UInt = #line) {
  137. exceptionThrown = true
  138. RLMAssertThrowsWithReason(self, { _ = block() }, reason, message, fileName, lineNumber)
  139. }
  140. func assertThrows<T>(_ block: @autoclosure () -> T, reasonMatching regexString: String,
  141. _ message: String? = nil, fileName: String = #file, lineNumber: UInt = #line) {
  142. exceptionThrown = true
  143. RLMAssertThrowsWithReasonMatching(self, { _ = block() }, regexString, message, fileName, lineNumber)
  144. }
  145. func assertSucceeds(message: String? = nil, fileName: StaticString = #file,
  146. lineNumber: UInt = #line, block: () throws -> Void) {
  147. do {
  148. try block()
  149. } catch {
  150. XCTFail("Expected no error, but instead caught <\(error)>.",
  151. file: fileName, line: lineNumber)
  152. }
  153. }
  154. func assertFails<T>(_ expectedError: Realm.Error.Code, _ message: String? = nil,
  155. fileName: StaticString = #file, lineNumber: UInt = #line,
  156. block: () throws -> T) {
  157. do {
  158. _ = try block()
  159. XCTFail("Expected to catch <\(expectedError)>, but no error was thrown.",
  160. file: fileName, line: lineNumber)
  161. } catch let e as Realm.Error where e.code == expectedError {
  162. // Success!
  163. } catch {
  164. XCTFail("Expected to catch <\(expectedError)>, but instead caught <\(error)>.",
  165. file: fileName, line: lineNumber)
  166. }
  167. }
  168. func assertFails<T>(_ expectedError: Error, _ message: String? = nil,
  169. fileName: StaticString = #file, lineNumber: UInt = #line,
  170. block: () throws -> T) {
  171. do {
  172. _ = try block()
  173. XCTFail("Expected to catch <\(expectedError)>, but no error was thrown.",
  174. file: fileName, line: lineNumber)
  175. } catch let e where e._code == expectedError._code {
  176. // Success!
  177. } catch {
  178. XCTFail("Expected to catch <\(expectedError)>, but instead caught <\(error)>.",
  179. file: fileName, line: lineNumber)
  180. }
  181. }
  182. func assertNil<T>(block: @autoclosure() -> T?, _ message: String? = nil,
  183. fileName: StaticString = #file, lineNumber: UInt = #line) {
  184. XCTAssert(block() == nil, message ?? "", file: fileName, line: lineNumber)
  185. }
  186. func assertMatches(_ block: @autoclosure () -> String, _ regexString: String, _ message: String? = nil,
  187. fileName: String = #file, lineNumber: UInt = #line) {
  188. RLMAssertMatches(self, block, regexString, message, fileName, lineNumber)
  189. }
  190. private func realmFilePrefix() -> String {
  191. let name: String? = self.name
  192. return name!.trimmingCharacters(in: CharacterSet(charactersIn: "-[]"))
  193. }
  194. internal func testRealmURL() -> URL {
  195. return realmURLForFile("test.realm")
  196. }
  197. internal func defaultRealmURL() -> URL {
  198. return realmURLForFile("default.realm")
  199. }
  200. private func realmURLForFile(_ fileName: String) -> URL {
  201. let directory = URL(fileURLWithPath: testDir, isDirectory: true)
  202. return directory.appendingPathComponent(fileName, isDirectory: false)
  203. }
  204. }
  205. #if !swift(>=3.2)
  206. func XCTAssertEqual<F: FloatingPoint>(_ expression1: F, _ expression2: F, accuracy: F,
  207. file: StaticString = #file, line: UInt = #line) {
  208. XCTAssertEqualWithAccuracy(expression1, expression2, accuracy: accuracy, file: file, line: line)
  209. }
  210. func XCTAssertNotEqual<F: FloatingPoint>(_ expression1: F, _ expression2: F, accuracy: F,
  211. file: StaticString = #file, line: UInt = #line) {
  212. XCTAssertNotEqualWithAccuracy(expression1, expression2, accuracy, file: file, line: line)
  213. }
  214. #endif