ResultTests.swift 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // Copyright (c) 2015 Rob Rix. All rights reserved.
  2. final class ResultTests: XCTestCase {
  3. func testMapTransformsSuccesses() {
  4. XCTAssertEqual(success.map { $0.characters.count } ?? 0, 7)
  5. }
  6. func testMapRewrapsFailures() {
  7. XCTAssertEqual(failure.map { $0.characters.count } ?? 0, 0)
  8. }
  9. func testInitOptionalSuccess() {
  10. XCTAssert(Result("success" as String?, failWith: error) == success)
  11. }
  12. func testInitOptionalFailure() {
  13. XCTAssert(Result(nil, failWith: error) == failure)
  14. }
  15. // MARK: Errors
  16. func testErrorsIncludeTheSourceFile() {
  17. let file = #file
  18. XCTAssert(Result<(), NSError>.error().file == file)
  19. }
  20. func testErrorsIncludeTheSourceLine() {
  21. let (line, error) = (#line, Result<(), NSError>.error())
  22. XCTAssertEqual(error.line ?? -1, line)
  23. }
  24. func testErrorsIncludeTheCallingFunction() {
  25. let function = #function
  26. XCTAssert(Result<(), NSError>.error().function == function)
  27. }
  28. // MARK: Try - Catch
  29. func testTryCatchProducesSuccesses() {
  30. let result: Result<String, NSError> = Result(try tryIsSuccess("success"))
  31. XCTAssert(result == success)
  32. }
  33. func testTryCatchProducesFailures() {
  34. #if os(Linux)
  35. /// FIXME: skipped on Linux because of crash with swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.
  36. print("Test Case `\(#function)` skipped on Linux because of crash with swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.")
  37. #else
  38. let result: Result<String, NSError> = Result(try tryIsSuccess(nil))
  39. XCTAssert(result.error == error)
  40. #endif
  41. }
  42. func testTryCatchWithFunctionProducesSuccesses() {
  43. let function = { try tryIsSuccess("success") }
  44. let result: Result<String, NSError> = Result(attempt: function)
  45. XCTAssert(result == success)
  46. }
  47. func testTryCatchWithFunctionCatchProducesFailures() {
  48. #if os(Linux)
  49. /// FIXME: skipped on Linux because of crash with swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.
  50. print("Test Case `\(#function)` skipped on Linux because of crash with swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.")
  51. #else
  52. let function = { try tryIsSuccess(nil) }
  53. let result: Result<String, NSError> = Result(attempt: function)
  54. XCTAssert(result.error == error)
  55. #endif
  56. }
  57. func testMaterializeProducesSuccesses() {
  58. let result1 = materialize(try tryIsSuccess("success"))
  59. XCTAssert(result1 == success)
  60. let result2: Result<String, NSError> = materialize { try tryIsSuccess("success") }
  61. XCTAssert(result2 == success)
  62. }
  63. func testMaterializeProducesFailures() {
  64. #if os(Linux)
  65. /// FIXME: skipped on Linux because of crash with swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.
  66. print("Test Case `\(#function)` skipped on Linux because of crash with swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.")
  67. #else
  68. let result1 = materialize(try tryIsSuccess(nil))
  69. XCTAssert(result1.error == error)
  70. let result2: Result<String, NSError> = materialize { try tryIsSuccess(nil) }
  71. XCTAssert(result2.error == error)
  72. #endif
  73. }
  74. // MARK: Recover
  75. func testRecoverProducesLeftForLeftSuccess() {
  76. let left = Result<String, NSError>.Success("left")
  77. XCTAssertEqual(left.recover("right"), "left")
  78. }
  79. func testRecoverProducesRightForLeftFailure() {
  80. struct Error: ResultErrorType {}
  81. let left = Result<String, Error>.Failure(Error())
  82. XCTAssertEqual(left.recover("right"), "right")
  83. }
  84. // MARK: Recover With
  85. func testRecoverWithProducesLeftForLeftSuccess() {
  86. let left = Result<String, NSError>.Success("left")
  87. let right = Result<String, NSError>.Success("right")
  88. XCTAssertEqual(left.recoverWith(right).value, "left")
  89. }
  90. func testRecoverWithProducesRightSuccessForLeftFailureAndRightSuccess() {
  91. struct Error: ResultErrorType {}
  92. let left = Result<String, Error>.Failure(Error())
  93. let right = Result<String, Error>.Success("right")
  94. XCTAssertEqual(left.recoverWith(right).value, "right")
  95. }
  96. func testRecoverWithProducesRightFailureForLeftFailureAndRightFailure() {
  97. enum Error: ResultErrorType { case Left, Right }
  98. let left = Result<String, Error>.Failure(.Left)
  99. let right = Result<String, Error>.Failure(.Right)
  100. XCTAssertEqual(left.recoverWith(right).error, .Right)
  101. }
  102. // MARK: Cocoa API idioms
  103. #if !os(Linux)
  104. func testTryProducesFailuresForBooleanAPIWithErrorReturnedByReference() {
  105. let result = `try` { attempt(true, succeed: false, error: $0) }
  106. XCTAssertFalse(result ?? false)
  107. XCTAssertNotNil(result.error)
  108. }
  109. func testTryProducesFailuresForOptionalWithErrorReturnedByReference() {
  110. let result = `try` { attempt(1, succeed: false, error: $0) }
  111. XCTAssertEqual(result ?? 0, 0)
  112. XCTAssertNotNil(result.error)
  113. }
  114. func testTryProducesSuccessesForBooleanAPI() {
  115. let result = `try` { attempt(true, succeed: true, error: $0) }
  116. XCTAssertTrue(result ?? false)
  117. XCTAssertNil(result.error)
  118. }
  119. func testTryProducesSuccessesForOptionalAPI() {
  120. let result = `try` { attempt(1, succeed: true, error: $0) }
  121. XCTAssertEqual(result ?? 0, 1)
  122. XCTAssertNil(result.error)
  123. }
  124. func testTryMapProducesSuccess() {
  125. let result = success.tryMap(tryIsSuccess)
  126. XCTAssert(result == success)
  127. }
  128. func testTryMapProducesFailure() {
  129. let result = Result<String, NSError>.Success("fail").tryMap(tryIsSuccess)
  130. XCTAssert(result == failure)
  131. }
  132. #endif
  133. // MARK: Operators
  134. func testConjunctionOperator() {
  135. let resultSuccess = success &&& success
  136. if let (x, y) = resultSuccess.value {
  137. XCTAssertTrue(x == "success" && y == "success")
  138. } else {
  139. XCTFail()
  140. }
  141. let resultFailureBoth = failure &&& failure2
  142. XCTAssert(resultFailureBoth.error == error)
  143. let resultFailureLeft = failure &&& success
  144. XCTAssert(resultFailureLeft.error == error)
  145. let resultFailureRight = success &&& failure2
  146. XCTAssert(resultFailureRight.error == error2)
  147. }
  148. }
  149. // MARK: - Fixtures
  150. let success = Result<String, NSError>.Success("success")
  151. let error = NSError(domain: "com.antitypical.Result", code: 1, userInfo: nil)
  152. let error2 = NSError(domain: "com.antitypical.Result", code: 2, userInfo: nil)
  153. let failure = Result<String, NSError>.Failure(error)
  154. let failure2 = Result<String, NSError>.Failure(error2)
  155. // MARK: - Helpers
  156. #if !os(Linux)
  157. #if swift(>=3.0)
  158. func attempt<T>(_ value: T, succeed: Bool, error: NSErrorPointer) -> T? {
  159. if succeed {
  160. return value
  161. } else {
  162. error?.pointee = Result<(), NSError>.error()
  163. return nil
  164. }
  165. }
  166. #else
  167. func attempt<T>(value: T, succeed: Bool, error: NSErrorPointer) -> T? {
  168. if succeed {
  169. return value
  170. } else {
  171. error.memory = Result<(), NSError>.error()
  172. return nil
  173. }
  174. }
  175. #endif
  176. #endif
  177. #if swift(>=3)
  178. func tryIsSuccess(_ text: String?) throws -> String {
  179. guard let text = text where text == "success" else {
  180. throw error
  181. }
  182. return text
  183. }
  184. #else
  185. func tryIsSuccess(text: String?) throws -> String {
  186. guard let text = text where text == "success" else {
  187. throw error
  188. }
  189. return text
  190. }
  191. #endif
  192. extension NSError {
  193. var function: String? {
  194. return userInfo[Result<(), NSError>.functionKey] as? String
  195. }
  196. var file: String? {
  197. return userInfo[Result<(), NSError>.fileKey] as? String
  198. }
  199. var line: Int? {
  200. return userInfo[Result<(), NSError>.lineKey] as? Int
  201. }
  202. }
  203. #if os(Linux)
  204. extension ResultTests {
  205. static var allTests: [(String, (ResultTests) -> () throws -> Void)] {
  206. return [
  207. ("testMapTransformsSuccesses", testMapTransformsSuccesses),
  208. ("testMapRewrapsFailures", testMapRewrapsFailures),
  209. ("testInitOptionalSuccess", testInitOptionalSuccess),
  210. ("testInitOptionalFailure", testInitOptionalFailure),
  211. ("testErrorsIncludeTheSourceFile", testErrorsIncludeTheSourceFile),
  212. ("testErrorsIncludeTheSourceLine", testErrorsIncludeTheSourceLine),
  213. ("testErrorsIncludeTheCallingFunction", testErrorsIncludeTheCallingFunction),
  214. ("testTryCatchProducesSuccesses", testTryCatchProducesSuccesses),
  215. ("testTryCatchProducesFailures", testTryCatchProducesFailures),
  216. ("testTryCatchWithFunctionProducesSuccesses", testTryCatchWithFunctionProducesSuccesses),
  217. ("testTryCatchWithFunctionCatchProducesFailures", testTryCatchWithFunctionCatchProducesFailures),
  218. ("testMaterializeProducesSuccesses", testMaterializeProducesSuccesses),
  219. ("testMaterializeProducesFailures", testMaterializeProducesFailures),
  220. ("testRecoverProducesLeftForLeftSuccess", testRecoverProducesLeftForLeftSuccess),
  221. ("testRecoverProducesRightForLeftFailure", testRecoverProducesRightForLeftFailure),
  222. ("testRecoverWithProducesLeftForLeftSuccess", testRecoverWithProducesLeftForLeftSuccess),
  223. ("testRecoverWithProducesRightSuccessForLeftFailureAndRightSuccess", testRecoverWithProducesRightSuccessForLeftFailureAndRightSuccess),
  224. ("testRecoverWithProducesRightFailureForLeftFailureAndRightFailure", testRecoverWithProducesRightFailureForLeftFailureAndRightFailure),
  225. // ("testTryProducesFailuresForBooleanAPIWithErrorReturnedByReference", testTryProducesFailuresForBooleanAPIWithErrorReturnedByReference),
  226. // ("testTryProducesFailuresForOptionalWithErrorReturnedByReference", testTryProducesFailuresForOptionalWithErrorReturnedByReference),
  227. // ("testTryProducesSuccessesForBooleanAPI", testTryProducesSuccessesForBooleanAPI),
  228. // ("testTryProducesSuccessesForOptionalAPI", testTryProducesSuccessesForOptionalAPI),
  229. // ("testTryMapProducesSuccess", testTryMapProducesSuccess),
  230. // ("testTryMapProducesFailure", testTryMapProducesFailure),
  231. ("testConjunctionOperator", testConjunctionOperator),
  232. ]
  233. }
  234. }
  235. #endif
  236. import Foundation
  237. import Result
  238. import XCTest