TimestampCodaleTests.swift 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright 2024 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import XCTest
  15. import FirebaseCore
  16. @testable import FirebaseDataConnect
  17. import Foundation
  18. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  19. final class TimestampTests: XCTestCase {
  20. override func setUpWithError() throws {}
  21. override func tearDownWithError() throws {}
  22. func testSecondsEquals0AndNanosecondsEquals0() throws {
  23. try verifyEncodeDecodeRoundTrip(Timestamp(seconds: 0, nanoseconds: 0))
  24. }
  25. func testSmallestValue() throws {
  26. try verifyEncodeDecodeRoundTrip(Timestamp(seconds: -62_135_596_800, nanoseconds: 0))
  27. }
  28. func testLargestValue() throws {
  29. try verifyEncodeDecodeRoundTrip(Timestamp(seconds: -62_135_596_800, nanoseconds: 999_999_999))
  30. }
  31. func testMillisecondPrecision() throws {
  32. try verifyEncodeDecodeRoundTrip(Timestamp(seconds: 130_804, nanoseconds: 642))
  33. }
  34. func testMicrosecondPrecision() throws {
  35. try verifyEncodeDecodeRoundTrip(Timestamp(seconds: 130_804, nanoseconds: 642))
  36. }
  37. func testWhenTimeSecfracIsOmitted() throws {
  38. try XCTAssertEqual(
  39. decodeTimestamp("2006-01-02T15:04:05Z"),
  40. Timestamp(seconds: 1_136_214_245, nanoseconds: 0)
  41. )
  42. }
  43. func testWhenTimeSecfracHasMillisecondPrecision() throws {
  44. try XCTAssertEqual(
  45. decodeTimestamp("2006-01-02T15:04:05.123Z"),
  46. Timestamp(seconds: 1_136_214_245, nanoseconds: 123_000_000)
  47. )
  48. }
  49. func testWhenTimeSecfracHasMicrosecondPrecision() throws {
  50. try XCTAssertEqual(
  51. decodeTimestamp("2006-01-02T15:04:05.123456Z"),
  52. Timestamp(seconds: 1_136_214_245, nanoseconds: 123_456_000)
  53. )
  54. }
  55. func testWhenTimeSecfracHasNanosecondPrecision() throws {
  56. try XCTAssertEqual(
  57. decodeTimestamp("2006-01-02T15:04:05.123456789Z"),
  58. Timestamp(seconds: 1_136_214_245, nanoseconds: 123_456_789)
  59. )
  60. }
  61. func testDecodeWhenTimeOffsetIs0() throws {
  62. try XCTAssertEqual(
  63. decodeTimestamp("2006-01-02T15:04:05-00:00"),
  64. decodeTimestamp("2006-01-02T15:04:05Z")
  65. )
  66. try XCTAssertEqual(
  67. decodeTimestamp("2006-01-02T15:04:05+00:00"),
  68. decodeTimestamp("2006-01-02T15:04:05Z")
  69. )
  70. }
  71. func testDecodeWhenTimeOffsetIsPositive() throws {
  72. try XCTAssertEqual(
  73. decodeTimestamp("2006-01-02T15:04:05+07:00"),
  74. decodeTimestamp("2006-01-02T08:04:05Z")
  75. )
  76. }
  77. func testDecodeWhenTimeOffsetIsNegative() throws {
  78. try XCTAssertEqual(
  79. decodeTimestamp("2006-01-02T15:04:05-05:10"),
  80. decodeTimestamp("2006-01-02T20:14:05Z")
  81. )
  82. }
  83. func testDecodeWithBothTimeSecFracAndTimeOffset() throws {
  84. try XCTAssertEqual(
  85. decodeTimestamp("2023-05-21T11:04:05.462-12:07"),
  86. decodeTimestamp("2023-05-21T23:11:05.462Z")
  87. )
  88. try XCTAssertEqual(
  89. decodeTimestamp("2053-11-02T15:04:05.743393-05:10"),
  90. decodeTimestamp("2053-11-02T20:14:05.743393Z")
  91. )
  92. try XCTAssertEqual(
  93. decodeTimestamp("1538-03-05T15:04:05.653498752-03:01"),
  94. decodeTimestamp("1538-03-05T18:05:05.653498752Z")
  95. )
  96. try XCTAssertEqual(
  97. decodeTimestamp("2023-05-21T11:04:05.662+10:01"),
  98. decodeTimestamp("2023-05-21T01:03:05.662Z")
  99. )
  100. try XCTAssertEqual(
  101. decodeTimestamp("2144-01-02T15:04:05.753493+01:00"),
  102. decodeTimestamp("2144-01-02T14:04:05.753493Z")
  103. )
  104. try XCTAssertEqual(
  105. decodeTimestamp("1358-03-05T15:04:05.527094582+13:03"),
  106. decodeTimestamp("1358-03-05T02:01:05.527094582Z")
  107. )
  108. }
  109. func testDecodeIsCaseInsensitive() throws {
  110. try XCTAssertEqual(
  111. decodeTimestamp("2006-01-02t15:04:05.123456789z"),
  112. decodeTimestamp("2006-01-02t15:04:05.123456789Z")
  113. )
  114. }
  115. func testMinimumValueInDataConnect() throws {
  116. try XCTAssertEqual(
  117. decodeTimestamp("1583-01-01T00:00:00.000000Z"),
  118. Timestamp(seconds: -12_212_553_600, nanoseconds: 0)
  119. )
  120. }
  121. func testMaximumValueInDataConnect() throws {
  122. try XCTAssertEqual(
  123. decodeTimestamp("9999-12-31T23:59:59.999999999Z"),
  124. Timestamp(seconds: 253_402_300_799, nanoseconds: 999_999_999)
  125. )
  126. }
  127. func testInvalidFormatShouldThrow() throws {
  128. for invalidText in invalidTimestampStrs {
  129. XCTAssertThrowsError(try decodeTimestamp(invalidText))
  130. }
  131. }
  132. func verifyEncodeDecodeRoundTrip(_ timestamp: Timestamp) throws {
  133. do {
  134. let jsonEncoder = JSONEncoder()
  135. let jsonData = try jsonEncoder.encode(timestamp)
  136. let jsonDecoder = JSONDecoder()
  137. let decodedTimestamp = try jsonDecoder.decode(Timestamp.self, from: jsonData)
  138. XCTAssertEqual(timestamp, decodedTimestamp)
  139. }
  140. }
  141. func decodeTimestamp(_ text: String) throws -> Timestamp {
  142. let jsonEncoder = JSONEncoder()
  143. let jsonData = try jsonEncoder.encode(text)
  144. let jsonDecoder = JSONDecoder()
  145. let decodedTimestamp = try jsonDecoder.decode(Timestamp.self, from: jsonData)
  146. return decodedTimestamp
  147. }
  148. // These strings were generated by Gemini
  149. let invalidTimestampStrs: [String] =
  150. [
  151. "",
  152. "1985-04-12T23:20:50.123456789",
  153. "1985-04-12T23:20:50.123456789X",
  154. "1985-04-12T23:20:50.123456789+",
  155. "1985-04-12T23:20:50.123456789+07",
  156. "1985-04-12T23:20:50.123456789+07:",
  157. "1985-04-12T23:20:50.123456789+07:0",
  158. "1985-04-12T23:20:50.123456789+07:000",
  159. "1985-04-12T23:20:50.123456789+07:00a",
  160. "1985-04-12T23:20:50.123456789+07:a0",
  161. "1985-04-12T23:20:50.123456789+07::00",
  162. "1985-04-12T23:20:50.123456789+0:00",
  163. "1985-04-12T23:20:50.123456789+00:",
  164. "1985-04-12T23:20:50.123456789+00:0",
  165. "1985-04-12T23:20:50.123456789+00:a",
  166. "1985-04-12T23:20:50.123456789+00:0a",
  167. "1985-04-12T23:20:50.123456789+0:0a",
  168. "1985-04-12T23:20:50.123456789+0:a0",
  169. "1985-04-12T23:20:50.123456789+0::00",
  170. "1985-04-12T23:20:50.123456789-07:0a",
  171. "1985-04-12T23:20:50.123456789-07:a0",
  172. "1985-04-12T23:20:50.123456789-07::00",
  173. "1985-04-12T23:20:50.123456789-0:0a",
  174. "1985-04-12T23:20:50.123456789-0:a0",
  175. "1985-04-12T23:20:50.123456789-0::00",
  176. "1985-04-12T23:20:50.123456789-00:0a",
  177. "1985-04-12T23:20:50.123456789-00:a0",
  178. "1985-04-12T23:20:50.123456789-00::00",
  179. "1985-04-12T23:20:50.123456789-0:00",
  180. "1985-04-12T23:20:50.123456789-00:",
  181. "1985-04-12T23:20:50.123456789-00:0",
  182. "1985-04-12T23:20:50.123456789-00:a",
  183. "1985-04-12T23:20:50.123456789-00:0a",
  184. "1985-04-12T23:20:50.123456789-0:0a",
  185. "1985-04-12T23:20:50.123456789-0:a0",
  186. "1985-04-12T23:20:50.123456789-0::00",
  187. "1985/04/12T23:20:50.123456789Z",
  188. "1985-04-12T23:20:50.123456789Z.",
  189. "1985-04-12T23:20:50.123456789Z..",
  190. "1985-04-12T23:20:50.123456789Z...",
  191. "1985-04-12T23:20:50.123456789+07:00.",
  192. "1985-04-12T23:20:50.123456789+07:00..",
  193. "1985-04-12T23:20:50.123456789+07:00...",
  194. "1985-04-12T23:20:50.123456789-07:00.",
  195. "1985-04-12T23:20:50.123456789-07:00..",
  196. "1985-04-12T23:20:50.123456789-07:00...",
  197. "1985-04-12T23:20:50.1234567890Z",
  198. "1985-04-12T23:20:50.12345678900Z",
  199. "1985-04-12T23:20:50.123456789000Z",
  200. "1985-04-12T23:20:50.1234567890000Z",
  201. "1985-04-12T23:20:50.12345678900000Z",
  202. "1985-04-12T23:20:50.123456789000000Z",
  203. "1985-04-12T23:20:50.1234567890000000Z",
  204. "1985-04-12T23:20:50.12345678900000000Z",
  205. "1985-04-12T23:20:50.1234567891Z",
  206. "1985-04-12T23:20:50.12345678911Z",
  207. "1985-04-12T23:20:50.123456789111Z",
  208. "1985-04-12T23:20:50.1234567891111Z",
  209. "1985-04-12T23:20:50.12345678911111Z",
  210. "1985-04-12T23:20:50.123456789111111Z",
  211. "1985-04-12T23:20:50.1234567891111111Z",
  212. "1985-04-12T23:20:50.12345678911111111Z",
  213. "1985-04-12T23:20:50.123456789000000000Z",
  214. "1985-04-12T23:20:50.1234567890000000000Z",
  215. "1985-04-12T23:20:50.12345678900000000000Z",
  216. ]
  217. }