farmbot_os/farmbot_celery_script/test/farmbot_celery_script/run_time/instruction_set_test.exs

192 lines
5.0 KiB
Elixir

defmodule Farmbot.CeleryScript.RunTime.InstructionTest do
alias Farmbot.CeleryScript.RunTime.FarmProc
alias Farmbot.CeleryScript.AST
defmacro io_test(kind) do
kind_atom = String.to_atom(kind)
quote do
test unquote(kind) do
pid = self()
fun = fn ast ->
send(pid, ast)
:ok
end
heap =
AST.new(unquote(kind_atom), %{}, [])
|> AST.slice()
step0 = FarmProc.new(fun, addr(0), heap)
step1 = FarmProc.step(step0)
assert FarmProc.get_status(step1) == :waiting
step2 = FarmProc.step(step1)
assert FarmProc.get_status(step2) == :done
assert_received %AST{kind: unquote(kind_atom), args: %{}}
end
end
end
end
defmodule Farmbot.CeleryScript.RunTime.InstructionSetTest do
use ExUnit.Case
alias Farmbot.CeleryScript.RunTime.{FarmProc, Error}
import Farmbot.CeleryScript.RunTime.InstructionTest
import Farmbot.CeleryScript.Utils
alias Farmbot.CeleryScript.AST
@fixture AST.decode(%{
kind: :_if,
args: %{
lhs: :x,
op: "is",
rhs: 10,
_then: %{kind: :nothing, args: %{}},
_else: %{kind: :nothing, args: %{}}
}
})
io_test("write_pin")
io_test("read_pin")
io_test("set_servo_angle")
io_test("send_message")
io_test("move_relative")
io_test("home")
io_test("find_home")
io_test("wait")
io_test("toggle_pin")
io_test("execute_script")
io_test("zero")
io_test("calibrate")
io_test("take_photo")
io_test("config_update")
io_test("set_user_env")
io_test("install_first_party_farmware")
io_test("install_farmware")
io_test("uninstall_farmware")
io_test("update_farmware")
io_test("read_status")
io_test("sync")
io_test("power_off")
io_test("reboot")
io_test("factory_reset")
io_test("change_ownership")
io_test("check_updates")
io_test("dump_info")
test "nothing returns or sets status" do
seq_1 =
AST.new(:sequence, %{}, [
AST.new(:execute, %{sequence_id: 2}, []),
AST.new(:wait, %{milliseconds: 10}, [])
])
seq_2 = AST.new(:sequence, %{}, [AST.new(:execute, %{sequence_id: 3}, [])])
seq_3 = AST.new(:sequence, %{}, [AST.new(:wait, %{milliseconds: 10}, [])])
pid = self()
fun = fn ast ->
case ast do
%{kind: :execute, args: %{sequence_id: 2}} ->
send(pid, {:execute, 2})
{:ok, seq_2}
%{kind: :execute, args: %{sequence_id: 3}} ->
send(pid, {:execute, 3})
{:ok, seq_3}
%{kind: :wait} ->
send(pid, :wait)
:ok
end
end
proc0 = FarmProc.new(fun, addr(1), AST.slice(seq_1))
complete =
Enum.reduce(0..100, proc0, fn _, proc ->
FarmProc.step(proc)
end)
assert FarmProc.get_status(complete) == :done
assert_received {:execute, 2}
assert_received {:execute, 3}
# we only want to execute those sequences once.
refute_receive {:execute, 2}
refute_receive {:execute, 3}
# Execute wait twice.
assert_received :wait
assert_received :wait
refute_receive :wait
end
test "Sets the correct `crash_reason`" do
fun = fn _ -> {:error, "whatever"} end
heap = AST.slice(@fixture)
farm_proc = FarmProc.new(fun, Address.new(1), heap)
waiting = FarmProc.step(farm_proc)
assert FarmProc.get_status(waiting) == :waiting
crashed = FarmProc.step(waiting)
assert FarmProc.get_status(crashed) == :crashed
assert FarmProc.get_crash_reason(crashed) == "whatever"
end
test "_if handles bad interaction layer implementations" do
fun = fn _ -> :ok end
heap = AST.slice(@fixture)
farm_proc = FarmProc.new(fun, Address.new(1), heap)
assert_raise Error, "Bad _if implementation.", fn ->
%{status: :waiting} = farm_proc = FarmProc.step(farm_proc)
FarmProc.step(farm_proc)
end
end
test "move absolute bad implementation" do
zero00 = AST.new(:location, %{x: 0, y: 0, z: 0}, [])
fun = fn _ -> :blah end
heap =
AST.new(:move_absolute, %{location: zero00, offset: zero00}, [])
|> AST.slice()
proc = FarmProc.new(fun, Address.new(0), heap)
assert_raise(Error, "Bad return value handling move_absolute IO: :blah", fn ->
Enum.reduce(0..100, proc, fn _num, acc ->
FarmProc.step(acc)
end)
end)
fun2 = fn _ -> {:error, "whatever"} end
proc2 = FarmProc.new(fun2, Address.new(0), heap)
result =
Enum.reduce(0..1, proc2, fn _num, acc ->
FarmProc.step(acc)
end)
assert(FarmProc.get_status(result) == :crashed)
assert(FarmProc.get_crash_reason(result) == "whatever")
end
test "execute handles bad interaction layer implementation." do
fun = fn _ -> {:ok, :not_ast} end
ast = AST.new(:execute, %{sequence_id: 100}, [])
heap = AST.slice(ast)
farm_proc = FarmProc.new(fun, Address.new(1), heap)
assert_raise Error, "Bad execute implementation.", fn ->
%{status: :waiting} = farm_proc = FarmProc.step(farm_proc)
FarmProc.step(farm_proc)
end
end
end