4.1 KiB · text History 9c0fc16
defmodule LambentExWeb.MachinesTest do
  use LambentExWeb.ConnCase

  import Phoenix.LiveViewTest

  alias LambentEx.Machine
  alias LambentEx.MachineSupervisor

  defp start(name, opts \\ []) do
    {:ok, _pid} =
      MachineSupervisor.start_child(
        LambentEx.Machine.Steps.Solid,
        %{h: 0},
        name,
        [single: true] ++ opts
      )

    on_exit(fn -> Machine.quit(name) end)
  end

  # the page lists a machine once it has published
  defp listed(conn, name) do
    Phoenix.PubSub.subscribe(LambentEx.PubSub, "machines_idx")
    assert_receive {:machines_pub, %{name: ^name}}, 1000
    {:ok, live, _html} = live(conn, "/cfg/machines")
    assert_receive {:machines_pub, %{name: ^name}}, 1000
    assert render(live) =~ name
    live
  end

  test "deleting a machine stops it and takes it off the page", %{conn: conn} do
    start("machines-test-del")
    live = listed(conn, "machines-test-del")

    render_click(live, "quit", %{"tgt" => "machines-test-del"})

    refute Machine.running?("machines-test-del")
    refute render(live) =~ "machines-test-del"
  end

  test "other pages hear that a machine is gone", %{conn: conn} do
    start("machines-test-other")
    live = listed(conn, "machines-test-other")

    # quit from somewhere else: the app, a schedule
    Machine.quit("machines-test-other")

    refute render(live) =~ "machines-test-other"
  end

  test "a deleted machine that was kept is not brought back on restart" do
    start("machines-test-kept", persist: true)
    Phoenix.PubSub.subscribe(LambentEx.PubSub, "machines_idx")
    assert_receive {:machines_pub, %{name: "machines-test-kept"}}, 1000

    # what Meta flushes every 5s, written straight away for the test
    :dets.insert(:lex_metadata, {"machs", :sys.get_state(LambentEx.Meta).machines})

    assert LambentEx.Meta.get_saved_machines()
           |> Enum.any?(fn m -> m[:name] == "machines-test-kept" end)

    Machine.quit("machines-test-kept")
    # Meta takes the news in its own time; a call behind it waits for that
    :sys.get_state(LambentEx.Meta)

    refute LambentEx.Meta.get_saved_machines()
           |> Enum.any?(fn m -> m[:name] == "machines-test-kept" end)

    refute :sys.get_state(LambentEx.Meta).machines
           |> Enum.any?(fn m -> m[:name] == "machines-test-kept" end)
  end

  test "dimming lands within a tick or two, even on a slow machine", %{conn: conn} do
    start("machines-test-dim", speed: 1000)
    live = listed(conn, "machines-test-dim")

    render_click(live, "dimmer", %{"id" => "machines-test-dim"})
    assert Machine.info("machines-test-dim").bgtt < 255

    Process.sleep(2100)
    info = Machine.info("machines-test-dim")
    assert info.bgt == info.bgtt
  end

  test "speed buttons move the machine's tick", %{conn: conn} do
    start("machines-test-speed", speed: 1000)
    live = listed(conn, "machines-test-speed")

    render_click(live, "slower", %{"id" => "machines-test-speed"})
    assert Machine.info("machines-test-speed").speed == 2000

    render_click(live, "faster", %{"id" => "machines-test-speed"})
    render_click(live, "faster", %{"id" => "machines-test-speed"})
    assert Machine.info("machines-test-speed").speed == 500
  end

  test "a catalog entry is started from the library", %{conn: conn} do
    on_exit(fn -> Machine.quit("red") end)
    {:ok, live, _html} = live(conn, "/cfg/machines")

    render_click(live, "library-add", %{"cls" => "solid", "entry" => "red"})

    assert Machine.running?("red")
  end

  test "an entry not in the catalog is ignored, and makes no atoms", %{conn: conn} do
    {:ok, live, _html} = live(conn, "/cfg/machines")
    cls = "no-such-class-#{System.unique_integer([:positive])}"
    entry = "no-such-entry-#{System.unique_integer([:positive])}"

    render_click(live, "library-add", %{"cls" => cls, "entry" => entry})
    render_click(live, "library-add", %{"cls" => "solid", "entry" => entry})

    # a crash in the handler would have taken the page, and this test, down
    assert render(live)
    refute Machine.running?(entry)
    assert_raise ArgumentError, fn -> String.to_existing_atom(cls) end
    assert_raise ArgumentError, fn -> String.to_existing_atom(entry) end
  end
end