erlang: fib_server.erl, 5/5 classic programs (+8 tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
This commit is contained in:
152
lib/erlang/tests/programs/fib_server.sx
Normal file
152
lib/erlang/tests/programs/fib_server.sx
Normal file
@@ -0,0 +1,152 @@
|
||||
;; Fib server — long-lived process that computes fibonacci numbers on
|
||||
;; request. Tests recursive function evaluation inside a server loop.
|
||||
|
||||
(define er-fib-test-count 0)
|
||||
(define er-fib-test-pass 0)
|
||||
(define er-fib-test-fails (list))
|
||||
|
||||
(define
|
||||
er-fib-test
|
||||
(fn
|
||||
(name actual expected)
|
||||
(set! er-fib-test-count (+ er-fib-test-count 1))
|
||||
(if
|
||||
(= actual expected)
|
||||
(set! er-fib-test-pass (+ er-fib-test-pass 1))
|
||||
(append! er-fib-test-fails {:actual actual :expected expected :name name}))))
|
||||
|
||||
(define fib-ev erlang-eval-ast)
|
||||
|
||||
;; Fib + server-loop source. Standalone so each test can chain queries.
|
||||
(define
|
||||
er-fib-server-src
|
||||
"Fib = fun (0) -> 0; (1) -> 1; (N) -> Fib(N-1) + Fib(N-2) end,
|
||||
FibSrv = fun () ->
|
||||
Loop = fun () ->
|
||||
receive
|
||||
{fib, N, From} -> From ! Fib(N), Loop();
|
||||
stop -> ok
|
||||
end
|
||||
end,
|
||||
Loop()
|
||||
end")
|
||||
|
||||
;; Base cases.
|
||||
(er-fib-test
|
||||
"fib(0)"
|
||||
(fib-ev
|
||||
(str
|
||||
er-fib-server-src
|
||||
", Me = self(),
|
||||
Srv = spawn(FibSrv),
|
||||
Srv ! {fib, 0, Me},
|
||||
receive R -> Srv ! stop, R end"))
|
||||
0)
|
||||
|
||||
(er-fib-test
|
||||
"fib(1)"
|
||||
(fib-ev
|
||||
(str
|
||||
er-fib-server-src
|
||||
", Me = self(),
|
||||
Srv = spawn(FibSrv),
|
||||
Srv ! {fib, 1, Me},
|
||||
receive R -> Srv ! stop, R end"))
|
||||
1)
|
||||
|
||||
;; Larger values.
|
||||
(er-fib-test
|
||||
"fib(10) = 55"
|
||||
(fib-ev
|
||||
(str
|
||||
er-fib-server-src
|
||||
", Me = self(),
|
||||
Srv = spawn(FibSrv),
|
||||
Srv ! {fib, 10, Me},
|
||||
receive R -> Srv ! stop, R end"))
|
||||
55)
|
||||
|
||||
(er-fib-test
|
||||
"fib(15) = 610"
|
||||
(fib-ev
|
||||
(str
|
||||
er-fib-server-src
|
||||
", Me = self(),
|
||||
Srv = spawn(FibSrv),
|
||||
Srv ! {fib, 15, Me},
|
||||
receive R -> Srv ! stop, R end"))
|
||||
610)
|
||||
|
||||
;; Multiple sequential queries to one server. Sum to avoid dict-equality.
|
||||
(er-fib-test
|
||||
"sequential fib(5..8) sum"
|
||||
(fib-ev
|
||||
(str
|
||||
er-fib-server-src
|
||||
", Me = self(),
|
||||
Srv = spawn(FibSrv),
|
||||
Srv ! {fib, 5, Me}, A = receive Ra -> Ra end,
|
||||
Srv ! {fib, 6, Me}, B = receive Rb -> Rb end,
|
||||
Srv ! {fib, 7, Me}, C = receive Rc -> Rc end,
|
||||
Srv ! {fib, 8, Me}, D = receive Rd -> Rd end,
|
||||
Srv ! stop,
|
||||
A + B + C + D"))
|
||||
47)
|
||||
|
||||
;; Verify Fib obeys the recurrence — fib(n) = fib(n-1) + fib(n-2).
|
||||
(er-fib-test
|
||||
"fib recurrence at n=12"
|
||||
(fib-ev
|
||||
(str
|
||||
er-fib-server-src
|
||||
", Me = self(),
|
||||
Srv = spawn(FibSrv),
|
||||
Srv ! {fib, 10, Me}, A = receive Ra -> Ra end,
|
||||
Srv ! {fib, 11, Me}, B = receive Rb -> Rb end,
|
||||
Srv ! {fib, 12, Me}, C = receive Rc -> Rc end,
|
||||
Srv ! stop,
|
||||
C - (A + B)"))
|
||||
0)
|
||||
|
||||
;; Two clients each get their own answer; main sums the results.
|
||||
(er-fib-test
|
||||
"two clients sum"
|
||||
(fib-ev
|
||||
(str
|
||||
er-fib-server-src
|
||||
", Me = self(),
|
||||
Srv = spawn(FibSrv),
|
||||
Client = fun (N) ->
|
||||
spawn(fun () ->
|
||||
Srv ! {fib, N, self()},
|
||||
receive R -> Me ! {result, R} end
|
||||
end)
|
||||
end,
|
||||
Client(7),
|
||||
Client(9),
|
||||
{result, A} = receive M1 -> M1 end,
|
||||
{result, B} = receive M2 -> M2 end,
|
||||
Srv ! stop,
|
||||
A + B"))
|
||||
47)
|
||||
|
||||
;; Trace queries via io-buffer.
|
||||
(er-fib-test
|
||||
"trace fib 0..6"
|
||||
(do
|
||||
(er-io-flush!)
|
||||
(fib-ev
|
||||
(str
|
||||
er-fib-server-src
|
||||
", Me = self(),
|
||||
Srv = spawn(FibSrv),
|
||||
Ask = fun (N) -> Srv ! {fib, N, Me}, receive R -> io:format(\"~p \", [R]) end end,
|
||||
Ask(0), Ask(1), Ask(2), Ask(3), Ask(4), Ask(5), Ask(6),
|
||||
Srv ! stop,
|
||||
done"))
|
||||
(er-io-buffer-content))
|
||||
"0 1 1 2 3 5 8 ")
|
||||
|
||||
(define
|
||||
er-fib-test-summary
|
||||
(str "fib " er-fib-test-pass "/" er-fib-test-count))
|
||||
@@ -74,7 +74,7 @@ Core mapping:
|
||||
- [x] `ping_pong.erl` — two processes exchanging messages — **4 ping-pong tests**
|
||||
- [x] `bank.erl` — account server (deposit/withdraw/balance) — **8 bank tests**
|
||||
- [x] `echo.erl` — minimal server — **7 echo tests**
|
||||
- [ ] `fib_server.erl` — compute fib on request
|
||||
- [x] `fib_server.erl` — compute fib on request — **8 fib tests**
|
||||
- [ ] `lib/erlang/conformance.sh` + runner, `scoreboard.json` + `scoreboard.md`
|
||||
- [ ] Target: 5/5 classic programs + 1M-process ring benchmark runs
|
||||
|
||||
@@ -99,6 +99,7 @@ Core mapping:
|
||||
|
||||
_Newest first._
|
||||
|
||||
- **2026-04-25 fib_server.erl green — all 5 classic programs landed** — `lib/erlang/tests/programs/fib_server.sx` with 8 tests. Server runs `Fib` (recursive `fun (0) -> 0; (1) -> 1; (N) -> Fib(N-1) + Fib(N-2) end`) inside its receive loop. Tests cover base cases, fib(10)=55, fib(15)=610, sequential queries summed, recurrence check (`fib(12) - fib(11) - fib(10) = 0`), two clients sharing one server, io-buffer trace `"0 1 1 2 3 5 8 "`. Total suite 358/358. Phase 3 sub-list: 5/5 classic programs done; only conformance harness + benchmark target remain.
|
||||
- **2026-04-25 echo.erl green** — `lib/erlang/tests/programs/echo.sx` with 7 tests. Server: `receive {From, Msg} -> From ! Msg, Loop(); stop -> ok end`. Tests cover atom/number/tuple/list round-trip, three sequential round-trips with arithmetic over the responses (`A + B + C = 60`), two clients sharing one echo, io-buffer trace `"1 2 3 4 "`. Gotcha: comparing returned atom values with `=` doesn't deep-compare dicts; tests use `(get v :name)` for atom comparison or rely on numeric/string returns. Total suite 350/350.
|
||||
- **2026-04-24 bank.erl green** — `lib/erlang/tests/programs/bank.sx` with 8 tests. Stateful server pattern: `Server = fun (Balance) -> receive ... Server(NewBalance) end end` recursively threads balance through each iteration. Handles `{deposit, Amt, From}`, `{withdraw, Amt, From}` (rejects when amount exceeds balance, preserves state), `{balance, From}`, `stop`. Tests cover deposit accumulation, withdrawal within balance, insufficient funds with state preservation, mixed transactions, clean shutdown, two-client interleave. Total suite 343/343.
|
||||
- **2026-04-24 ping_pong.erl green** — `lib/erlang/tests/programs/ping_pong.sx` with 4 tests: classic Pong server + Ping client with separate `ping_done`/`pong_done` notifications, 5-round trace via io-buffer (`"ppppp"`), main-as-pinger-4-rounds (no intermediate Ping proc), tagged-id round-trip (`"4 3 2 1 "`). All driven by `Ping = fun (Target, K) -> ... Ping(Target, K-1) ... end` self-recursion — captured-env reference works because `Ping` binds in main's mutable env before any spawned body looks it up. Total suite 335/335.
|
||||
|
||||
Reference in New Issue
Block a user