DataEncoderTests.swift 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932
  1. // This file is derived from swift/test/stdlib/TestJSONEncoder.swift
  2. // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
  3. // Licensed under Apache License v2.0 with Runtime Library Exception
  4. //
  5. // See https://swift.org/LICENSE.txt for license information
  6. // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  7. //
  8. //===----------------------------------------------------------------------===//
  9. import FirebaseSharedSwift
  10. import Swift
  11. import Foundation
  12. // MARK: - Test Suite
  13. import XCTest
  14. class TestFirebaseDataEncoder: XCTestCase {
  15. // MARK: - Encoding Top-Level Empty Types
  16. func testEncodingTopLevelEmptyStruct() {
  17. let empty = EmptyStruct()
  18. _testRoundTrip(of: empty, expected: _emptyDictionary)
  19. }
  20. func testEncodingTopLevelEmptyClass() {
  21. let empty = EmptyClass()
  22. _testRoundTrip(of: empty, expected: _emptyDictionary)
  23. }
  24. // MARK: - Encoding Top-Level Single-Value Types
  25. func testEncodingTopLevelSingleValueEnum() {
  26. _testRoundTrip(of: Switch.off)
  27. _testRoundTrip(of: Switch.on)
  28. }
  29. func testEncodingTopLevelSingleValueStruct() {
  30. _testRoundTrip(of: Timestamp(3_141_592_653))
  31. }
  32. func testEncodingTopLevelSingleValueClass() {
  33. _testRoundTrip(of: Counter())
  34. }
  35. // MARK: - Encoding Top-Level Structured Types
  36. func testEncodingTopLevelStructuredStruct() {
  37. // Address is a struct type with multiple fields.
  38. let address = Address.testValue
  39. _testRoundTrip(of: address)
  40. }
  41. func testEncodingTopLevelStructuredClass() {
  42. // Person is a class with multiple fields.
  43. let expected = ["name": "Johnny Appleseed", "email": "appleseed@apple.com"]
  44. let person = Person.testValue
  45. _testRoundTrip(of: person, expected: expected)
  46. }
  47. func testEncodingTopLevelStructuredSingleStruct() {
  48. // Numbers is a struct which encodes as an array through a single value container.
  49. let numbers = Numbers.testValue
  50. _testRoundTrip(of: numbers)
  51. }
  52. func testEncodingTopLevelStructuredSingleClass() {
  53. // Mapping is a class which encodes as a dictionary through a single value container.
  54. let mapping = Mapping.testValue
  55. _testRoundTrip(of: mapping)
  56. }
  57. func testEncodingTopLevelDeepStructuredType() {
  58. // Company is a type with fields which are Codable themselves.
  59. let company = Company.testValue
  60. _testRoundTrip(of: company)
  61. }
  62. func testEncodingClassWhichSharesEncoderWithSuper() {
  63. // Employee is a type which shares its encoder & decoder with its superclass, Person.
  64. let employee = Employee.testValue
  65. _testRoundTrip(of: employee)
  66. }
  67. func testEncodingTopLevelNullableType() {
  68. // EnhancedBool is a type which encodes either as a Bool or as nil.
  69. _testRoundTrip(of: EnhancedBool.true, expected: true)
  70. _testRoundTrip(of: EnhancedBool.false, expected: false)
  71. _testRoundTrip(of: EnhancedBool.fileNotFound, expected: NSNull())
  72. }
  73. func testEncodingMultipleNestedContainersWithTheSameTopLevelKey() {
  74. struct Model: Codable, Equatable {
  75. let first: String
  76. let second: String
  77. init(from coder: Decoder) throws {
  78. let container = try coder.container(keyedBy: TopLevelCodingKeys.self)
  79. let firstNestedContainer = try container.nestedContainer(
  80. keyedBy: FirstNestedCodingKeys.self,
  81. forKey: .top
  82. )
  83. first = try firstNestedContainer.decode(String.self, forKey: .first)
  84. let secondNestedContainer = try container.nestedContainer(
  85. keyedBy: SecondNestedCodingKeys.self,
  86. forKey: .top
  87. )
  88. second = try secondNestedContainer.decode(String.self, forKey: .second)
  89. }
  90. func encode(to encoder: Encoder) throws {
  91. var container = encoder.container(keyedBy: TopLevelCodingKeys.self)
  92. var firstNestedContainer = container.nestedContainer(
  93. keyedBy: FirstNestedCodingKeys.self,
  94. forKey: .top
  95. )
  96. try firstNestedContainer.encode(first, forKey: .first)
  97. var secondNestedContainer = container.nestedContainer(
  98. keyedBy: SecondNestedCodingKeys.self,
  99. forKey: .top
  100. )
  101. try secondNestedContainer.encode(second, forKey: .second)
  102. }
  103. init(first: String, second: String) {
  104. self.first = first
  105. self.second = second
  106. }
  107. static var testValue: Model {
  108. return Model(first: "Johnny Appleseed",
  109. second: "appleseed@apple.com")
  110. }
  111. enum TopLevelCodingKeys: String, CodingKey {
  112. case top
  113. }
  114. enum FirstNestedCodingKeys: String, CodingKey {
  115. case first
  116. }
  117. enum SecondNestedCodingKeys: String, CodingKey {
  118. case second
  119. }
  120. }
  121. let model = Model.testValue
  122. if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
  123. let expected = ["top": ["first": "Johnny Appleseed", "second": "appleseed@apple.com"]]
  124. _testRoundTrip(of: model, expected: expected)
  125. } else {
  126. _testRoundTrip(of: model)
  127. }
  128. }
  129. // NOTE: This test causes a precondition error, so I am uncertain about how it ought to be tested.
  130. // func testEncodingConflictedTypeNestedContainersWithTheSameTopLevelKey() {
  131. // struct Model : Encodable, Equatable {
  132. // let first: String
  133. //
  134. // func encode(to encoder: Encoder) throws {
  135. // var container = encoder.container(keyedBy: TopLevelCodingKeys.self)
  136. //
  137. // var firstNestedContainer = container.nestedContainer(keyedBy: FirstNestedCodingKeys.self, forKey: .top)
  138. // try firstNestedContainer.encode(self.first, forKey: .first)
  139. //
  140. // // The following line would fail as it attempts to re-encode into already encoded container is invalid. This will always fail
  141. // var secondNestedContainer = container.nestedUnkeyedContainer(forKey: .top)
  142. // try secondNestedContainer.encode("second")
  143. // }
  144. //
  145. // init(first: String) {
  146. // self.first = first
  147. // }
  148. //
  149. // static var testValue: Model {
  150. // return Model(first: "Johnny Appleseed")
  151. // }
  152. //
  153. // enum TopLevelCodingKeys : String, CodingKey {
  154. // case top
  155. // }
  156. // enum FirstNestedCodingKeys : String, CodingKey {
  157. // case first
  158. // }
  159. // }
  160. //
  161. // let model = Model.testValue
  162. // // This following test would fail as it attempts to re-encode into already encoded container is invalid. This will always fail
  163. // if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
  164. // _testEncodeFailure(of: model)
  165. // } else {
  166. // _testEncodeFailure(of: model)
  167. // }
  168. // }
  169. // MARK: - Date Strategy Tests
  170. // Disabled for now till we resolve rdar://52618414
  171. func x_testEncodingDate() {
  172. func formattedLength(of value: Double) -> Int {
  173. let empty = UnsafeMutablePointer<Int8>.allocate(capacity: 0)
  174. defer { empty.deallocate() }
  175. let length = snprintf(ptr: empty, 0, "%0.*g", DBL_DECIMAL_DIG, value)
  176. return Int(length)
  177. }
  178. // Duplicated to handle a special case
  179. func localTestRoundTrip<T: Codable & Equatable>(of value: T) {
  180. var payload: Any! = nil
  181. do {
  182. let encoder = FirebaseDataEncoder()
  183. payload = try encoder.encode(value)
  184. } catch {
  185. XCTFail("Failed to encode \(T.self): \(error)")
  186. }
  187. do {
  188. let decoder = FirebaseDataDecoder()
  189. let decoded = try decoder.decode(T.self, from: payload!)
  190. /// `snprintf`'s `%g`, which `JSONSerialization` uses internally for double values, does not respect
  191. /// our precision requests in every case. This bug effects Darwin, FreeBSD, and Linux currently
  192. /// causing this test (which uses the current time) to fail occasionally.
  193. if formattedLength(of: (decoded as! Date).timeIntervalSinceReferenceDate) >
  194. DBL_DECIMAL_DIG +
  195. 2 {
  196. let adjustedTimeIntervalSinceReferenceDate: (Date) -> Double = { date in
  197. let adjustment = pow(10, Double(DBL_DECIMAL_DIG))
  198. return Double(floor(adjustment * date.timeIntervalSinceReferenceDate)
  199. .rounded() / adjustment)
  200. }
  201. let decodedAprox = adjustedTimeIntervalSinceReferenceDate(decoded as! Date)
  202. let valueAprox = adjustedTimeIntervalSinceReferenceDate(value as! Date)
  203. XCTAssertEqual(
  204. decodedAprox,
  205. valueAprox,
  206. "\(T.self) did not round-trip to an equal value after DBL_DECIMAL_DIG adjustment \(decodedAprox) != \(valueAprox)."
  207. )
  208. return
  209. }
  210. XCTAssertEqual(
  211. decoded,
  212. value,
  213. "\(T.self) did not round-trip to an equal value. \((decoded as! Date).timeIntervalSinceReferenceDate) != \((value as! Date).timeIntervalSinceReferenceDate)"
  214. )
  215. } catch {
  216. XCTFail("Failed to decode \(T.self): \(error)")
  217. }
  218. }
  219. // Test the above `snprintf` edge case evaluation with a known triggering case
  220. let knownBadDate = Date(timeIntervalSinceReferenceDate: 0.0021413276231263384)
  221. localTestRoundTrip(of: knownBadDate)
  222. localTestRoundTrip(of: Date())
  223. // Optional dates should encode the same way.
  224. localTestRoundTrip(of: Optional(Date()))
  225. }
  226. func testEncodingDateSecondsSince1970() {
  227. // Cannot encode an arbitrary number of seconds since we've lost precision since 1970.
  228. let seconds = 1000.0
  229. let expected = 1000
  230. _testRoundTrip(of: Date(timeIntervalSince1970: seconds),
  231. expected: expected,
  232. dateEncodingStrategy: .secondsSince1970,
  233. dateDecodingStrategy: .secondsSince1970)
  234. // Optional dates should encode the same way.
  235. _testRoundTrip(of: Optional(Date(timeIntervalSince1970: seconds)),
  236. expected: expected,
  237. dateEncodingStrategy: .secondsSince1970,
  238. dateDecodingStrategy: .secondsSince1970)
  239. }
  240. func testEncodingDateMillisecondsSince1970() {
  241. // Cannot encode an arbitrary number of seconds since we've lost precision since 1970.
  242. let seconds = 1000.0
  243. let expected = 1_000_000
  244. _testRoundTrip(of: Date(timeIntervalSince1970: seconds),
  245. expected: expected,
  246. dateEncodingStrategy: .millisecondsSince1970,
  247. dateDecodingStrategy: .millisecondsSince1970)
  248. // Optional dates should encode the same way.
  249. _testRoundTrip(of: Optional(Date(timeIntervalSince1970: seconds)),
  250. expected: expected,
  251. dateEncodingStrategy: .millisecondsSince1970,
  252. dateDecodingStrategy: .millisecondsSince1970)
  253. }
  254. func testEncodingDateISO8601() {
  255. if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
  256. let formatter = ISO8601DateFormatter()
  257. formatter.formatOptions = .withInternetDateTime
  258. let timestamp = Date(timeIntervalSince1970: 1000)
  259. let expected = "\(formatter.string(from: timestamp))"
  260. _testRoundTrip(of: timestamp,
  261. expected: expected,
  262. dateEncodingStrategy: .iso8601,
  263. dateDecodingStrategy: .iso8601)
  264. // Optional dates should encode the same way.
  265. _testRoundTrip(of: Optional(timestamp),
  266. expected: expected,
  267. dateEncodingStrategy: .iso8601,
  268. dateDecodingStrategy: .iso8601)
  269. }
  270. }
  271. func testEncodingDateFormatted() {
  272. let formatter = DateFormatter()
  273. formatter.dateStyle = .full
  274. formatter.timeStyle = .full
  275. let timestamp = Date(timeIntervalSince1970: 1000)
  276. let expected = "\(formatter.string(from: timestamp))"
  277. _testRoundTrip(of: timestamp,
  278. expected: expected,
  279. dateEncodingStrategy: .formatted(formatter),
  280. dateDecodingStrategy: .formatted(formatter))
  281. // Optional dates should encode the same way.
  282. _testRoundTrip(of: Optional(timestamp),
  283. expected: expected,
  284. dateEncodingStrategy: .formatted(formatter),
  285. dateDecodingStrategy: .formatted(formatter))
  286. }
  287. func testEncodingDateCustom() {
  288. let timestamp = Date()
  289. // We'll encode a number instead of a date.
  290. let encode = { (_ data: Date, _ encoder: Encoder) throws -> Void in
  291. var container = encoder.singleValueContainer()
  292. try container.encode(42)
  293. }
  294. let decode = { (_: Decoder) throws -> Date in timestamp }
  295. let expected = 42
  296. _testRoundTrip(of: timestamp,
  297. expected: expected,
  298. dateEncodingStrategy: .custom(encode),
  299. dateDecodingStrategy: .custom(decode))
  300. // Optional dates should encode the same way.
  301. _testRoundTrip(of: Optional(timestamp),
  302. expected: expected,
  303. dateEncodingStrategy: .custom(encode),
  304. dateDecodingStrategy: .custom(decode))
  305. }
  306. func testEncodingDateCustomEmpty() {
  307. let timestamp = Date()
  308. // Encoding nothing should encode an empty keyed container ({}).
  309. let encode = { (_: Date, _: Encoder) throws -> Void in }
  310. let decode = { (_: Decoder) throws -> Date in timestamp }
  311. let expected: [String: String] = [:]
  312. _testRoundTrip(of: timestamp,
  313. expected: expected,
  314. dateEncodingStrategy: .custom(encode),
  315. dateDecodingStrategy: .custom(decode))
  316. // Optional dates should encode the same way.
  317. _testRoundTrip(of: Optional(timestamp),
  318. expected: expected,
  319. dateEncodingStrategy: .custom(encode),
  320. dateDecodingStrategy: .custom(decode))
  321. }
  322. // MARK: - Data Strategy Tests
  323. func testEncodingData() {
  324. let data = Data([0xDE, 0xAD, 0xBE, 0xEF])
  325. let expected = [222, 173, 190, 239]
  326. _testRoundTrip(of: data,
  327. expected: expected,
  328. dataEncodingStrategy: .deferredToData,
  329. dataDecodingStrategy: .deferredToData)
  330. // Optional data should encode the same way.
  331. _testRoundTrip(of: Optional(data),
  332. expected: expected,
  333. dataEncodingStrategy: .deferredToData,
  334. dataDecodingStrategy: .deferredToData)
  335. }
  336. func testEncodingDataBase64() {
  337. let data = Data([0xDE, 0xAD, 0xBE, 0xEF])
  338. let expected = "3q2+7w=="
  339. _testRoundTrip(of: data, expected: expected)
  340. // Optional data should encode the same way.
  341. _testRoundTrip(of: Optional(data), expected: expected)
  342. }
  343. func testEncodingDataBlob() {
  344. let data = Data([0xDE, 0xAD, 0xBE, 0xEF])
  345. _testRoundTrip(of: data,
  346. expected: data,
  347. dataEncodingStrategy: .blob,
  348. dataDecodingStrategy: .blob)
  349. // Optional data should encode the same way.
  350. _testRoundTrip(of: Optional(data),
  351. expected: data,
  352. dataEncodingStrategy: .blob,
  353. dataDecodingStrategy: .blob)
  354. }
  355. func testEncodingData2Blob() {
  356. let string = "abcdef"
  357. let data = string.data(using: .utf8)!
  358. _testRoundTrip(of: data,
  359. expected: data,
  360. dataEncodingStrategy: .blob,
  361. dataDecodingStrategy: .blob)
  362. // Optional data should encode the same way.
  363. _testRoundTrip(of: Optional(data),
  364. expected: data,
  365. dataEncodingStrategy: .blob,
  366. dataDecodingStrategy: .blob)
  367. }
  368. func testEncodingDataCustom() {
  369. // We'll encode a number instead of data.
  370. let encode = { (_ data: Data, _ encoder: Encoder) throws -> Void in
  371. var container = encoder.singleValueContainer()
  372. try container.encode(42)
  373. }
  374. let decode = { (_: Decoder) throws -> Data in Data() }
  375. let expected = 42
  376. _testRoundTrip(of: Data(),
  377. expected: expected,
  378. dataEncodingStrategy: .custom(encode),
  379. dataDecodingStrategy: .custom(decode))
  380. // Optional data should encode the same way.
  381. _testRoundTrip(of: Optional(Data()),
  382. expected: expected,
  383. dataEncodingStrategy: .custom(encode),
  384. dataDecodingStrategy: .custom(decode))
  385. }
  386. func testEncodingDataCustomEmpty() {
  387. // Encoding nothing should encode an empty keyed container ({}).
  388. let encode = { (_: Data, _: Encoder) throws -> Void in }
  389. let decode = { (_: Decoder) throws -> Data in Data() }
  390. _testRoundTrip(of: Data(),
  391. expected: [:] as [String: String],
  392. dataEncodingStrategy: .custom(encode),
  393. dataDecodingStrategy: .custom(decode))
  394. // Optional Data should encode the same way.
  395. _testRoundTrip(of: Optional(Data()),
  396. expected: [:] as [String: String],
  397. dataEncodingStrategy: .custom(encode),
  398. dataDecodingStrategy: .custom(decode))
  399. }
  400. // Tests implicit migration of data that was written with .base64 (String type) using Firestore
  401. // 10.0 through 10.3 (see PR #10604).
  402. func testDecodingBase64StringAsBlobData() throws {
  403. let inputString = "abcdef"
  404. let data = inputString.data(using: .utf8)!
  405. let base64String = "YWJjZGVm"
  406. let encoder = FirebaseDataEncoder()
  407. encoder.dataEncodingStrategy = .base64
  408. let payload = try encoder.encode(data)
  409. XCTAssertEqual(
  410. base64String,
  411. try XCTUnwrap(payload as? String, "Encoding did not produce a \(String.self)."),
  412. "Encoding \"\(inputString)\" did not produce expected the base64 string \"\(base64String)\"."
  413. )
  414. let decoder = FirebaseDataDecoder()
  415. decoder.dataDecodingStrategy = .blob
  416. let decoded = try decoder.decode(Data.self, from: payload)
  417. XCTAssertEqual(
  418. inputString,
  419. try XCTUnwrap(String(data: decoded, encoding: .utf8)),
  420. "Decoding base64-encoded payload did not produce original value \"\(inputString)\"."
  421. )
  422. }
  423. // MARK: - Non-Conforming Floating Point Strategy Tests
  424. func testEncodingNonConformingFloats() {
  425. _testEncodeFailure(of: Float.infinity)
  426. _testEncodeFailure(of: Float.infinity)
  427. _testEncodeFailure(of: -Float.infinity)
  428. _testEncodeFailure(of: Float.nan)
  429. _testEncodeFailure(of: Double.infinity)
  430. _testEncodeFailure(of: -Double.infinity)
  431. _testEncodeFailure(of: Double.nan)
  432. // Optional Floats/Doubles should encode the same way.
  433. _testEncodeFailure(of: Float.infinity)
  434. _testEncodeFailure(of: -Float.infinity)
  435. _testEncodeFailure(of: Float.nan)
  436. _testEncodeFailure(of: Double.infinity)
  437. _testEncodeFailure(of: -Double.infinity)
  438. _testEncodeFailure(of: Double.nan)
  439. }
  440. func testEncodingNonConformingFloatStrings() {
  441. let encodingStrategy: FirebaseDataEncoder.NonConformingFloatEncodingStrategy = .convertToString(
  442. positiveInfinity: "INF",
  443. negativeInfinity: "-INF",
  444. nan: "NaN"
  445. )
  446. let decodingStrategy: FirebaseDataDecoder.NonConformingFloatDecodingStrategy = .convertFromString(
  447. positiveInfinity: "INF",
  448. negativeInfinity: "-INF",
  449. nan: "NaN"
  450. )
  451. _testRoundTrip(of: Float.infinity,
  452. expected: "INF",
  453. nonConformingFloatEncodingStrategy: encodingStrategy,
  454. nonConformingFloatDecodingStrategy: decodingStrategy)
  455. _testRoundTrip(of: -Float.infinity,
  456. expected: "-INF",
  457. nonConformingFloatEncodingStrategy: encodingStrategy,
  458. nonConformingFloatDecodingStrategy: decodingStrategy)
  459. // Since Float.nan != Float.nan, we have to use a placeholder that'll encode NaN but actually round-trip.
  460. _testRoundTrip(of: FloatNaNPlaceholder(),
  461. expected: "NaN",
  462. nonConformingFloatEncodingStrategy: encodingStrategy,
  463. nonConformingFloatDecodingStrategy: decodingStrategy)
  464. _testRoundTrip(of: Double.infinity,
  465. expected: "INF",
  466. nonConformingFloatEncodingStrategy: encodingStrategy,
  467. nonConformingFloatDecodingStrategy: decodingStrategy)
  468. _testRoundTrip(of: -Double.infinity,
  469. expected: "-INF",
  470. nonConformingFloatEncodingStrategy: encodingStrategy,
  471. nonConformingFloatDecodingStrategy: decodingStrategy)
  472. // Since Double.nan != Double.nan, we have to use a placeholder that'll encode NaN but actually round-trip.
  473. _testRoundTrip(of: DoubleNaNPlaceholder(),
  474. expected: "NaN",
  475. nonConformingFloatEncodingStrategy: encodingStrategy,
  476. nonConformingFloatDecodingStrategy: decodingStrategy)
  477. // Optional Floats and Doubles should encode the same way.
  478. _testRoundTrip(of: Optional(Float.infinity),
  479. expected: "INF",
  480. nonConformingFloatEncodingStrategy: encodingStrategy,
  481. nonConformingFloatDecodingStrategy: decodingStrategy)
  482. _testRoundTrip(of: Optional(-Float.infinity),
  483. expected: "-INF",
  484. nonConformingFloatEncodingStrategy: encodingStrategy,
  485. nonConformingFloatDecodingStrategy: decodingStrategy)
  486. _testRoundTrip(of: Optional(Double.infinity),
  487. expected: "INF",
  488. nonConformingFloatEncodingStrategy: encodingStrategy,
  489. nonConformingFloatDecodingStrategy: decodingStrategy)
  490. _testRoundTrip(of: Optional(-Double.infinity),
  491. expected: "-INF",
  492. nonConformingFloatEncodingStrategy: encodingStrategy,
  493. nonConformingFloatDecodingStrategy: decodingStrategy)
  494. }
  495. // MARK: - Key Strategy Tests
  496. private struct EncodeMe: Encodable {
  497. var keyName: String
  498. func encode(to coder: Encoder) throws {
  499. var c = coder.container(keyedBy: _TestKey.self)
  500. try c.encode("test", forKey: _TestKey(stringValue: keyName)!)
  501. }
  502. }
  503. func testEncodingKeyStrategySnake() {
  504. let toSnakeCaseTests = [
  505. ("simpleOneTwo", "simple_one_two"),
  506. ("myURL", "my_url"),
  507. ("singleCharacterAtEndX", "single_character_at_end_x"),
  508. ("thisIsAnXMLProperty", "this_is_an_xml_property"),
  509. ("single", "single"), // no underscore
  510. ("", ""), // don't die on empty string
  511. ("a", "a"), // single character
  512. ("aA", "a_a"), // two characters
  513. ("version4Thing", "version4_thing"), // numerics
  514. ("partCAPS", "part_caps"), // only insert underscore before first all caps
  515. ("partCAPSLowerAGAIN", "part_caps_lower_again"), // switch back and forth caps.
  516. ("manyWordsInThisThing", "many_words_in_this_thing"), // simple lowercase + underscore + more
  517. ("asdfĆqer", "asdf_ćqer"),
  518. ("already_snake_case", "already_snake_case"),
  519. ("dataPoint22", "data_point22"),
  520. ("dataPoint22Word", "data_point22_word"),
  521. ("_oneTwoThree", "_one_two_three"),
  522. ("oneTwoThree_", "one_two_three_"),
  523. ("__oneTwoThree", "__one_two_three"),
  524. ("oneTwoThree__", "one_two_three__"),
  525. ("_oneTwoThree_", "_one_two_three_"),
  526. ("__oneTwoThree", "__one_two_three"),
  527. ("__oneTwoThree__", "__one_two_three__"),
  528. ("_test", "_test"),
  529. ("_test_", "_test_"),
  530. ("__test", "__test"),
  531. ("test__", "test__"),
  532. ("m͉̟̹y̦̳G͍͚͎̳r̤͉̤͕ͅea̲͕t͇̥̼͖U͇̝̠R͙̻̥͓̣L̥̖͎͓̪̫ͅR̩͖̩eq͈͓u̞e̱s̙t̤̺ͅ", "m͉̟̹y̦̳_g͍͚͎̳r̤͉̤͕ͅea̲͕t͇̥̼͖_u͇̝̠r͙̻̥͓̣l̥̖͎͓̪̫ͅ_r̩͖̩eq͈͓u̞e̱s̙t̤̺ͅ"), // because Itai wanted to test this
  533. ("🐧🐟", "🐧🐟"), // fishy emoji example?
  534. ]
  535. for test in toSnakeCaseTests {
  536. let expected = ["\(test.1)": "test"]
  537. let encoded = EncodeMe(keyName: test.0)
  538. let encoder = FirebaseDataEncoder()
  539. encoder.keyEncodingStrategy = .convertToSnakeCase
  540. let result = try! encoder.encode(encoded)
  541. XCTAssertEqual(expected, result as? [String: String])
  542. }
  543. }
  544. func testEncodingKeyStrategyCustom() {
  545. let expected = ["QQQhello": "test"]
  546. let encoded = EncodeMe(keyName: "hello")
  547. let encoder = FirebaseDataEncoder()
  548. let customKeyConversion = { (_ path: [CodingKey]) -> CodingKey in
  549. let key = _TestKey(stringValue: "QQQ" + path.last!.stringValue)!
  550. return key
  551. }
  552. encoder.keyEncodingStrategy = .custom(customKeyConversion)
  553. let result = try! encoder.encode(encoded)
  554. XCTAssertEqual(expected, result as? [String: String])
  555. }
  556. func testEncodingDictionaryStringKeyConversionUntouched() {
  557. let toEncode = ["leaveMeAlone": "test"]
  558. let encoder = FirebaseDataEncoder()
  559. encoder.keyEncodingStrategy = .convertToSnakeCase
  560. let result = try! encoder.encode(toEncode)
  561. XCTAssertEqual(toEncode, result as? [String: String])
  562. }
  563. private struct EncodeFailure: Encodable {
  564. var someValue: Double
  565. }
  566. private struct EncodeFailureNested: Encodable {
  567. var nestedValue: EncodeFailure
  568. }
  569. func testEncodingDictionaryFailureKeyPath() {
  570. let toEncode: [String: EncodeFailure] = ["key": EncodeFailure(someValue: Double.nan)]
  571. let encoder = FirebaseDataEncoder()
  572. encoder.keyEncodingStrategy = .convertToSnakeCase
  573. do {
  574. _ = try encoder.encode(toEncode)
  575. } catch let EncodingError.invalidValue(_, context) {
  576. XCTAssertEqual(2, context.codingPath.count)
  577. XCTAssertEqual("key", context.codingPath[0].stringValue)
  578. XCTAssertEqual("someValue", context.codingPath[1].stringValue)
  579. } catch {
  580. XCTFail("Unexpected error: \(String(describing: error))")
  581. }
  582. }
  583. func testEncodingDictionaryFailureKeyPathNested() {
  584. let toEncode: [String: [String: EncodeFailureNested]] =
  585. ["key": ["sub_key": EncodeFailureNested(nestedValue: EncodeFailure(someValue: Double.nan))]]
  586. let encoder = FirebaseDataEncoder()
  587. encoder.keyEncodingStrategy = .convertToSnakeCase
  588. do {
  589. _ = try encoder.encode(toEncode)
  590. } catch let EncodingError.invalidValue(_, context) {
  591. XCTAssertEqual(4, context.codingPath.count)
  592. XCTAssertEqual("key", context.codingPath[0].stringValue)
  593. XCTAssertEqual("sub_key", context.codingPath[1].stringValue)
  594. XCTAssertEqual("nestedValue", context.codingPath[2].stringValue)
  595. XCTAssertEqual("someValue", context.codingPath[3].stringValue)
  596. } catch {
  597. XCTFail("Unexpected error: \(String(describing: error))")
  598. }
  599. }
  600. private struct EncodeNested: Encodable {
  601. let nestedValue: EncodeMe
  602. }
  603. private struct EncodeNestedNested: Encodable {
  604. let outerValue: EncodeNested
  605. }
  606. func testEncodingKeyStrategyPath() {
  607. // Make sure a more complex path shows up the way we want
  608. // Make sure the path reflects keys in the Swift, not the resulting ones in the structure
  609. let expected = ["QQQouterValue": ["QQQnestedValue": ["QQQhelloWorld": "test"]]]
  610. let encoded =
  611. EncodeNestedNested(outerValue: EncodeNested(nestedValue: EncodeMe(keyName: "helloWorld")))
  612. let encoder = FirebaseDataEncoder()
  613. var callCount = 0
  614. let customKeyConversion = { (_ path: [CodingKey]) -> CodingKey in
  615. // This should be called three times:
  616. // 1. to convert 'outerValue' to something
  617. // 2. to convert 'nestedValue' to something
  618. // 3. to convert 'helloWorld' to something
  619. callCount = callCount + 1
  620. if path.count == 0 {
  621. XCTFail("The path should always have at least one entry")
  622. } else if path.count == 1 {
  623. XCTAssertEqual(["outerValue"], path.map { $0.stringValue })
  624. } else if path.count == 2 {
  625. XCTAssertEqual(["outerValue", "nestedValue"], path.map { $0.stringValue })
  626. } else if path.count == 3 {
  627. XCTAssertEqual(["outerValue", "nestedValue", "helloWorld"], path.map { $0.stringValue })
  628. } else {
  629. XCTFail("The path mysteriously had more entries")
  630. }
  631. let key = _TestKey(stringValue: "QQQ" + path.last!.stringValue)!
  632. return key
  633. }
  634. encoder.keyEncodingStrategy = .custom(customKeyConversion)
  635. let result = try! encoder.encode(encoded)
  636. XCTAssertEqual(expected, result as? [String: [String: [String: String]]])
  637. XCTAssertEqual(3, callCount)
  638. }
  639. private struct DecodeMe: Decodable {
  640. let found: Bool
  641. init(from coder: Decoder) throws {
  642. let c = try coder.container(keyedBy: _TestKey.self)
  643. // Get the key that we expect to be passed in (camel case)
  644. let camelCaseKey = try c.decode(String.self, forKey: _TestKey(stringValue: "camelCaseKey")!)
  645. // Use the camel case key to decode from the structure. The decoder should convert it to snake case to find it.
  646. found = try c.decode(Bool.self, forKey: _TestKey(stringValue: camelCaseKey)!)
  647. }
  648. }
  649. func testDecodingKeyStrategyCamel() {
  650. let fromSnakeCaseTests = [
  651. ("", ""), // don't die on empty string
  652. ("a", "a"), // single character
  653. ("ALLCAPS", "ALLCAPS"), // If no underscores, we leave the word as-is
  654. ("ALL_CAPS", "allCaps"), // Conversion from screaming snake case
  655. ("single", "single"), // do not capitalize anything with no underscore
  656. ("snake_case", "snakeCase"), // capitalize a character
  657. ("one_two_three", "oneTwoThree"), // more than one word
  658. ("one_2_three", "one2Three"), // numerics
  659. ("one2_three", "one2Three"), // numerics, part 2
  660. ("snake_Ćase", "snakeĆase"), // do not further modify a capitalized diacritic
  661. ("snake_ćase", "snakeĆase"), // capitalize a diacritic
  662. ("alreadyCamelCase", "alreadyCamelCase"), // do not modify already camel case
  663. ("__this_and_that", "__thisAndThat"),
  664. ("_this_and_that", "_thisAndThat"),
  665. ("this__and__that", "thisAndThat"),
  666. ("this_and_that__", "thisAndThat__"),
  667. ("this_aNd_that", "thisAndThat"),
  668. ("_one_two_three", "_oneTwoThree"),
  669. ("one_two_three_", "oneTwoThree_"),
  670. ("__one_two_three", "__oneTwoThree"),
  671. ("one_two_three__", "oneTwoThree__"),
  672. ("_one_two_three_", "_oneTwoThree_"),
  673. ("__one_two_three", "__oneTwoThree"),
  674. ("__one_two_three__", "__oneTwoThree__"),
  675. ("_test", "_test"),
  676. ("_test_", "_test_"),
  677. ("__test", "__test"),
  678. ("test__", "test__"),
  679. ("_", "_"),
  680. ("__", "__"),
  681. ("___", "___"),
  682. ("m͉̟̹y̦̳G͍͚͎̳r̤͉̤͕ͅea̲͕t͇̥̼͖U͇̝̠R͙̻̥͓̣L̥̖͎͓̪̫ͅR̩͖̩eq͈͓u̞e̱s̙t̤̺ͅ", "m͉̟̹y̦̳G͍͚͎̳r̤͉̤͕ͅea̲͕t͇̥̼͖U͇̝̠R͙̻̥͓̣L̥̖͎͓̪̫ͅR̩͖̩eq͈͓u̞e̱s̙t̤̺ͅ"), // because Itai wanted to test this
  683. ("🐧_🐟", "🐧🐟"), // fishy emoji example?
  684. ]
  685. for test in fromSnakeCaseTests {
  686. // This structure contains the camel case key that the test object should decode with, then it uses the snake case key (test.0) as the actual key for the boolean value.
  687. let input = ["camelCaseKey": "\(test.1)", "\(test.0)": true] as [String: Any]
  688. let decoder = FirebaseDataDecoder()
  689. decoder.keyDecodingStrategy = .convertFromSnakeCase
  690. let result = try! decoder.decode(DecodeMe.self, from: input)
  691. XCTAssertTrue(result.found)
  692. }
  693. }
  694. private struct DecodeMe2: Decodable { var hello: String }
  695. func testDecodingKeyStrategyCustom() {
  696. let input = ["----hello": "test"]
  697. let decoder = FirebaseDataDecoder()
  698. let customKeyConversion = { (_ path: [CodingKey]) -> CodingKey in
  699. // This converter removes the first 4 characters from the start of all string keys, if it has more than 4 characters
  700. let string = path.last!.stringValue
  701. guard string.count > 4 else { return path.last! }
  702. let newString = String(string.dropFirst(4))
  703. return _TestKey(stringValue: newString)!
  704. }
  705. decoder.keyDecodingStrategy = .custom(customKeyConversion)
  706. let result = try! decoder.decode(DecodeMe2.self, from: input)
  707. XCTAssertEqual("test", result.hello)
  708. }
  709. func testDecodingDictionaryStringKeyConversionUntouched() {
  710. let input = ["leave_me_alone": "test"]
  711. let decoder = FirebaseDataDecoder()
  712. decoder.keyDecodingStrategy = .convertFromSnakeCase
  713. let result = try! decoder.decode([String: String].self, from: input)
  714. XCTAssertEqual(["leave_me_alone": "test"], result)
  715. }
  716. func testDecodingDictionaryFailureKeyPath() {
  717. let input = ["leave_me_alone": "test"]
  718. let decoder = FirebaseDataDecoder()
  719. decoder.keyDecodingStrategy = .convertFromSnakeCase
  720. do {
  721. _ = try decoder.decode([String: Int].self, from: input)
  722. } catch let DecodingError.typeMismatch(_, context) {
  723. XCTAssertEqual(1, context.codingPath.count)
  724. XCTAssertEqual("leave_me_alone", context.codingPath[0].stringValue)
  725. } catch {
  726. XCTFail("Unexpected error: \(String(describing: error))")
  727. }
  728. }
  729. private struct DecodeFailure: Decodable {
  730. var intValue: Int
  731. }
  732. private struct DecodeFailureNested: Decodable {
  733. var nestedValue: DecodeFailure
  734. }
  735. func testDecodingDictionaryFailureKeyPathNested() {
  736. let input = ["top_level": ["sub_level": ["nested_value": ["int_value": "not_an_int"]]]]
  737. let decoder = FirebaseDataDecoder()
  738. decoder.keyDecodingStrategy = .convertFromSnakeCase
  739. do {
  740. _ = try decoder.decode([String: [String: DecodeFailureNested]].self, from: input)
  741. } catch let DecodingError.typeMismatch(_, context) {
  742. XCTAssertEqual(4, context.codingPath.count)
  743. XCTAssertEqual("top_level", context.codingPath[0].stringValue)
  744. XCTAssertEqual("sub_level", context.codingPath[1].stringValue)
  745. XCTAssertEqual("nestedValue", context.codingPath[2].stringValue)
  746. XCTAssertEqual("intValue", context.codingPath[3].stringValue)
  747. } catch {
  748. XCTFail("Unexpected error: \(String(describing: error))")
  749. }
  750. }
  751. private struct DecodeMe3: Codable {
  752. var thisIsCamelCase: String
  753. }
  754. func testEncodingKeyStrategySnakeGenerated() {
  755. // Test that this works with a struct that has automatically generated keys
  756. let input = ["this_is_camel_case": "test"]
  757. let decoder = FirebaseDataDecoder()
  758. decoder.keyDecodingStrategy = .convertFromSnakeCase
  759. let result = try! decoder.decode(DecodeMe3.self, from: input)
  760. XCTAssertEqual("test", result.thisIsCamelCase)
  761. }
  762. func testDecodingKeyStrategyCamelGenerated() {
  763. let encoded = DecodeMe3(thisIsCamelCase: "test")
  764. let encoder = FirebaseDataEncoder()
  765. encoder.keyEncodingStrategy = .convertToSnakeCase
  766. let result = try! encoder.encode(encoded)
  767. XCTAssertEqual(["this_is_camel_case": "test"], result as? [String: String])
  768. }
  769. func testKeyStrategySnakeGeneratedAndCustom() {
  770. // Test that this works with a struct that has automatically generated keys
  771. struct DecodeMe4: Codable {
  772. var thisIsCamelCase: String
  773. var thisIsCamelCaseToo: String
  774. private enum CodingKeys: String, CodingKey {
  775. case thisIsCamelCase = "fooBar"
  776. case thisIsCamelCaseToo
  777. }
  778. }
  779. // Decoding
  780. let input = ["foo_bar": "test", "this_is_camel_case_too": "test2"]
  781. let decoder = FirebaseDataDecoder()
  782. decoder.keyDecodingStrategy = .convertFromSnakeCase
  783. let decodingResult = try! decoder.decode(DecodeMe4.self, from: input)
  784. XCTAssertEqual("test", decodingResult.thisIsCamelCase)
  785. XCTAssertEqual("test2", decodingResult.thisIsCamelCaseToo)
  786. // Encoding
  787. let encoded = DecodeMe4(thisIsCamelCase: "test", thisIsCamelCaseToo: "test2")
  788. let encoder = FirebaseDataEncoder()
  789. encoder.keyEncodingStrategy = .convertToSnakeCase
  790. let encodingResult = try! encoder.encode(encoded)
  791. XCTAssertEqual(
  792. ["foo_bar": "test", "this_is_camel_case_too": "test2"],
  793. encodingResult as? [String: String]
  794. )
  795. }
  796. func testKeyStrategyDuplicateKeys() {
  797. // This test is mostly to make sure we don't assert on duplicate keys
  798. struct DecodeMe5: Codable {
  799. var oneTwo: String
  800. var numberOfKeys: Int
  801. enum CodingKeys: String, CodingKey {
  802. case oneTwo
  803. case oneTwoThree
  804. }
  805. init() {
  806. oneTwo = "test"
  807. numberOfKeys = 0
  808. }
  809. init(from decoder: Decoder) throws {
  810. let container = try decoder.container(keyedBy: CodingKeys.self)
  811. oneTwo = try container.decode(String.self, forKey: .oneTwo)
  812. numberOfKeys = container.allKeys.count
  813. }
  814. func encode(to encoder: Encoder) throws {
  815. var container = encoder.container(keyedBy: CodingKeys.self)
  816. try container.encode(oneTwo, forKey: .oneTwo)
  817. try container.encode("test2", forKey: .oneTwoThree)
  818. }
  819. }
  820. let customKeyConversion = { (_ path: [CodingKey]) -> CodingKey in
  821. // All keys are the same!
  822. _TestKey(stringValue: "oneTwo")!
  823. }
  824. // Decoding
  825. // This input has a dictionary with two keys, but only one will end up in the container
  826. let input = ["unused key 1": "test1", "unused key 2": "test2"]
  827. let decoder = FirebaseDataDecoder()
  828. decoder.keyDecodingStrategy = .custom(customKeyConversion)
  829. let decodingResult = try! decoder.decode(DecodeMe5.self, from: input)
  830. // There will be only one result for oneTwo (the second one in the structure)
  831. XCTAssertEqual(1, decodingResult.numberOfKeys)
  832. // Encoding
  833. let encoded = DecodeMe5()
  834. let encoder = FirebaseDataEncoder()
  835. encoder.keyEncodingStrategy = .custom(customKeyConversion)
  836. let decodingResult2 = try! encoder.encode(encoded)
  837. // There will be only one value in the result (the second one encoded)
  838. XCTAssertEqual(["oneTwo": "test2"], decodingResult2 as? [String: String])
  839. }
  840. // MARK: - Encoder Features
  841. func testNestedContainerCodingPaths() {
  842. let encoder = FirebaseDataEncoder()
  843. do {
  844. _ = try encoder.encode(NestedContainersTestType())
  845. } catch let error as NSError {
  846. XCTFail("Caught error during encoding nested container types: \(error)")
  847. }
  848. }
  849. func testSuperEncoderCodingPaths() {
  850. let encoder = FirebaseDataEncoder()
  851. do {
  852. _ = try encoder.encode(NestedContainersTestType(testSuperEncoder: true))
  853. } catch let error as NSError {
  854. XCTFail("Caught error during encoding nested container types: \(error)")
  855. }
  856. }
  857. func testInterceptDecimal() {
  858. let expected =
  859. NSDecimalNumber(
  860. string: "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  861. )
  862. // Want to make sure we write out a number, not the keyed encoding here.
  863. // 1e127 is too big to fit natively in a Double, too, so want to make sure it's encoded as a Decimal.
  864. let decimal = Decimal(sign: .plus, exponent: 127, significand: Decimal(1))
  865. _testRoundTrip(of: decimal, expected: expected)
  866. // Optional Decimals should encode the same way.
  867. _testRoundTrip(of: Optional(decimal), expected: expected)
  868. }
  869. func testInterceptURL() {
  870. // Want to make sure FirebaseDataEncoder writes out single-value URLs, not the keyed encoding.
  871. let expected = "http://swift.org"
  872. let url = URL(string: "http://swift.org")!
  873. _testRoundTrip(of: url, expected: expected)
  874. // Optional URLs should encode the same way.
  875. _testRoundTrip(of: Optional(url), expected: expected)
  876. }
  877. // MARK: - Type coercion
  878. func testTypeCoercion() {
  879. _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int].self)
  880. _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int8].self)
  881. _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int16].self)
  882. _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int32].self)
  883. _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int64].self)
  884. _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt].self)
  885. _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt8].self)
  886. _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt16].self)
  887. _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt32].self)
  888. _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt64].self)
  889. _testRoundTripTypeCoercionFailure(of: [false, true], as: [Float].self)
  890. _testRoundTripTypeCoercionFailure(of: [false, true], as: [Double].self)
  891. _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int], as: [Bool].self)
  892. _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int8], as: [Bool].self)
  893. _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int16], as: [Bool].self)
  894. _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int32], as: [Bool].self)
  895. _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int64], as: [Bool].self)
  896. _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt], as: [Bool].self)
  897. _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt8], as: [Bool].self)
  898. _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt16], as: [Bool].self)
  899. _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt32], as: [Bool].self)
  900. _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt64], as: [Bool].self)
  901. _testRoundTripTypeCoercionFailure(of: [0.0, 1.0] as [Float], as: [Bool].self)
  902. _testRoundTripTypeCoercionFailure(of: [0.0, 1.0] as [Double], as: [Bool].self)
  903. }
  904. func testDecodingConcreteTypeParameter() {
  905. let encoder = FirebaseDataEncoder()
  906. guard let value = try? encoder.encode(Employee.testValue) else {
  907. XCTFail("Unable to encode Employee.")
  908. return
  909. }
  910. let decoder = FirebaseDataDecoder()
  911. guard let decoded = try? decoder.decode(Employee.self as Person.Type, from: value) else {
  912. XCTFail("Failed to decode Employee as Person.")
  913. return
  914. }
  915. XCTAssert(
  916. type(of: decoded) == Employee.self,
  917. "Expected decoded value to be of type Employee; got \(type(of: decoded)) instead."
  918. )
  919. }
  920. // MARK: - Encoder State
  921. // SR-6078
  922. func testEncoderStateThrowOnEncode() {
  923. struct ReferencingEncoderWrapper<T: Encodable>: Encodable {
  924. let value: T
  925. init(_ value: T) { self.value = value }
  926. func encode(to encoder: Encoder) throws {
  927. // This approximates a subclass calling into its superclass, where the superclass encodes a value that might throw.
  928. // The key here is that getting the superEncoder creates a referencing encoder.
  929. var container = encoder.unkeyedContainer()
  930. let superEncoder = container.superEncoder()
  931. // Pushing a nested container on leaves the referencing encoder with multiple containers.
  932. var nestedContainer = superEncoder.unkeyedContainer()
  933. try nestedContainer.encode(value)
  934. }
  935. }
  936. // The structure that would be encoded here looks like
  937. //
  938. // [[[Float.infinity]]]
  939. //
  940. // The wrapper asks for an unkeyed container ([^]), gets a super encoder, and creates a nested container into that ([[^]]).
  941. // We then encode an array into that ([[[^]]]), which happens to be a value that causes us to throw an error.
  942. //
  943. // The issue at hand reproduces when you have a referencing encoder (superEncoder() creates one) that has a container on the stack (unkeyedContainer() adds one) that encodes a value going through box_() (Array does that) that encodes something which throws (Float.infinity does that).
  944. // When reproducing, this will cause a test failure via fatalError().
  945. _ = try? FirebaseDataEncoder().encode(ReferencingEncoderWrapper([Float.infinity]))
  946. }
  947. func testEncoderStateThrowOnEncodeCustomDate() {
  948. // This test is identical to testEncoderStateThrowOnEncode, except throwing via a custom Date closure.
  949. struct ReferencingEncoderWrapper<T: Encodable>: Encodable {
  950. let value: T
  951. init(_ value: T) { self.value = value }
  952. func encode(to encoder: Encoder) throws {
  953. var container = encoder.unkeyedContainer()
  954. let superEncoder = container.superEncoder()
  955. var nestedContainer = superEncoder.unkeyedContainer()
  956. try nestedContainer.encode(value)
  957. }
  958. }
  959. // The closure needs to push a container before throwing an error to trigger.
  960. let encoder = FirebaseDataEncoder()
  961. encoder.dateEncodingStrategy = .custom { _, encoder in
  962. _ = encoder.unkeyedContainer()
  963. enum CustomError: Error { case foo }
  964. throw CustomError.foo
  965. }
  966. _ = try? encoder.encode(ReferencingEncoderWrapper(Date()))
  967. }
  968. func testEncoderStateThrowOnEncodeCustomData() {
  969. // This test is identical to testEncoderStateThrowOnEncode, except throwing via a custom Data closure.
  970. struct ReferencingEncoderWrapper<T: Encodable>: Encodable {
  971. let value: T
  972. init(_ value: T) { self.value = value }
  973. func encode(to encoder: Encoder) throws {
  974. var container = encoder.unkeyedContainer()
  975. let superEncoder = container.superEncoder()
  976. var nestedContainer = superEncoder.unkeyedContainer()
  977. try nestedContainer.encode(value)
  978. }
  979. }
  980. // The closure needs to push a container before throwing an error to trigger.
  981. let encoder = FirebaseDataEncoder()
  982. encoder.dataEncodingStrategy = .custom { _, encoder in
  983. _ = encoder.unkeyedContainer()
  984. enum CustomError: Error { case foo }
  985. throw CustomError.foo
  986. }
  987. _ = try? encoder.encode(ReferencingEncoderWrapper(Data()))
  988. }
  989. // MARK: - Decoder State
  990. // SR-6048
  991. func testDecoderStateThrowOnDecode() {
  992. // The container stack here starts as [[1,2,3]]. Attempting to decode as [String] matches the outer layer (Array), and begins decoding the array.
  993. // Once Array decoding begins, 1 is pushed onto the container stack ([[1,2,3], 1]), and 1 is attempted to be decoded as String. This throws a .typeMismatch, but the container is not popped off the stack.
  994. // When attempting to decode [Int], the container stack is still ([[1,2,3], 1]), and 1 fails to decode as [Int].
  995. let input = [1, 2, 3]
  996. _ = try! FirebaseDataDecoder().decode(EitherDecodable<[String], [Int]>.self, from: input)
  997. }
  998. func testDecoderStateThrowOnDecodeCustomDate() {
  999. // This test is identical to testDecoderStateThrowOnDecode, except we're going to fail because our closure throws an error, not because we hit a type mismatch.
  1000. let decoder = FirebaseDataDecoder()
  1001. decoder.dateDecodingStrategy = .custom { decoder in
  1002. enum CustomError: Error { case foo }
  1003. throw CustomError.foo
  1004. }
  1005. let input = 1
  1006. _ = try! decoder.decode(EitherDecodable<Date, Int>.self, from: input)
  1007. }
  1008. func testDecoderStateThrowOnDecodeCustomData() {
  1009. // This test is identical to testDecoderStateThrowOnDecode, except we're going to fail because our closure throws an error, not because we hit a type mismatch.
  1010. let decoder = FirebaseDataDecoder()
  1011. decoder.dataDecodingStrategy = .custom { decoder in
  1012. enum CustomError: Error { case foo }
  1013. throw CustomError.foo
  1014. }
  1015. let input = 1
  1016. _ = try! decoder.decode(EitherDecodable<Data, Int>.self, from: input)
  1017. }
  1018. // MARK: - Helper Functions
  1019. private var _emptyDictionary: [String: String] {
  1020. return [:]
  1021. }
  1022. private func _testEncodeFailure<T: Encodable>(of value: T) {
  1023. do {
  1024. _ = try FirebaseDataEncoder().encode(value)
  1025. XCTFail("Encode of top-level \(T.self) was expected to fail.")
  1026. } catch {}
  1027. }
  1028. private func _testRoundTrip<T, U>(of value: T,
  1029. expected: U,
  1030. dateEncodingStrategy: FirebaseDataEncoder
  1031. .DateEncodingStrategy = .deferredToDate,
  1032. dateDecodingStrategy: FirebaseDataDecoder
  1033. .DateDecodingStrategy = .deferredToDate,
  1034. dataEncodingStrategy: FirebaseDataEncoder
  1035. .DataEncodingStrategy = .base64,
  1036. dataDecodingStrategy: FirebaseDataDecoder
  1037. .DataDecodingStrategy = .base64,
  1038. keyEncodingStrategy: FirebaseDataEncoder
  1039. .KeyEncodingStrategy = .useDefaultKeys,
  1040. keyDecodingStrategy: FirebaseDataDecoder
  1041. .KeyDecodingStrategy = .useDefaultKeys,
  1042. nonConformingFloatEncodingStrategy: FirebaseDataEncoder
  1043. .NonConformingFloatEncodingStrategy = .throw,
  1044. nonConformingFloatDecodingStrategy: FirebaseDataDecoder
  1045. .NonConformingFloatDecodingStrategy = .throw)
  1046. where T: Codable,
  1047. T: Equatable, U: Equatable {
  1048. var payload: Any! = nil
  1049. do {
  1050. let encoder = FirebaseDataEncoder()
  1051. encoder.dateEncodingStrategy = dateEncodingStrategy
  1052. encoder.dataEncodingStrategy = dataEncodingStrategy
  1053. encoder.nonConformingFloatEncodingStrategy = nonConformingFloatEncodingStrategy
  1054. encoder.keyEncodingStrategy = keyEncodingStrategy
  1055. payload = try encoder.encode(value)
  1056. } catch {
  1057. XCTFail("Failed to encode \(T.self): \(error)")
  1058. }
  1059. XCTAssertEqual(
  1060. expected,
  1061. payload as? U,
  1062. "Produced structure not identical to expected structure."
  1063. )
  1064. do {
  1065. let decoder = FirebaseDataDecoder()
  1066. decoder.dateDecodingStrategy = dateDecodingStrategy
  1067. decoder.dataDecodingStrategy = dataDecodingStrategy
  1068. decoder.nonConformingFloatDecodingStrategy = nonConformingFloatDecodingStrategy
  1069. decoder.keyDecodingStrategy = keyDecodingStrategy
  1070. let decoded = try decoder.decode(T.self, from: payload!)
  1071. XCTAssertEqual(decoded, value, "\(T.self) did not round-trip to an equal value.")
  1072. } catch {
  1073. XCTFail("Failed to decode \(T.self): \(error)")
  1074. }
  1075. }
  1076. private func _testRoundTrip<T>(of value: T,
  1077. dateEncodingStrategy: FirebaseDataEncoder
  1078. .DateEncodingStrategy = .deferredToDate,
  1079. dateDecodingStrategy: FirebaseDataDecoder
  1080. .DateDecodingStrategy = .deferredToDate,
  1081. dataEncodingStrategy: FirebaseDataEncoder
  1082. .DataEncodingStrategy = .base64,
  1083. dataDecodingStrategy: FirebaseDataDecoder
  1084. .DataDecodingStrategy = .base64,
  1085. keyEncodingStrategy: FirebaseDataEncoder
  1086. .KeyEncodingStrategy = .useDefaultKeys,
  1087. keyDecodingStrategy: FirebaseDataDecoder
  1088. .KeyDecodingStrategy = .useDefaultKeys,
  1089. nonConformingFloatEncodingStrategy: FirebaseDataEncoder
  1090. .NonConformingFloatEncodingStrategy = .throw,
  1091. nonConformingFloatDecodingStrategy: FirebaseDataDecoder
  1092. .NonConformingFloatDecodingStrategy = .throw) where T: Codable,
  1093. T: Equatable {
  1094. var payload: Any! = nil
  1095. do {
  1096. let encoder = FirebaseDataEncoder()
  1097. encoder.dateEncodingStrategy = dateEncodingStrategy
  1098. encoder.dataEncodingStrategy = dataEncodingStrategy
  1099. encoder.nonConformingFloatEncodingStrategy = nonConformingFloatEncodingStrategy
  1100. encoder.keyEncodingStrategy = keyEncodingStrategy
  1101. payload = try encoder.encode(value)
  1102. } catch {
  1103. XCTFail("Failed to encode \(T.self): \(error)")
  1104. }
  1105. do {
  1106. let decoder = FirebaseDataDecoder()
  1107. decoder.dateDecodingStrategy = dateDecodingStrategy
  1108. decoder.dataDecodingStrategy = dataDecodingStrategy
  1109. decoder.nonConformingFloatDecodingStrategy = nonConformingFloatDecodingStrategy
  1110. decoder.keyDecodingStrategy = keyDecodingStrategy
  1111. let decoded = try decoder.decode(T.self, from: payload!)
  1112. XCTAssertEqual(decoded, value, "\(T.self) did not round-trip to an equal value.")
  1113. } catch {
  1114. XCTFail("Failed to decode \(T.self): \(error)")
  1115. }
  1116. }
  1117. private func _testRoundTripTypeCoercionFailure<T, U>(of value: T, as type: U.Type)
  1118. where T: Codable, U: Codable {
  1119. do {
  1120. let data = try FirebaseDataEncoder().encode(value)
  1121. _ = try FirebaseDataDecoder().decode(U.self, from: data)
  1122. XCTFail("Coercion from \(T.self) to \(U.self) was expected to fail.")
  1123. } catch {}
  1124. }
  1125. }
  1126. // MARK: - Helper Global Functions
  1127. func expectEqualPaths(_ lhs: [CodingKey], _ rhs: [CodingKey], _ prefix: String) {
  1128. if lhs.count != rhs.count {
  1129. XCTFail("\(prefix) [CodingKey].count mismatch: \(lhs.count) != \(rhs.count)")
  1130. return
  1131. }
  1132. for (key1, key2) in zip(lhs, rhs) {
  1133. switch (key1.intValue, key2.intValue) {
  1134. case (.none, .none): break
  1135. case let (.some(i1), .none):
  1136. XCTFail("\(prefix) CodingKey.intValue mismatch: \(type(of: key1))(\(i1)) != nil")
  1137. return
  1138. case let (.none, .some(i2)):
  1139. XCTFail("\(prefix) CodingKey.intValue mismatch: nil != \(type(of: key2))(\(i2))")
  1140. return
  1141. case let (.some(i1), .some(i2)):
  1142. guard i1 == i2 else {
  1143. XCTFail(
  1144. "\(prefix) CodingKey.intValue mismatch: \(type(of: key1))(\(i1)) != \(type(of: key2))(\(i2))"
  1145. )
  1146. return
  1147. }
  1148. }
  1149. XCTAssertEqual(
  1150. key1.stringValue,
  1151. key2.stringValue,
  1152. "\(prefix) CodingKey.stringValue mismatch: \(type(of: key1))('\(key1.stringValue)') != \(type(of: key2))('\(key2.stringValue)')"
  1153. )
  1154. }
  1155. }
  1156. // MARK: - Test Types
  1157. /* FIXME: Import from %S/Inputs/Coding/SharedTypes.swift somehow. */
  1158. // MARK: - Empty Types
  1159. private struct EmptyStruct: Codable, Equatable {
  1160. static func == (_ lhs: EmptyStruct, _ rhs: EmptyStruct) -> Bool {
  1161. return true
  1162. }
  1163. }
  1164. private class EmptyClass: Codable, Equatable {
  1165. static func == (_ lhs: EmptyClass, _ rhs: EmptyClass) -> Bool {
  1166. return true
  1167. }
  1168. }
  1169. // MARK: - Single-Value Types
  1170. /// A simple on-off switch type that encodes as a single Bool value.
  1171. private enum Switch: Codable {
  1172. case off
  1173. case on
  1174. init(from decoder: Decoder) throws {
  1175. let container = try decoder.singleValueContainer()
  1176. switch try container.decode(Bool.self) {
  1177. case false: self = .off
  1178. case true: self = .on
  1179. }
  1180. }
  1181. func encode(to encoder: Encoder) throws {
  1182. var container = encoder.singleValueContainer()
  1183. switch self {
  1184. case .off: try container.encode(false)
  1185. case .on: try container.encode(true)
  1186. }
  1187. }
  1188. }
  1189. /// A simple timestamp type that encodes as a single Double value.
  1190. private struct Timestamp: Codable, Equatable {
  1191. let value: Double
  1192. init(_ value: Double) {
  1193. self.value = value
  1194. }
  1195. init(from decoder: Decoder) throws {
  1196. let container = try decoder.singleValueContainer()
  1197. value = try container.decode(Double.self)
  1198. }
  1199. func encode(to encoder: Encoder) throws {
  1200. var container = encoder.singleValueContainer()
  1201. try container.encode(value)
  1202. }
  1203. static func == (_ lhs: Timestamp, _ rhs: Timestamp) -> Bool {
  1204. return lhs.value == rhs.value
  1205. }
  1206. }
  1207. /// A simple referential counter type that encodes as a single Int value.
  1208. private final class Counter: Codable, Equatable {
  1209. var count: Int = 0
  1210. init() {}
  1211. init(from decoder: Decoder) throws {
  1212. let container = try decoder.singleValueContainer()
  1213. count = try container.decode(Int.self)
  1214. }
  1215. func encode(to encoder: Encoder) throws {
  1216. var container = encoder.singleValueContainer()
  1217. try container.encode(count)
  1218. }
  1219. static func == (_ lhs: Counter, _ rhs: Counter) -> Bool {
  1220. return lhs === rhs || lhs.count == rhs.count
  1221. }
  1222. }
  1223. // MARK: - Structured Types
  1224. /// A simple address type that encodes as a dictionary of values.
  1225. private struct Address: Codable, Equatable {
  1226. let street: String
  1227. let city: String
  1228. let state: String
  1229. let zipCode: Int
  1230. let country: String
  1231. init(street: String, city: String, state: String, zipCode: Int, country: String) {
  1232. self.street = street
  1233. self.city = city
  1234. self.state = state
  1235. self.zipCode = zipCode
  1236. self.country = country
  1237. }
  1238. static func == (_ lhs: Address, _ rhs: Address) -> Bool {
  1239. return lhs.street == rhs.street &&
  1240. lhs.city == rhs.city &&
  1241. lhs.state == rhs.state &&
  1242. lhs.zipCode == rhs.zipCode &&
  1243. lhs.country == rhs.country
  1244. }
  1245. static var testValue: Address {
  1246. return Address(street: "1 Infinite Loop",
  1247. city: "Cupertino",
  1248. state: "CA",
  1249. zipCode: 95014,
  1250. country: "United States")
  1251. }
  1252. }
  1253. /// A simple person class that encodes as a dictionary of values.
  1254. private class Person: Codable, Equatable {
  1255. let name: String
  1256. let email: String
  1257. let website: URL?
  1258. init(name: String, email: String, website: URL? = nil) {
  1259. self.name = name
  1260. self.email = email
  1261. self.website = website
  1262. }
  1263. func isEqual(_ other: Person) -> Bool {
  1264. return name == other.name &&
  1265. email == other.email &&
  1266. website == other.website
  1267. }
  1268. static func == (_ lhs: Person, _ rhs: Person) -> Bool {
  1269. return lhs.isEqual(rhs)
  1270. }
  1271. class var testValue: Person {
  1272. return Person(name: "Johnny Appleseed", email: "appleseed@apple.com")
  1273. }
  1274. }
  1275. /// A class which shares its encoder and decoder with its superclass.
  1276. private class Employee: Person {
  1277. let id: Int
  1278. init(name: String, email: String, website: URL? = nil, id: Int) {
  1279. self.id = id
  1280. super.init(name: name, email: email, website: website)
  1281. }
  1282. enum CodingKeys: String, CodingKey {
  1283. case id
  1284. }
  1285. required init(from decoder: Decoder) throws {
  1286. let container = try decoder.container(keyedBy: CodingKeys.self)
  1287. id = try container.decode(Int.self, forKey: .id)
  1288. try super.init(from: decoder)
  1289. }
  1290. override func encode(to encoder: Encoder) throws {
  1291. var container = encoder.container(keyedBy: CodingKeys.self)
  1292. try container.encode(id, forKey: .id)
  1293. try super.encode(to: encoder)
  1294. }
  1295. override func isEqual(_ other: Person) -> Bool {
  1296. if let employee = other as? Employee {
  1297. guard id == employee.id else { return false }
  1298. }
  1299. return super.isEqual(other)
  1300. }
  1301. override class var testValue: Employee {
  1302. return Employee(name: "Johnny Appleseed", email: "appleseed@apple.com", id: 42)
  1303. }
  1304. }
  1305. /// A simple company struct which encodes as a dictionary of nested values.
  1306. private struct Company: Codable, Equatable {
  1307. let address: Address
  1308. var employees: [Employee]
  1309. init(address: Address, employees: [Employee]) {
  1310. self.address = address
  1311. self.employees = employees
  1312. }
  1313. static func == (_ lhs: Company, _ rhs: Company) -> Bool {
  1314. return lhs.address == rhs.address && lhs.employees == rhs.employees
  1315. }
  1316. static var testValue: Company {
  1317. return Company(address: Address.testValue, employees: [Employee.testValue])
  1318. }
  1319. }
  1320. /// An enum type which decodes from Bool?.
  1321. private enum EnhancedBool: Codable {
  1322. case `true`
  1323. case `false`
  1324. case fileNotFound
  1325. init(from decoder: Decoder) throws {
  1326. let container = try decoder.singleValueContainer()
  1327. if container.decodeNil() {
  1328. self = .fileNotFound
  1329. } else {
  1330. let value = try container.decode(Bool.self)
  1331. self = value ? .true : .false
  1332. }
  1333. }
  1334. func encode(to encoder: Encoder) throws {
  1335. var container = encoder.singleValueContainer()
  1336. switch self {
  1337. case .true: try container.encode(true)
  1338. case .false: try container.encode(false)
  1339. case .fileNotFound: try container.encodeNil()
  1340. }
  1341. }
  1342. }
  1343. /// A type which encodes as an array directly through a single value container.
  1344. struct Numbers: Codable, Equatable {
  1345. let values = [4, 8, 15, 16, 23, 42]
  1346. init() {}
  1347. init(from decoder: Decoder) throws {
  1348. let container = try decoder.singleValueContainer()
  1349. let decodedValues = try container.decode([Int].self)
  1350. guard decodedValues == values else {
  1351. throw DecodingError
  1352. .dataCorrupted(DecodingError
  1353. .Context(codingPath: decoder.codingPath, debugDescription: "The Numbers are wrong!"))
  1354. }
  1355. }
  1356. func encode(to encoder: Encoder) throws {
  1357. var container = encoder.singleValueContainer()
  1358. try container.encode(values)
  1359. }
  1360. static func == (_ lhs: Numbers, _ rhs: Numbers) -> Bool {
  1361. return lhs.values == rhs.values
  1362. }
  1363. static var testValue: Numbers {
  1364. return Numbers()
  1365. }
  1366. }
  1367. /// A type which encodes as a dictionary directly through a single value container.
  1368. private final class Mapping: Codable, Equatable {
  1369. let values: [String: URL]
  1370. init(values: [String: URL]) {
  1371. self.values = values
  1372. }
  1373. init(from decoder: Decoder) throws {
  1374. let container = try decoder.singleValueContainer()
  1375. values = try container.decode([String: URL].self)
  1376. }
  1377. func encode(to encoder: Encoder) throws {
  1378. var container = encoder.singleValueContainer()
  1379. try container.encode(values)
  1380. }
  1381. static func == (_ lhs: Mapping, _ rhs: Mapping) -> Bool {
  1382. return lhs === rhs || lhs.values == rhs.values
  1383. }
  1384. static var testValue: Mapping {
  1385. return Mapping(values: ["Apple": URL(string: "http://apple.com")!,
  1386. "localhost": URL(string: "http://127.0.0.1")!])
  1387. }
  1388. }
  1389. struct NestedContainersTestType: Encodable {
  1390. let testSuperEncoder: Bool
  1391. init(testSuperEncoder: Bool = false) {
  1392. self.testSuperEncoder = testSuperEncoder
  1393. }
  1394. enum TopLevelCodingKeys: Int, CodingKey {
  1395. case a
  1396. case b
  1397. case c
  1398. }
  1399. enum IntermediateCodingKeys: Int, CodingKey {
  1400. case one
  1401. case two
  1402. }
  1403. func encode(to encoder: Encoder) throws {
  1404. if testSuperEncoder {
  1405. var topLevelContainer = encoder.container(keyedBy: TopLevelCodingKeys.self)
  1406. expectEqualPaths(encoder.codingPath, [], "Top-level Encoder's codingPath changed.")
  1407. expectEqualPaths(
  1408. topLevelContainer.codingPath,
  1409. [],
  1410. "New first-level keyed container has non-empty codingPath."
  1411. )
  1412. let superEncoder = topLevelContainer.superEncoder(forKey: .a)
  1413. expectEqualPaths(encoder.codingPath, [], "Top-level Encoder's codingPath changed.")
  1414. expectEqualPaths(
  1415. topLevelContainer.codingPath,
  1416. [],
  1417. "First-level keyed container's codingPath changed."
  1418. )
  1419. expectEqualPaths(
  1420. superEncoder.codingPath,
  1421. [TopLevelCodingKeys.a],
  1422. "New superEncoder had unexpected codingPath."
  1423. )
  1424. _testNestedContainers(in: superEncoder, baseCodingPath: [TopLevelCodingKeys.a])
  1425. } else {
  1426. _testNestedContainers(in: encoder, baseCodingPath: [])
  1427. }
  1428. }
  1429. func _testNestedContainers(in encoder: Encoder, baseCodingPath: [CodingKey]) {
  1430. expectEqualPaths(encoder.codingPath, baseCodingPath, "New encoder has non-empty codingPath.")
  1431. // codingPath should not change upon fetching a non-nested container.
  1432. var firstLevelContainer = encoder.container(keyedBy: TopLevelCodingKeys.self)
  1433. expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
  1434. expectEqualPaths(
  1435. firstLevelContainer.codingPath,
  1436. baseCodingPath,
  1437. "New first-level keyed container has non-empty codingPath."
  1438. )
  1439. // Nested Keyed Container
  1440. do {
  1441. // Nested container for key should have a new key pushed on.
  1442. var secondLevelContainer = firstLevelContainer.nestedContainer(
  1443. keyedBy: IntermediateCodingKeys.self,
  1444. forKey: .a
  1445. )
  1446. expectEqualPaths(
  1447. encoder.codingPath,
  1448. baseCodingPath,
  1449. "Top-level Encoder's codingPath changed."
  1450. )
  1451. expectEqualPaths(
  1452. firstLevelContainer.codingPath,
  1453. baseCodingPath,
  1454. "First-level keyed container's codingPath changed."
  1455. )
  1456. expectEqualPaths(
  1457. secondLevelContainer.codingPath,
  1458. baseCodingPath + [TopLevelCodingKeys.a],
  1459. "New second-level keyed container had unexpected codingPath."
  1460. )
  1461. // Inserting a keyed container should not change existing coding paths.
  1462. let thirdLevelContainerKeyed = secondLevelContainer.nestedContainer(
  1463. keyedBy: IntermediateCodingKeys.self,
  1464. forKey: .one
  1465. )
  1466. expectEqualPaths(
  1467. encoder.codingPath,
  1468. baseCodingPath,
  1469. "Top-level Encoder's codingPath changed."
  1470. )
  1471. expectEqualPaths(
  1472. firstLevelContainer.codingPath,
  1473. baseCodingPath,
  1474. "First-level keyed container's codingPath changed."
  1475. )
  1476. expectEqualPaths(
  1477. secondLevelContainer.codingPath,
  1478. baseCodingPath + [TopLevelCodingKeys.a],
  1479. "Second-level keyed container's codingPath changed."
  1480. )
  1481. expectEqualPaths(
  1482. thirdLevelContainerKeyed.codingPath,
  1483. baseCodingPath + [TopLevelCodingKeys.a, IntermediateCodingKeys.one],
  1484. "New third-level keyed container had unexpected codingPath."
  1485. )
  1486. // Inserting an unkeyed container should not change existing coding paths.
  1487. let thirdLevelContainerUnkeyed = secondLevelContainer.nestedUnkeyedContainer(forKey: .two)
  1488. expectEqualPaths(
  1489. encoder.codingPath,
  1490. baseCodingPath + [],
  1491. "Top-level Encoder's codingPath changed."
  1492. )
  1493. expectEqualPaths(
  1494. firstLevelContainer.codingPath,
  1495. baseCodingPath + [],
  1496. "First-level keyed container's codingPath changed."
  1497. )
  1498. expectEqualPaths(
  1499. secondLevelContainer.codingPath,
  1500. baseCodingPath + [TopLevelCodingKeys.a],
  1501. "Second-level keyed container's codingPath changed."
  1502. )
  1503. expectEqualPaths(
  1504. thirdLevelContainerUnkeyed.codingPath,
  1505. baseCodingPath + [TopLevelCodingKeys.a, IntermediateCodingKeys.two],
  1506. "New third-level unkeyed container had unexpected codingPath."
  1507. )
  1508. }
  1509. // Nested Unkeyed Container
  1510. do {
  1511. // Nested container for key should have a new key pushed on.
  1512. var secondLevelContainer = firstLevelContainer.nestedUnkeyedContainer(forKey: .b)
  1513. expectEqualPaths(
  1514. encoder.codingPath,
  1515. baseCodingPath,
  1516. "Top-level Encoder's codingPath changed."
  1517. )
  1518. expectEqualPaths(
  1519. firstLevelContainer.codingPath,
  1520. baseCodingPath,
  1521. "First-level keyed container's codingPath changed."
  1522. )
  1523. expectEqualPaths(
  1524. secondLevelContainer.codingPath,
  1525. baseCodingPath + [TopLevelCodingKeys.b],
  1526. "New second-level keyed container had unexpected codingPath."
  1527. )
  1528. // Appending a keyed container should not change existing coding paths.
  1529. let thirdLevelContainerKeyed = secondLevelContainer
  1530. .nestedContainer(keyedBy: IntermediateCodingKeys.self)
  1531. expectEqualPaths(
  1532. encoder.codingPath,
  1533. baseCodingPath,
  1534. "Top-level Encoder's codingPath changed."
  1535. )
  1536. expectEqualPaths(
  1537. firstLevelContainer.codingPath,
  1538. baseCodingPath,
  1539. "First-level keyed container's codingPath changed."
  1540. )
  1541. expectEqualPaths(
  1542. secondLevelContainer.codingPath,
  1543. baseCodingPath + [TopLevelCodingKeys.b],
  1544. "Second-level unkeyed container's codingPath changed."
  1545. )
  1546. expectEqualPaths(
  1547. thirdLevelContainerKeyed.codingPath,
  1548. baseCodingPath + [TopLevelCodingKeys.b, _TestKey(index: 0)],
  1549. "New third-level keyed container had unexpected codingPath."
  1550. )
  1551. // Appending an unkeyed container should not change existing coding paths.
  1552. let thirdLevelContainerUnkeyed = secondLevelContainer.nestedUnkeyedContainer()
  1553. expectEqualPaths(
  1554. encoder.codingPath,
  1555. baseCodingPath,
  1556. "Top-level Encoder's codingPath changed."
  1557. )
  1558. expectEqualPaths(
  1559. firstLevelContainer.codingPath,
  1560. baseCodingPath,
  1561. "First-level keyed container's codingPath changed."
  1562. )
  1563. expectEqualPaths(
  1564. secondLevelContainer.codingPath,
  1565. baseCodingPath + [TopLevelCodingKeys.b],
  1566. "Second-level unkeyed container's codingPath changed."
  1567. )
  1568. expectEqualPaths(
  1569. thirdLevelContainerUnkeyed.codingPath,
  1570. baseCodingPath + [TopLevelCodingKeys.b, _TestKey(index: 1)],
  1571. "New third-level unkeyed container had unexpected codingPath."
  1572. )
  1573. }
  1574. }
  1575. }
  1576. // MARK: - Helper Types
  1577. /// A key type which can take on any string or integer value.
  1578. /// This needs to mirror _JSONKey.
  1579. private struct _TestKey: CodingKey {
  1580. var stringValue: String
  1581. var intValue: Int?
  1582. init?(stringValue: String) {
  1583. self.stringValue = stringValue
  1584. intValue = nil
  1585. }
  1586. init?(intValue: Int) {
  1587. stringValue = "\(intValue)"
  1588. self.intValue = intValue
  1589. }
  1590. init(index: Int) {
  1591. stringValue = "Index \(index)"
  1592. intValue = index
  1593. }
  1594. }
  1595. private struct FloatNaNPlaceholder: Codable, Equatable {
  1596. init() {}
  1597. func encode(to encoder: Encoder) throws {
  1598. var container = encoder.singleValueContainer()
  1599. try container.encode(Float.nan)
  1600. }
  1601. init(from decoder: Decoder) throws {
  1602. let container = try decoder.singleValueContainer()
  1603. let float = try container.decode(Float.self)
  1604. if !float.isNaN {
  1605. throw DecodingError
  1606. .dataCorrupted(DecodingError
  1607. .Context(codingPath: decoder.codingPath, debugDescription: "Couldn't decode NaN."))
  1608. }
  1609. }
  1610. static func == (_ lhs: FloatNaNPlaceholder, _ rhs: FloatNaNPlaceholder) -> Bool {
  1611. return true
  1612. }
  1613. }
  1614. private struct DoubleNaNPlaceholder: Codable, Equatable {
  1615. init() {}
  1616. func encode(to encoder: Encoder) throws {
  1617. var container = encoder.singleValueContainer()
  1618. try container.encode(Double.nan)
  1619. }
  1620. init(from decoder: Decoder) throws {
  1621. let container = try decoder.singleValueContainer()
  1622. let double = try container.decode(Double.self)
  1623. if !double.isNaN {
  1624. throw DecodingError
  1625. .dataCorrupted(DecodingError
  1626. .Context(codingPath: decoder.codingPath, debugDescription: "Couldn't decode NaN."))
  1627. }
  1628. }
  1629. static func == (_ lhs: DoubleNaNPlaceholder, _ rhs: DoubleNaNPlaceholder) -> Bool {
  1630. return true
  1631. }
  1632. }
  1633. private enum EitherDecodable<T: Decodable, U: Decodable>: Decodable {
  1634. case t(T)
  1635. case u(U)
  1636. init(from decoder: Decoder) throws {
  1637. let container = try decoder.singleValueContainer()
  1638. do {
  1639. self = .t(try container.decode(T.self))
  1640. } catch {
  1641. self = .u(try container.decode(U.self))
  1642. }
  1643. }
  1644. }