defmodule CljElixir.Phase5Test do use ExUnit.Case, async: false # Helper to compile and evaluate CljElixir code defp eval!(source) do case CljElixir.Compiler.eval_string(source) do {:ok, result, _bindings} -> result {:error, errors} -> raise "CljElixir eval error: #{inspect(errors)}" end end # ========================================================================== # GenServer integration # ========================================================================== describe "GenServer - simple counter" do test "define and use a counter GenServer" do eval!(""" (defmodule TestCounter (use GenServer) (defn init [initial] #el[:ok initial]) (defn handle-call ([:get _from state] #el[:reply state state]) ([:increment _from state] #el[:reply :ok (+ state 1)]))) """) {:ok, pid} = GenServer.start_link(TestCounter, 0) assert GenServer.call(pid, :get) == 0 assert GenServer.call(pid, :increment) == :ok assert GenServer.call(pid, :get) == 1 GenServer.stop(pid) end end describe "GenServer - handle_cast" do test "cast resets state" do eval!(""" (defmodule TestCaster (use GenServer) (defn init [initial] #el[:ok initial]) (defn handle-call ([:get _from state] #el[:reply state state])) (defn handle-cast ([:reset _state] #el[:noreply 0]))) """) {:ok, pid} = GenServer.start_link(TestCaster, 42) assert GenServer.call(pid, :get) == 42 GenServer.cast(pid, :reset) Process.sleep(50) assert GenServer.call(pid, :get) == 0 GenServer.stop(pid) end end describe "GenServer - handle_info" do test "handle-info receives plain messages" do eval!(""" (defmodule TestInfoHandler (use GenServer) (defn init [initial] #el[:ok initial]) (defn handle-call ([:get _from state] #el[:reply state state])) (defn handle-info ([:bump state] #el[:noreply (+ state 1)]))) """) {:ok, pid} = GenServer.start_link(TestInfoHandler, 0) send(pid, :bump) Process.sleep(50) assert GenServer.call(pid, :get) == 1 GenServer.stop(pid) end end # ========================================================================== # ChatRoom pattern: spawn + send + receive loop # ========================================================================== describe "ChatRoom pattern" do test "spawn + send + receive loop" do eval!(""" (defmodule TestChatLoop (defn loop [state] (receive [:ping pid] (do (send pid #el[:pong state]) (TestChatLoop/loop (+ state 1))) [:get pid] (do (send pid #el[:count state]) (TestChatLoop/loop state)) :stop :stopped :after 5000 :timeout))) """) pid = spawn(fn -> TestChatLoop.loop(0) end) send(pid, {:ping, self()}) assert_receive {:pong, 0}, 1000 send(pid, {:ping, self()}) assert_receive {:pong, 1}, 1000 send(pid, {:get, self()}) assert_receive {:count, 2}, 1000 send(pid, :stop) Process.sleep(50) refute Process.alive?(pid) end end end