import Foundation
import Testing
@testable import IrdP2PCrypto
@Suite struct JSONValueTests {
@Test func serializesLikeJSONStringify() {
let v: JSONValue = .object(JSONObject([("t", .string("hi")), ("nick", .string("gazda")), ("score", .int(0)), ("live", .bool(true)), ("x", .null)]))
#expect(v.serialized == #"{"t":"hi","nick":"gazda","score":0,"live":true,"x":null}"#)
}
@Test func preservesInsertionOrderNotSorting() {
let v: JSONValue = .object(JSONObject([("z", .int(1)), ("a", .int(2))]))
#expect(v.serialized == #"{"z":1,"a":2}"#)
}
@Test func numbersFormatLikeJavaScript() {
#expect(JSONValue.number(0).serialized == "0")
#expect(JSONValue.number(-0.0).serialized == "0")
#expect(JSONValue.number(1).serialized == "1")
#expect(JSONValue.number(-42).serialized == "-42")
#expect(JSONValue.number(1.5).serialized == "1.5")
#expect(JSONValue.number(0.1).serialized == "0.1")
#expect(JSONValue.number(1e21).serialized == "1e+21")
#expect(JSONValue.number(1e-7).serialized == "1e-7")
#expect(JSONValue.number(9007199254740992).serialized == "9007199254740992")
#expect(JSONValue.number(.nan).serialized == "null")
#expect(JSONValue.number(.infinity).serialized == "null")
}
@Test func stringsEscapeLikeJavaScript() {
#expect(JSONValue.string("a\"b\\c\n\t\u{08}\u{0C}\r\u{01}").serialized == #""a\"b\\c\n\t\b\f\r\u0001""#)
#expect(JSONValue.string("ăîșț 🐢 / \u{2028}").serialized == "\"ăîșț 🐢 / \u{2028}\"")
}
@Test func parsesAndRoundTripsPreservingOrder() throws {
let text = #"{"kind":"msg","payload":{"t":"chat","text":"salut","n":[1,2.5,-3e2,true,null]},"z":{}}"#
let v = try JSONValue.parse(text)
#expect(v.serialized == #"{"kind":"msg","payload":{"t":"chat","text":"salut","n":[1,2.5,-300,true,null]},"z":{}}"#)
#expect(v["payload"]?["text"]?.stringValue == "salut")
#expect(v["payload"]?["n"]?.arrayValue?.count == 5)
}
@Test func parsesEscapesAndSurrogates() throws {
let v = try JSONValue.parse(#""\u00e9\ud83d\udc22\n\/""#)
#expect(v.stringValue == "é🐢\n/")
}
@Test func objectEqualityIgnoresOrder() {
let a: JSONValue = .object(JSONObject([("a", .int(1)), ("b", .int(2))]))
let b: JSONValue = .object(JSONObject([("b", .int(2)), ("a", .int(1))]))
#expect(a == b)
#expect(a.serialized != b.serialized)
}
@Test func rejectsMalformed() {
for bad in ["", "{", "[1,]", "{\"a\":}", "tru", "\"unterminated", "01", "1.", "{\"a\":1}x", "\"\\ud83d\""] {
#expect(throws: JSONValue.ParseError.self) { try JSONValue.parse(bad) }
}
}
@Test func codableBridge() throws {
struct Line: Codable, Equatable { var text: String; var n: Int }
let v = try JSONValue(encoding: Line(text: "x", n: 3))
#expect(v["text"]?.stringValue == "x")
let line = try v.decode(Line.self)
#expect(line == Line(text: "x", n: 3))
}
}