///|
test "serializer emits fixed standard member order" {
  let p = unwrap_problem(
    "{\"instance\":\"/i\",\"detail\":\"D\",\"status\":400,\"title\":\"T\",\"type\":\"urn:x\"}",
  )
  assert_str_eq(
    serialize_problem(p),
    "{\"type\":\"urn:x\",\"title\":\"T\",\"status\":400,\"detail\":\"D\",\"instance\":\"/i\"}",
  )
}

///|
test "serializer sorts extensions lexically" {
  assert_str_eq(
    serialize_problem(unwrap_problem("{\"z\":1,\"a\":2}")),
    "{\"a\":2,\"z\":1}",
  )
}

///|
test "serializer does not synthesize about blank" {
  assert_str_eq(serialize_problem(unwrap_problem("{}")), "{}")
}

///|
test "serializer escapes strings through core json" {
  assert_str_eq(
    serialize_problem(unwrap_problem("{\"title\":\"a\\nb\\\"c\"}")),
    "{\"title\":\"a\\nb\\\"c\"}",
  )
}

///|
test "serializer preserves extension number" {
  assert_str_eq(
    serialize_problem(unwrap_problem("{\"x\":12.5}")),
    "{\"x\":12.5}",
  )
}

///|
test "serializer preserves extension null" {
  assert_str_eq(
    serialize_problem(unwrap_problem("{\"x\":null}")),
    "{\"x\":null}",
  )
}

///|
test "serializer preserves extension array" {
  assert_str_eq(
    serialize_problem(unwrap_problem("{\"x\":[1,true,null]}")),
    "{\"x\":[1,true,null]}",
  )
}

///|
test "canonicalization is idempotent" {
  let first = canonicalize_problem_json("{\"z\":1,\"title\":\"T\"}").unwrap()
  assert_str_eq(canonicalize_problem_json(first).unwrap(), first)
}

///|
test "semantic roundtrip includes nested extension values" {
  let p = unwrap_problem("{\"meta\":{\"a\":[1,false,null]},\"status\":422}")
  assert_true(unwrap_problem(serialize_problem(p)) == p)
}

///|
test "canonicalization reports errors" {
  assert_true(canonicalize_problem_json("[") is Err(_))
}