// 真实语料黄金测试:读取 tests/fixtures 下的文件对,对比统计结果。

///|
fn split_char(text : String, separator : Char) -> Array[String] {
  let parts : Array[String] = []
  let buffer = StringBuilder()
  for c in text {
    if c == separator {
      parts.push(buffer.to_string())
      buffer.reset()
    } else {
      buffer.write_char(c)
    }
  }
  parts.push(buffer.to_string())
  parts
}

///|
fn parse_int(raw : String) -> Int? {
  if raw.is_empty() {
    return None
  }
  let mut value = 0
  for c in raw {
    if !c.is_ascii_digit() {
      return None
    }
    value = value * 10 + (c.to_int() - 48)
  }
  Some(value)
}

///|
fn read_text(path : String) -> Result[String, String] {
  Ok(@fs.read_file_to_string(path)) catch { _ => Err("读取失败: \{path}") }
}

///|
fn main {
  let manifest = match read_text("tests/fixtures/manifest.txt") {
    Ok(text) => text
    Err(message) => {
      println(message)
      @sys.exit(2)
      ""
    }
  }
  let failures : Array[String] = []
  let mut total = 0
  for line in split_char(manifest, '\n') {
    if line.trim().is_empty() {
      continue
    }
    let fields = split_char(line.trim().to_owned(), '|')
    if fields.length() != 6 {
      failures.push("manifest 格式错误: \{line}")
      continue
    }
    let old_file = "tests/fixtures/" + fields[0]
    let new_file = "tests/fixtures/" + fields[1]
    let old_text = match read_text(old_file) {
      Ok(text) => text
      Err(message) => {
        failures.push(message)
        ""
      }
    }
    let new_text = match read_text(new_file) {
      Ok(text) => text
      Err(message) => {
        failures.push(message)
        ""
      }
    }
    let expected_added = parse_int(fields[2])
    let expected_removed = parse_int(fields[3])
    let expected_changed = parse_int(fields[4])
    let expected_unchanged = parse_int(fields[5])
    let result = @lib.diff_text(
      old_text,
      new_text,
      @lib.DiffOptions::new(),
    )
    total = total + 1
    match (expected_added, expected_removed, expected_changed, expected_unchanged) {
      (Some(a), Some(r), Some(c), Some(u)) =>
        if result.stats.added != a ||
          result.stats.removed != r ||
          result.stats.changed != c ||
          result.stats.unchanged != u {
          failures.push(
            "\{fields[0]}: expected +\{a} -\{r} ~\{c} =\{u}, got +\{result.stats.added} -\{result.stats.removed} ~\{result.stats.changed} =\{result.stats.unchanged}",
          )
        }
      _ => failures.push("\{fields[0]}: manifest 数字无效")
    }
  }
  if failures.length() == 0 {
    println("golden: \{total} fixtures passed")
    @sys.exit(0)
  } else {
    for failure in failures {
      println("FAIL \{failure}")
    }
    println("golden: \{failures.length()} / \{total} failed")
    @sys.exit(1)
  }
}