defmodule VMTest do use ExUnit.Case doctest Day5 def run(prog, io \\ []) do parent = self() pid = spawn(fn -> Day5.run(prog, parent) end) handle_io(pid, io) receive do {:halt, ^pid, memory} -> {:halt, memory} {:ok, ^pid, memory} -> {:ok, memory} msg -> IO.inspect(msg) end end def handle_io(_, []), do: :ok def handle_io(pid, [head | rest]) do case head do {:in, input} -> receive do {:in, ^pid} -> send(pid, {:in, input}) end {:out, expected} -> receive do {:out, ^pid, output} -> assert output == expected end end handle_io(pid, rest) end test "exits" do assert run([]) == {:ok, []} end test "halts" do assert run([99]) == {:halt, [99]} end test "basic position mode instructions" do assert run([1, 3, 2, 3]) == {:ok, [1, 3, 2, 5]} assert run([2, 3, 2, 3]) == {:ok, [2, 3, 2, 6]} end test "basic immediate mode instructions" do assert run([1101, 1, 2, 0]) == {:ok, [3, 1, 2, 0]} assert run([1102, 4, 2, 0]) == {:ok, [8, 4, 2, 0]} end test "receives input" do assert run([3, 1], in: 1234) == {:ok, [3, 1234]} end test "produces output" do assert run([104, 77], out: 77) == {:ok, [104, 77]} assert run([4, 0], out: 4) == {:ok, [4, 0]} end test "jump if non-zero" do prog = [1105, 1, 4, 99, 1101, 1, 2, 7] assert run(prog) == {:ok, List.replace_at(prog, 7, 3)} prog = [1105, 0, 4, 99, 1101, 1, 2, 7] assert run(prog) == {:halt, prog} prog = [1005, 0, 4, 99, 1101, 1, 2, 7] assert run(prog) == {:ok, List.replace_at(prog, 7, 3)} prog = [5, 0, 9, 99, 1101, 1, 2, 7, 99, 4] assert run(prog) == {:halt, List.replace_at(prog, 7, 3)} end test "jump if zero" do prog = [1106, 0, 4, 99, 1101, 1, 2, 7] assert run(prog) == {:ok, List.replace_at(prog, 7, 3)} prog = [1106, 42, 4, 99, 1101, 1, 2, 7] assert run(prog) == {:halt, prog} prog = [1006, 9, 4, 99, 1101, 1, 2, 7, 99, 0] assert run(prog) == {:halt, List.replace_at(prog, 7, 3)} prog = [6, 9, 10, 99, 1101, 1, 2, 7, 99, 0, 4] assert run(prog) == {:halt, List.replace_at(prog, 7, 3)} end test "compare less than" do prog = [1107, 3, 8, 3] assert run(prog) == {:ok, List.replace_at(prog, 3, 1)} prog = [1107, 12, 8, 3] assert run(prog) == {:ok, List.replace_at(prog, 3, 0)} prog = [1007, 3, 8, 3] assert run(prog) == {:ok, List.replace_at(prog, 3, 1)} prog = [7, 3, 0, 3] assert run(prog) == {:ok, List.replace_at(prog, 3, 1)} end test "compare equal to" do prog = [1108, 4, 4, 3] assert run(prog) == {:ok, List.replace_at(prog, 3, 1)} prog = [1108, 5, 4, 3] assert run(prog) == {:ok, List.replace_at(prog, 3, 0)} prog = [1008, 0, 1008, 3] assert run(prog) == {:ok, List.replace_at(prog, 3, 1)} prog = [8, 2, 2, 3] assert run(prog) == {:ok, List.replace_at(prog, 3, 1)} end end