;; Go stdlib tests — exercises lib/go/std/*.sx packages via the
;; idiomatic `import-style` qualified call (`strings.Contains(...)`).

(define go-std-test-count 0)
(define go-std-test-pass 0)
(define go-std-test-fails (list))

(define
  go-std-test
  (fn
    (name actual expected)
    (set! go-std-test-count (+ go-std-test-count 1))
    (if
      (= actual expected)
      (set! go-std-test-pass (+ go-std-test-pass 1))
      (append! go-std-test-fails {:name name :expected expected :actual actual}))))

(define
  go-std-env
  ;; Convenience: env with all stdlib packages registered.
  (go-env-extend
    (go-env-extend go-env-builtins "strings" go-std-strings)
    "strconv" go-std-strconv))

(define
  go-std-run
  ;; Parse + run Go source against the stdlib env; return final env.
  (fn (src-list)
    (go-eval-program go-std-env (map go-parse src-list))))

;; ── strings.Contains ─────────────────────────────────────────────
(go-std-test "strings.Contains: hit"
  (go-env-lookup (go-std-run (list "r := strings.Contains(\"hello world\", \"world\")")) "r")
  true)

(go-std-test "strings.Contains: miss"
  (go-env-lookup (go-std-run (list "r := strings.Contains(\"hello\", \"xyz\")")) "r")
  false)

(go-std-test "strings.Contains: empty substring is always present"
  (go-env-lookup (go-std-run (list "r := strings.Contains(\"abc\", \"\")")) "r")
  true)

;; ── strings.HasPrefix / HasSuffix ────────────────────────────────
(go-std-test "strings.HasPrefix: true"
  (go-env-lookup (go-std-run (list "r := strings.HasPrefix(\"hello world\", \"hello\")")) "r")
  true)

(go-std-test "strings.HasPrefix: false"
  (go-env-lookup (go-std-run (list "r := strings.HasPrefix(\"hello\", \"world\")")) "r")
  false)

(go-std-test "strings.HasSuffix: true"
  (go-env-lookup (go-std-run (list "r := strings.HasSuffix(\"hello world\", \"world\")")) "r")
  true)

(go-std-test "strings.HasSuffix: false"
  (go-env-lookup (go-std-run (list "r := strings.HasSuffix(\"hello\", \"world\")")) "r")
  false)

;; ── strings.Index ─────────────────────────────────────────────────
(go-std-test "strings.Index: found at 6"
  (go-env-lookup (go-std-run (list "r := strings.Index(\"hello world\", \"world\")")) "r")
  6)

(go-std-test "strings.Index: not found = -1"
  (go-env-lookup (go-std-run (list "r := strings.Index(\"hello\", \"xyz\")")) "r")
  -1)

(go-std-test "strings.Index: empty substring = 0"
  (go-env-lookup (go-std-run (list "r := strings.Index(\"abc\", \"\")")) "r")
  0)

;; ── strings.Count ─────────────────────────────────────────────────
(go-std-test "strings.Count: 3 occurrences of 'a'"
  (go-env-lookup (go-std-run (list "r := strings.Count(\"banana\", \"a\")")) "r")
  3)

(go-std-test "strings.Count: 0 occurrences"
  (go-env-lookup (go-std-run (list "r := strings.Count(\"hello\", \"z\")")) "r")
  0)

;; ── strings.Repeat ────────────────────────────────────────────────
(go-std-test "strings.Repeat: ab × 3 = ababab"
  (go-env-lookup (go-std-run (list "r := strings.Repeat(\"ab\", 3)")) "r")
  "ababab")

(go-std-test "strings.Repeat: any × 0 = empty"
  (go-env-lookup (go-std-run (list "r := strings.Repeat(\"x\", 0)")) "r")
  "")

;; ── strings.Join ──────────────────────────────────────────────────
(go-std-test "strings.Join: comma-separated"
  (go-env-lookup (go-std-run (list "r := strings.Join([]string{\"a\", \"b\", \"c\"}, \", \")")) "r")
  "a, b, c")

(go-std-test "strings.Join: empty slice = empty"
  (go-env-lookup (go-std-run (list "r := strings.Join([]string{}, \"-\")")) "r")
  "")

(go-std-test "strings.Join: single elem = elem"
  (go-env-lookup (go-std-run (list "r := strings.Join([]string{\"solo\"}, \",\")")) "r")
  "solo")

;; ── strings.ToUpper / ToLower ─────────────────────────────────────
(go-std-test "strings.ToUpper: hello → HELLO"
  (go-env-lookup (go-std-run (list "r := strings.ToUpper(\"hello\")")) "r")
  "HELLO")

(go-std-test "strings.ToUpper: leaves digits alone"
  (go-env-lookup (go-std-run (list "r := strings.ToUpper(\"abc123\")")) "r")
  "ABC123")

(go-std-test "strings.ToLower: HELLO → hello"
  (go-env-lookup (go-std-run (list "r := strings.ToLower(\"HELLO\")")) "r")
  "hello")

(go-std-test "strings.ToLower: mixed case"
  (go-env-lookup (go-std-run (list "r := strings.ToLower(\"MixED\")")) "r")
  "mixed")

;; ── strings.TrimSpace ─────────────────────────────────────────────
(go-std-test "strings.TrimSpace: leading + trailing"
  (go-env-lookup (go-std-run (list "r := strings.TrimSpace(\"  hello  \")")) "r")
  "hello")

(go-std-test "strings.TrimSpace: no whitespace = noop"
  (go-env-lookup (go-std-run (list "r := strings.TrimSpace(\"abc\")")) "r")
  "abc")

(go-std-test "strings.TrimSpace: all whitespace → empty"
  (go-env-lookup (go-std-run (list "r := strings.TrimSpace(\"   \")")) "r")
  "")

;; ── strings.Split ─────────────────────────────────────────────────
(go-std-test "strings.Split: comma-separated"
  (go-env-lookup (go-std-run (list "r := strings.Split(\"a,b,c\", \",\")")) "r")
  (list :go-slice (list "a" "b" "c")))

(go-std-test "strings.Split: no occurrence → single elem"
  (go-env-lookup (go-std-run (list "r := strings.Split(\"abc\", \"-\")")) "r")
  (list :go-slice (list "abc")))

(go-std-test "strings.Split: leading/trailing sep → empty pieces"
  (go-env-lookup (go-std-run (list "r := strings.Split(\",a,\", \",\")")) "r")
  (list :go-slice (list "" "a" "")))

;; ── strings.Replace ───────────────────────────────────────────────
(go-std-test "strings.Replace: replace once with n=1"
  (go-env-lookup (go-std-run (list "r := strings.Replace(\"a,b,c\", \",\", \"-\", 1)")) "r")
  "a-b,c")

(go-std-test "strings.Replace: replace all with n=-1"
  (go-env-lookup (go-std-run (list "r := strings.Replace(\"a,b,c\", \",\", \"-\", -1)")) "r")
  "a-b-c")

(go-std-test "strings.Replace: no match = noop"
  (go-env-lookup (go-std-run (list "r := strings.Replace(\"abc\", \"x\", \"y\", -1)")) "r")
  "abc")

;; ── strconv.Itoa ─────────────────────────────────────────────────
(go-std-test "strconv.Itoa: 42 → \"42\""
  (go-env-lookup (go-std-run (list "r := strconv.Itoa(42)")) "r")
  "42")

(go-std-test "strconv.Itoa: 0 → \"0\""
  (go-env-lookup (go-std-run (list "r := strconv.Itoa(0)")) "r")
  "0")

;; ── strconv.Atoi ─────────────────────────────────────────────────
(go-std-test "strconv.Atoi: \"42\" → 42"
  (go-env-lookup (go-std-run (list "r := strconv.Atoi(\"42\")")) "r")
  42)

(go-std-test "strconv.Atoi: \"-7\" → -7"
  (go-env-lookup (go-std-run (list "r := strconv.Atoi(\"-7\")")) "r")
  -7)

(go-std-test "strconv.Atoi: \"100\" → 100"
  (go-env-lookup (go-std-run (list "r := strconv.Atoi(\"100\")")) "r")
  100)

(go-std-test "round-trip: Atoi(Itoa(n)) → n positive"
  (go-env-lookup (go-std-run (list "r := strconv.Atoi(strconv.Itoa(12345))")) "r")
  12345)

(go-std-test "round-trip: Atoi(Itoa(n)) → n negative"
  (go-env-lookup (go-std-run (list "r := strconv.Atoi(strconv.Itoa(-9999))")) "r")
  -9999)

(go-std-test "strings: Pipeline ToUpper(TrimSpace(s))"
  (go-env-lookup (go-std-run (list "r := strings.ToUpper(strings.TrimSpace(\"  go  \"))")) "r")
  "GO")

(go-std-test "strings: Join(Split(s, sep), sep) round-trip"
  (go-env-lookup (go-std-run (list "r := strings.Join(strings.Split(\"a,b,c\", \",\"), \",\")")) "r")
  "a,b,c")

(go-std-test "strings: Count(Repeat(s, n), s) == n"
  (go-env-lookup (go-std-run (list "r := strings.Count(strings.Repeat(\"ab\", 5), \"ab\")")) "r")
  5)

(go-std-test "round-trip: Itoa(Atoi(s)) → s"
  (go-env-lookup (go-std-run (list "r := strconv.Itoa(strconv.Atoi(\"777\"))")) "r")
  "777")

(define
  go-std-test-summary
  (str "stdlib " go-std-test-pass "/" go-std-test-count))
