JSONCompareTests.swift 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import Foundation
  2. import Testing
  3. @testable import Trio
  4. @Suite("JSON Compare") struct JSONCompareTests {
  5. // Test fixtures
  6. let matchingJSON = """
  7. {
  8. "value": 42,
  9. "text": "hello",
  10. "flag": true,
  11. "nested": {
  12. "array": [1, 2, 3],
  13. "object": {"key": "value"}
  14. }
  15. }
  16. """
  17. @Test("should find no differences between identical JSONs") func matchingJSONs() async throws {
  18. let differences = try JSONCompare.differences(
  19. function: .makeProfile,
  20. swift: matchingJSON,
  21. javascript: matchingJSON
  22. )
  23. #expect(differences.isEmpty)
  24. }
  25. @Test("should detect scalar value differences") func scalarDifferences() async throws {
  26. let jsJSON = """
  27. {
  28. "number": 42,
  29. "text": "hello",
  30. "boolean": true
  31. }
  32. """
  33. let swiftJSON = """
  34. {
  35. "number": 43,
  36. "text": "world",
  37. "boolean": false
  38. }
  39. """
  40. let differences = try JSONCompare.differences(
  41. function: .makeProfile,
  42. swift: swiftJSON,
  43. javascript: jsJSON
  44. )
  45. #expect(differences.count == 3)
  46. #expect(differences["number"]?.js == .number(42))
  47. #expect(differences["number"]?.swift == .number(43))
  48. #expect(differences["text"]?.js == .string("hello"))
  49. #expect(differences["text"]?.swift == .string("world"))
  50. #expect(differences["boolean"]?.js == .boolean(true))
  51. #expect(differences["boolean"]?.swift == .boolean(false))
  52. }
  53. @Test("should detect missing keys") func missingKeys() async throws {
  54. let jsJSON = """
  55. {
  56. "common": 42,
  57. "jsOnly": "hello"
  58. }
  59. """
  60. let swiftJSON = """
  61. {
  62. "common": 42,
  63. "swiftOnly": "world"
  64. }
  65. """
  66. let differences = try JSONCompare.differences(
  67. function: .makeProfile,
  68. swift: swiftJSON,
  69. javascript: jsJSON
  70. )
  71. #expect(differences.count == 2)
  72. #expect(differences["jsOnly"]?.nativeKeyMissing == true)
  73. #expect(differences["jsOnly"]?.jsKeyMissing == false)
  74. #expect(differences["swiftOnly"]?.jsKeyMissing == true)
  75. #expect(differences["swiftOnly"]?.nativeKeyMissing == false)
  76. }
  77. @Test("should detect nested object differences") func nestedDifferences() async throws {
  78. let jsJSON = """
  79. {
  80. "nested": {
  81. "value": 42,
  82. "array": [1, 2, 3]
  83. }
  84. }
  85. """
  86. let swiftJSON = """
  87. {
  88. "nested": {
  89. "value": 43,
  90. "array": [1, 2, 4]
  91. }
  92. }
  93. """
  94. let differences = try JSONCompare.differences(
  95. function: .makeProfile,
  96. swift: swiftJSON,
  97. javascript: jsJSON
  98. )
  99. #expect(differences.count == 1)
  100. guard case let .object(nestedDiff) = differences["nested"]?.js else {
  101. throw TestFailure("Expected nested object difference")
  102. }
  103. #expect(nestedDiff["value"] == .number(42))
  104. #expect(nestedDiff["array"] == .array([.number(1), .number(2), .number(3)]))
  105. }
  106. @Test("should ignore specified keys for makeProfile") func keyIgnoring() async throws {
  107. let jsJSON = """
  108. {
  109. "value": 42,
  110. "calc_glucose_noise": true,
  111. "enableEnliteBgproxy": false
  112. }
  113. """
  114. let swiftJSON = """
  115. {
  116. "value": 42
  117. }
  118. """
  119. let differences = try JSONCompare.differences(
  120. function: .makeProfile,
  121. swift: swiftJSON,
  122. javascript: jsJSON
  123. )
  124. #expect(differences.isEmpty)
  125. }
  126. @Test("should handle invalid JSON") func invalidJSON() async throws {
  127. let invalidJSON = "{ invalid json }"
  128. do {
  129. _ = try JSONCompare.differences(
  130. function: .makeProfile,
  131. swift: invalidJSON,
  132. javascript: matchingJSON
  133. )
  134. throw TestFailure("Expected error for invalid JSON")
  135. } catch {
  136. // Expected error
  137. #expect(true)
  138. }
  139. }
  140. @Test("should handle empty JSON objects") func emptyObjects() async throws {
  141. let emptyJSON = "{}"
  142. let differences = try JSONCompare.differences(
  143. function: .makeProfile,
  144. swift: emptyJSON,
  145. javascript: emptyJSON
  146. )
  147. #expect(differences.isEmpty)
  148. }
  149. @Test("should detect array length differences") func arrayLengthDifferences() async throws {
  150. let jsJSON = """
  151. {
  152. "array": [1, 2, 3]
  153. }
  154. """
  155. let swiftJSON = """
  156. {
  157. "array": [1, 2]
  158. }
  159. """
  160. let differences = try JSONCompare.differences(
  161. function: .makeProfile,
  162. swift: swiftJSON,
  163. javascript: jsJSON
  164. )
  165. #expect(differences.count == 1)
  166. guard case let .array(jsArray) = differences["array"]?.js,
  167. case let .array(swiftArray) = differences["array"]?.swift
  168. else {
  169. throw TestFailure("Expected array differences")
  170. }
  171. #expect(jsArray.count == 3)
  172. #expect(swiftArray.count == 2)
  173. }
  174. @Test("should be empty array for {} and [] pump history strings") func emptyPumpHistoryParsing() async throws {
  175. let emptyArray = try JSONBridge.pumpHistory(from: "[]")
  176. let emptyObject = try JSONBridge.pumpHistory(from: "{}")
  177. #expect(emptyArray.isEmpty)
  178. #expect(emptyObject.isEmpty)
  179. }
  180. }
  181. struct TestFailure: Error {
  182. let message: String
  183. init(_ message: String) {
  184. self.message = message
  185. }
  186. }