// 独立自检:与 `moon test` 等价的固定语料校验。
//
// Windows 下 `moon test` 可能因嵌套进程限制失败(os error 5),
// 因此这里提供一条不依赖测试框架的校验路径,CI 与本地共用同一份断言。

///|
fn check_hex(name : String, actual : Bytes, expected : String) -> String? {
  let got = @hex.encode(actual)
  if got == expected {
    None
  } else {
    Some("\{name}: expected \{expected}, got \{got}")
  }
}

///|
pub fn run_selftest() -> Array[String] {
  let failures : Array[String] = []
  let cases : Array[(String, Bytes, String)] = [
    (
      "sha256/empty", b"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    ),
    (
      "sha256/abc", b"abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
    ),
    (
      "sha256/two-block", b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
      "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
    ),
  ]
  for case in cases {
    match check_hex(case.0, sha256(case.1), case.2) {
      Some(message) => failures.push(message)
      None => ()
    }
  }
  // 跨实现向量:由 Node/OpenSSL 生成密钥并签名,本项目只负责验签
  let node_spki = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArtwFJjPn9RgRSAFlZlnT" +
    "TNq3VZb5Bg4BXTTrAQ2m8cHz+ygndf9nfLLXRAxiWrGm/sxbYov2Nr7cs9bmrny58Jw0U773rtWrZ" +
    "fKNlpWHA4r/gizPaaULMUSqk9d5Zj9pkWAwdAVQD+A8QH2BM/SQ6sf4OhVKE/q6PCHKwMxSoJc6qd4" +
    "50XqwT44Itj3fzkGPFQe/BSv+8yKxqnEsc2cLXf31zJjPsftK3O++4UXjYHL7Mhs7m7S8JaIPUrRi4" +
    "gf9l0vP/eYc22QYPWZQFQcRNud1ZiYYru3xi0SMvQxUUH59ikE/bSJhm1YZt9QDuhX3nn02wsAeyDF" +
    "vycaCj0niuQIDAQAB"
  let node_sig = "i57bUIntstS+H7+k6zMctOeeIri3KA1gvj+7zuhj+npGlkSiED0nnDnjg4GcCGzAaG7nrj" +
    "BTLhT5O04EWgyqhupI7gNSNLVxqii1XHz1BIsjCWzxAST0I901l5QtsEVF8Lo2PGK8xLv7Fs5OX41l/" +
    "kV90F94oPf609C2M5fNr+P8fvI/N2hvQO3zNX1KXAPWLxSuh7UwhtD1a3hgFP3sJUCLNmN2qwHmCf0w" +
    "JQ94mgrqf5Ny+/7OwwPA0wsGruWaLV8WSzTpHYB3/5oohe90PWUSKk9kiuF1fw/DBJ3sfcTG8fYg6rI" +
    "+ftr/owAspdQIozJye0e3rjHdoHlP4iDgFw=="
  if !rsa_verify_sha256_base64(node_spki, b"mailauth-rsa-vector", node_sig) {
    failures.push("rsa/openssl-vector: valid signature was rejected")
  }
  if rsa_verify_sha256_base64(node_spki, b"mailauth-rsa-vectoX", node_sig) {
    failures.push("rsa/tamper: modified message was accepted")
  }
  // DKIM 跨实现语料:Node/OpenSSL 签名
  let zone = Zone::from_text(dkim_zone_text)
  let good = verify_dkim_all(
    zone,
    parse_message(@utf8.encode(dkim_relaxed_eml)),
    now=1800000000,
  )
  if good.length() != 1 {
    failures.push("dkim/relaxed: expected 1 signature, got \{good.length()}")
  } else if good[0].status != Pass {
    failures.push(
      "dkim/relaxed: expected pass, got \{good[0].status.label()}: \{good[0].reason}",
    )
  }
  let bad_body = verify_dkim_all(
    zone,
    parse_message(@utf8.encode(dkim_tampered_body_eml)),
    now=1800000000,
  )
  if bad_body.length() != 1 || bad_body[0].status != Fail {
    failures.push("dkim/tampered-body: tampered body was not rejected")
  }
  let bad_header = verify_dkim_all(
    zone,
    parse_message(@utf8.encode(dkim_tampered_header_eml)),
    now=1800000000,
  )
  if bad_header.length() != 1 || bad_header[0].status != Fail {
    failures.push("dkim/tampered-header: tampered header was not rejected")
  }
  for failure in run_spf_tests() {
    failures.push(failure)
  }
  for failure in run_dmarc_tests() {
    failures.push(failure)
  }
  failures
}

///|
fn run_spf_tests() -> Array[String] {
  let failures : Array[String] = []
  let zone_text = "example.com TXT v=spf1 ip4:192.0.2.0/24 -all\n" +
    "inc.example.com TXT v=spf1 include:_spf.inc.example.com -all\n" +
    "_spf.inc.example.com TXT v=spf1 ip4:203.0.113.0/24 -all\n" +
    "macro.example.com TXT v=spf1 exists:%{i}.macro.example.com -all\n" +
    "203.0.113.9.macro.example.com A 127.0.0.1\n" +
    "v6.example.com TXT v=spf1 ip6:2001:db8::/32 -all\n" +
    "void.example.com TXT v=spf1 exists:a.void.example.net exists:b.void.example.net exists:c.void.example.net -all\n"
  let zone = Zone::from_text(zone_text)
  let hit = evaluate_spf(zone, "example.com", "192.0.2.5")
  if hit.status != Pass {
    failures.push("spf/ip4-match: expected pass, got \{hit.status.label()}")
  }
  let miss = evaluate_spf(zone, "example.com", "198.51.100.1")
  if miss.status != Fail {
    failures.push("spf/all-fail: expected fail, got \{miss.status.label()}")
  }
  let included = evaluate_spf(zone, "inc.example.com", "203.0.113.9")
  if included.status != Pass {
    failures.push(
      "spf/include: expected pass, got \{included.status.label()}: \{included.reason}",
    )
  }
  let macro = evaluate_spf(zone, "macro.example.com", "203.0.113.9")
  if macro.status != Pass {
    failures.push(
      "spf/macro-exists: expected pass, got \{macro.status.label()}: \{macro.reason}",
    )
  }
  let v6 = evaluate_spf(zone, "v6.example.com", "2001:db8::1")
  if v6.status != Pass {
    failures.push("spf/ip6: expected pass, got \{v6.status.label()}")
  }
  let void_case = evaluate_spf(zone, "void.example.com", "192.0.2.5")
  if void_case.status != PermError {
    failures.push(
      "spf/void-limit: expected permerror, got \{void_case.status.label()}",
    )
  }
  // 10 次 DNS 查询上限
  let lookup_zone = StringBuilder()
  lookup_zone.write_string("too-many.example.com TXT v=spf1")
  for i in 0..<11 {
    lookup_zone.write_string(" include:i\{i}.too-many.example.net")
  }
  lookup_zone.write_string(" -all\n")
  for i in 0..<11 {
    lookup_zone.write_string("i\{i}.too-many.example.net TXT v=spf1 -all\n")
  }
  let limit_zone = Zone::from_text(lookup_zone.to_string())
  let limited = evaluate_spf(limit_zone, "too-many.example.com", "192.0.2.5")
  if limited.status != PermError {
    failures.push(
      "spf/lookup-limit: expected permerror, got \{limited.status.label()}",
    )
  }
  failures
}

///|
fn run_dmarc_tests() -> Array[String] {
  let failures : Array[String] = []
  let zone_text = "_dmarc.example.com TXT v=DMARC1; p=reject; sp=quarantine\n" +
    "_dmarc.strict.example.com TXT v=DMARC1; p=reject; adkim=s\n" +
    "_dmarc.pct.example.com TXT v=DMARC1; p=reject; pct=0\n"
  let zone = Zone::from_text(zone_text)
  let passing : DkimResult = {
    domain: "mail.example.com",
    selector: "test",
    algorithm: "rsa-sha256",
    status: Pass,
    reason: "signature verified",
    evidence: [],
  }
  let relaxed = evaluate_dmarc(zone, "example.com", [passing], None, sample=0)
  if relaxed.status != Pass || !relaxed.dkim_aligned {
    failures.push("dmarc/relaxed-align: expected pass with aligned dkim")
  }
  // strict 对齐:子域签名不应通过
  let strict = evaluate_dmarc(
    zone,
    "strict.example.com",
    [passing],
    None,
    sample=0,
  )
  if strict.status != Fail || strict.disposition != "reject" {
    failures.push("dmarc/strict-align: expected fail with reject disposition")
  }
  // pct=0:策略命中但采样外,处置降为 none
  let sampled = evaluate_dmarc(zone, "pct.example.com", [], None, sample=0)
  if sampled.status != Fail || sampled.disposition != "none" {
    failures.push("dmarc/pct-zero: expected fail with none disposition")
  }
  // 子域策略
  let sub = evaluate_dmarc(zone, "sub.example.com", [], None, sample=0)
  if sub.disposition != "quarantine" {
    failures.push(
      "dmarc/subdomain-policy: expected quarantine, got \{sub.disposition}",
    )
  }
  failures
}

///|
pub fn selftest_case_count() -> Int {
  19
}