defmodule Microwaveprop.CacheTest do
  use ExUnit.Case, async: false

  alias Microwaveprop.Cache

  setup do
    Cache.clear()
    :ok
  end

  describe "fetch_or_store/3" do
    test "invokes the function and returns the value on a cold cache" do
      assert Cache.fetch_or_store(:the_key, 1_000, fn -> 42 end) == 42
    end

    test "returns the cached value without invoking the function on a warm hit" do
      Cache.fetch_or_store(:the_key, 1_000, fn -> 42 end)
      assert Cache.fetch_or_store(:the_key, 1_000, fn -> raise "should not run" end) == 42
    end

    test "re-invokes the function once the TTL expires" do
      Cache.put(:the_key, 1, -1)
      assert Cache.fetch_or_store(:the_key, 1_000, fn -> 2 end) == 2
    end

    test "isolates values by key" do
      assert Cache.fetch_or_store(:a, 1_000, fn -> 1 end) == 1
      assert Cache.fetch_or_store(:b, 1_000, fn -> 2 end) == 2
      assert Cache.fetch_or_store(:a, 1_000, fn -> raise "no" end) == 1
      assert Cache.fetch_or_store(:b, 1_000, fn -> raise "no" end) == 2
    end
  end

  describe "put/3 and invalidate/1" do
    test "put/3 stores a value with the given TTL" do
      Cache.put(:k, "hello", 1_000)
      assert Cache.fetch_or_store(:k, 1_000, fn -> "other" end) == "hello"
    end

    test "invalidate/1 removes an entry, forcing the next fetch to recompute" do
      Cache.put(:k, "stale", 60_000)
      Cache.invalidate(:k)
      assert Cache.fetch_or_store(:k, 1_000, fn -> "fresh" end) == "fresh"
    end
  end
end
