defmodule Beaker.GaugeTest do
  use ExUnit.Case
  doctest Beaker.Gauge

  alias Beaker.Gauge

  setup do
    on_exit fn ->
      Gauge.clear
    end
  end

  test "Gauge.all returns an empty map if there are no gauges" do
    assert Gauge.all == %{}
  end

  test "Gauge.all returns a map with all gauges and values" do
    Gauge.set("all1", 5, 0, 100)
    Gauge.set("all2", 2, 0, 100)
    assert Gauge.all == %{"all1" => %{max: 100, min: 0, name: "all1", value: 5},
                          "all2" => %{max: 100, min: 0, name: "all2", value: 2}}
  end

  test "Gauge.clear returns :ok and erases all gauges" do
    :ok = Gauge.set("clear1", 5, 0, 100)
    :ok = Gauge.set("clear2", 2, 0, 100)
    refute Gauge.all |> Enum.empty?
    Gauge.clear
    assert Gauge.all |> Enum.empty?
  end

  test "Gauge.clear(key) returns :ok and clears the specified gauge" do
    :ok = Gauge.set("clear1", 5, 0, 100)
    :ok = Gauge.set("clear2", 2, 0, 100)
    assert Gauge.all |> Map.keys |> Enum.member?("clear1")
    assert Gauge.all |> Map.keys |> Enum.member?("clear2")
    Gauge.clear("clear1")
    refute Gauge.all |> Map.keys |> Enum.member?("clear1")
    assert Gauge.all |> Map.keys |> Enum.member?("clear2")
  end

  test "Gauge.get(key) returns nil if name is not yet registered as a gauge" do
    assert Gauge.get("non-existent") == nil
  end

  test "Gauge.get(key) returns the stored value in the gauge" do
    Gauge.set("get", 50, 0, 100)
    assert Gauge.get("get") == %{max: 100, min: 0, name: "get", value: 50}
  end

  test "Gauge.set(key, value) sets the gauge to the value" do
    key = "set"
    assert Gauge.get(key) == nil
    Gauge.set(key, 10, 0, 100)
    assert Gauge.get(key) == %{max: 100, min: 0, name: "set", value: 10}
    Gauge.set(key, 2, 0, 100)
    assert Gauge.get(key) == %{max: 100, min: 0, name: "set", value: 2}
  end

  test "Gauge.set(key, value) accepts floats" do
    key = "set_float"
    Gauge.set(key, 3.14159, 0, 100)
    assert Gauge.get(key) == %{max: 100, min: 0, name: "set_float", value: 3.14159}
  end

  test "Gauge.time(key, fn -> :timer.sleep(500); :slept end) should set the gauge of the key to > 500 and return the value :slept" do
    key = "time_sleep"
    value = Gauge.time(key, fn -> :timer.sleep(50); :slept end)
    assert Gauge.get(key) > 50000 # :timer.tc returns in microseconds
    assert value == :slept
  end

  test "Gauge.time(key, [do: block]) alternative syntax works" do
    key = "time_sleep"
    value = Gauge.time(key) do
      :timer.sleep(50)
      :slept
    end

    assert Gauge.get(key) > 50000 # :timer.tc returns in microseconds
    assert value == :slept
  end

  test "Gauges can have a min max property" do
    key = "with_min_max"
    value = 50
    Gauge.set(key, value, 0, 100)
    response = Gauge.get(key)

    assert response.min == 0
    assert response.max == 100
  end
end
