Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
160 lines
4.2 KiB
Plaintext
160 lines
4.2 KiB
Plaintext
;; Bank account server — stateful process, balance threaded through
|
|
;; recursive loop. Handles {deposit, Amt, From}, {withdraw, Amt, From},
|
|
;; {balance, From}, stop. Tests stateful process patterns.
|
|
|
|
(define er-bank-test-count 0)
|
|
(define er-bank-test-pass 0)
|
|
(define er-bank-test-fails (list))
|
|
|
|
(define
|
|
er-bank-test
|
|
(fn
|
|
(name actual expected)
|
|
(set! er-bank-test-count (+ er-bank-test-count 1))
|
|
(if
|
|
(= actual expected)
|
|
(set! er-bank-test-pass (+ er-bank-test-pass 1))
|
|
(append! er-bank-test-fails {:actual actual :expected expected :name name}))))
|
|
|
|
(define bank-ev erlang-eval-ast)
|
|
|
|
;; Server fun shared by all tests — threaded via the program string.
|
|
(define
|
|
er-bank-server-src
|
|
"Server = fun (Balance) ->
|
|
receive
|
|
{deposit, Amt, From} -> From ! ok, Server(Balance + Amt);
|
|
{withdraw, Amt, From} ->
|
|
if Amt > Balance -> From ! insufficient, Server(Balance);
|
|
true -> From ! ok, Server(Balance - Amt)
|
|
end;
|
|
{balance, From} -> From ! Balance, Server(Balance);
|
|
stop -> ok
|
|
end
|
|
end")
|
|
|
|
;; Open account, deposit, check balance.
|
|
(er-bank-test
|
|
"deposit 100 -> balance 100"
|
|
(bank-ev
|
|
(str
|
|
er-bank-server-src
|
|
", Me = self(),
|
|
Bank = spawn(fun () -> Server(0) end),
|
|
Bank ! {deposit, 100, Me},
|
|
receive ok -> ok end,
|
|
Bank ! {balance, Me},
|
|
receive B -> Bank ! stop, B end"))
|
|
100)
|
|
|
|
;; Multiple deposits accumulate.
|
|
(er-bank-test
|
|
"deposits accumulate"
|
|
(bank-ev
|
|
(str
|
|
er-bank-server-src
|
|
", Me = self(),
|
|
Bank = spawn(fun () -> Server(0) end),
|
|
Bank ! {deposit, 50, Me}, receive ok -> ok end,
|
|
Bank ! {deposit, 25, Me}, receive ok -> ok end,
|
|
Bank ! {deposit, 10, Me}, receive ok -> ok end,
|
|
Bank ! {balance, Me},
|
|
receive B -> Bank ! stop, B end"))
|
|
85)
|
|
|
|
;; Withdraw within balance succeeds; insufficient gets rejected.
|
|
(er-bank-test
|
|
"withdraw within balance"
|
|
(bank-ev
|
|
(str
|
|
er-bank-server-src
|
|
", Me = self(),
|
|
Bank = spawn(fun () -> Server(100) end),
|
|
Bank ! {withdraw, 30, Me}, receive ok -> ok end,
|
|
Bank ! {balance, Me},
|
|
receive B -> Bank ! stop, B end"))
|
|
70)
|
|
|
|
(er-bank-test
|
|
"withdraw insufficient"
|
|
(get
|
|
(bank-ev
|
|
(str
|
|
er-bank-server-src
|
|
", Me = self(),
|
|
Bank = spawn(fun () -> Server(20) end),
|
|
Bank ! {withdraw, 100, Me},
|
|
receive R -> Bank ! stop, R end"))
|
|
:name)
|
|
"insufficient")
|
|
|
|
;; State preserved across an insufficient withdrawal.
|
|
(er-bank-test
|
|
"state preserved on rejection"
|
|
(bank-ev
|
|
(str
|
|
er-bank-server-src
|
|
", Me = self(),
|
|
Bank = spawn(fun () -> Server(50) end),
|
|
Bank ! {withdraw, 1000, Me}, receive _ -> ok end,
|
|
Bank ! {balance, Me},
|
|
receive B -> Bank ! stop, B end"))
|
|
50)
|
|
|
|
;; Mixed deposits and withdrawals.
|
|
(er-bank-test
|
|
"mixed transactions"
|
|
(bank-ev
|
|
(str
|
|
er-bank-server-src
|
|
", Me = self(),
|
|
Bank = spawn(fun () -> Server(100) end),
|
|
Bank ! {deposit, 50, Me}, receive ok -> ok end,
|
|
Bank ! {withdraw, 30, Me}, receive ok -> ok end,
|
|
Bank ! {deposit, 10, Me}, receive ok -> ok end,
|
|
Bank ! {withdraw, 5, Me}, receive ok -> ok end,
|
|
Bank ! {balance, Me},
|
|
receive B -> Bank ! stop, B end"))
|
|
125)
|
|
|
|
;; Server.stop terminates the bank cleanly — main can verify by
|
|
;; sending stop and then exiting normally.
|
|
(er-bank-test
|
|
"server stops cleanly"
|
|
(get
|
|
(bank-ev
|
|
(str
|
|
er-bank-server-src
|
|
", Me = self(),
|
|
Bank = spawn(fun () -> Server(0) end),
|
|
Bank ! stop,
|
|
done"))
|
|
:name)
|
|
"done")
|
|
|
|
;; Two clients sharing one bank — interleaved transactions.
|
|
(er-bank-test
|
|
"two clients share bank"
|
|
(bank-ev
|
|
(str
|
|
er-bank-server-src
|
|
", Me = self(),
|
|
Bank = spawn(fun () -> Server(0) end),
|
|
Client = fun (Amt) ->
|
|
spawn(fun () ->
|
|
Bank ! {deposit, Amt, self()},
|
|
receive ok -> Me ! deposited end
|
|
end)
|
|
end,
|
|
Client(40),
|
|
Client(60),
|
|
receive deposited -> ok end,
|
|
receive deposited -> ok end,
|
|
Bank ! {balance, Me},
|
|
receive B -> Bank ! stop, B end"))
|
|
100)
|
|
|
|
(define
|
|
er-bank-test-summary
|
|
(str "bank " er-bank-test-pass "/" er-bank-test-count))
|