;; Go runtime tests — goroutines + channels. (define go-rt-test-count 0) (define go-rt-test-pass 0) (define go-rt-test-fails (list)) (define go-rt-test (fn (name actual expected) (set! go-rt-test-count (+ go-rt-test-count 1)) (if (= actual expected) (set! go-rt-test-pass (+ go-rt-test-pass 1)) (append! go-rt-test-fails {:name name :expected expected :actual actual})))) ;; ── channel primitives (direct API, no source parsing) ───────── (go-rt-test "chan: make returns a chan value" (go-chan? (go-make-chan)) true) (go-rt-test "chan: distinct channels have distinct identity" (= (go-make-chan) (go-make-chan)) false) (go-rt-test "chan: send + recv round-trip" (let ((ch (go-make-chan))) (go-chan-send! ch 42) (go-chan-recv! ch)) 42) (go-rt-test "chan: empty recv returns :empty marker" (let ((ch (go-make-chan))) (go-chan-recv! ch)) :empty) (go-rt-test "chan: FIFO order" (let ((ch (go-make-chan))) (go-chan-send! ch 1) (go-chan-send! ch 2) (go-chan-send! ch 3) (list (go-chan-recv! ch) (go-chan-recv! ch) (go-chan-recv! ch))) (list 1 2 3)) (go-rt-test "chan: closed? flag flips" (let ((ch (go-make-chan))) (let ((before (go-chan-closed? ch))) (go-chan-close! ch) (list before (go-chan-closed? ch)))) (list false true)) ;; ── source-level: make / send / recv / close ─────────────────── (go-rt-test "src: ch := make() returns chan" (go-chan? (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()"))))) (go-env-lookup env "ch"))) true) (go-rt-test "src: ch <- 5 then <-ch = 5" (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()") (go-parse "ch <- 5"))))) (go-eval env (go-parse "<-ch"))) 5) (go-rt-test "src: go + chan ping-pong" (let ((env (go-eval-program go-env-builtins (list (go-parse "func sender(c chan int) { c <- 99 }") (go-parse "ch := make()") (go-parse "go sender(ch)"))))) (go-eval env (go-parse "<-ch"))) 99) (go-rt-test "src: close(ch) marks it closed" (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()") (go-parse "close(ch)"))))) (go-chan-closed? (go-env-lookup env "ch"))) true) (go-rt-test "src: multiple goroutines feeding one channel" (let ((env (go-eval-program go-env-builtins (list (go-parse "func push(c chan int, v int) { c <- v }") (go-parse "ch := make()") (go-parse "go push(ch, 1)") (go-parse "go push(ch, 2)") (go-parse "go push(ch, 3)"))))) (list (go-eval env (go-parse "<-ch")) (go-eval env (go-parse "<-ch")) (go-eval env (go-parse "<-ch")))) (list 1 2 3)) (go-rt-test "src: worker pattern — send sum back" (let ((env (go-eval-program go-env-builtins (list (go-parse "func work(c chan int, a int, b int) { c <- a + b }") (go-parse "result := make()") (go-parse "go work(result, 7, 13)"))))) (go-eval env (go-parse "<-result"))) 20) ;; ── report ───────────────────────────────────────────────────── (go-rt-test "select: default runs when no case is ready" (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()") (go-parse "x := 0") (go-parse "select { case <-ch: x = 1 ; default: x = 99 }"))))) (go-env-lookup env "x")) 99) (go-rt-test "select: recv case fires when ready" (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()") (go-parse "ch <- 7") (go-parse "x := 0") (go-parse "select { case <-ch: x = 1 ; default: x = 99 }"))))) (go-env-lookup env "x")) 1) (go-rt-test "select: recv-into-var binds the value" (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()") (go-parse "ch <- 42") (go-parse "select { case v := <-ch: v }"))))) (go-env-lookup env "v")) 42) (go-rt-test "select: send case (always ready in v0)" (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()") (go-parse "select { case ch <- 5: }"))))) (go-chan-len (go-env-lookup env "ch"))) 1) (go-rt-test "select: picks first ready case" (let ((env (go-eval-program go-env-builtins (list (go-parse "a := make()") (go-parse "b := make()") (go-parse "b <- 100") (go-parse "x := 0") (go-parse "select { case <-a: x = 1 ; case <-b: x = 2 ; default: x = 99 }"))))) (go-env-lookup env "x")) 2) (go-rt-test "select: no default + nothing ready → blocked error" (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()"))))) (go-eval-stmt env (go-parse "select { case <-ch: }") (list))) (list :eval-error :select-blocked-no-default)) (go-rt-test "select: combined with goroutine fan-in" (let ((env (go-eval-program go-env-builtins (list (go-parse "func push(c chan int, v int) { c <- v }") (go-parse "ch := make()") (go-parse "go push(ch, 7)") (go-parse "result := 0") (go-parse "select { case v := <-ch: result = v ; default: result = -1 }"))))) (go-env-lookup env "result")) 7) (go-rt-test "range: slice — sum of 1..5" (let ((env (go-eval-program go-env-builtins (list (go-parse "var sum = 0") (go-parse "a := []int{1, 2, 3, 4, 5}") (go-parse "for i, v := range a { sum = sum + v }"))))) (go-env-lookup env "sum")) 15) (go-rt-test "range: slice — key only (index)" (let ((env (go-eval-program go-env-builtins (list (go-parse "var s = 0") (go-parse "a := []int{10, 20, 30}") (go-parse "for i := range a { s = s + i }"))))) (go-env-lookup env "s")) 3) (go-rt-test "range: map — sum values" (let ((env (go-eval-program go-env-builtins (list (go-parse "var s = 0") (go-parse "m := map[string]int{\"a\": 1, \"b\": 2, \"c\": 3}") (go-parse "for k, v := range m { s = s + v }"))))) (go-env-lookup env "s")) 6) (go-rt-test "range: channel — collect all buffered" (let ((env (go-eval-program go-env-builtins (list (go-parse "ch := make()") (go-parse "ch <- 1") (go-parse "ch <- 2") (go-parse "ch <- 3") (go-parse "var sum = 0") (go-parse "for v := range ch { sum = sum + v }"))))) (go-env-lookup env "sum")) 6) (go-rt-test "range: slice with break exits early" (let ((env (go-eval-program go-env-builtins (list (go-parse "var s = 0") (go-parse "a := []int{1, 2, 3, 4, 5}") (go-parse "for i, v := range a { if v == 3 { break } ; s = s + v }"))))) (go-env-lookup env "s")) 3) (go-rt-test "range: slice with continue skips an element" (let ((env (go-eval-program go-env-builtins (list (go-parse "var s = 0") (go-parse "a := []int{1, 2, 3, 4, 5}") (go-parse "for i, v := range a { if v == 3 { continue } ; s = s + v }"))))) (go-env-lookup env "s")) 12) (go-rt-test "range: empty slice — body never runs" (let ((env (go-eval-program go-env-builtins (list (go-parse "var s = 0") (go-parse "a := []int{}") (go-parse "for v := range a { s = s + v }"))))) (go-env-lookup env "s")) 0) (go-rt-test "range: chan + goroutine producer" (let ((env (go-eval-program go-env-builtins (list (go-parse "func emit(c chan int) { c <- 10 ; c <- 20 ; c <- 30 }") (go-parse "ch := make()") (go-parse "go emit(ch)") (go-parse "var total = 0") (go-parse "for v := range ch { total = total + v }"))))) (go-env-lookup env "total")) 60) (define go-rt-test-summary (str "runtime " go-rt-test-pass "/" go-rt-test-count))