From 7f28addd752d7c866d69beaf6f5489a69606d12f Mon Sep 17 00:00:00 2001 From: BobbieBarker <4307099+BobbieBarker@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:40:41 -0700 Subject: [PATCH] feat: support Elixir 1.20 Add Elixir 1.20 compatibility and clear the new compiler/type-system warnings under `--warnings-as-errors`: - Cache.__using__: emit a single adapter_options!/1 clause per adapter shape so the catch-all is never a dead clause, and drop the now-dead `{:error, _}` branches in generated get/1 (handle_adapter_result is typed to never return an error for non-erroring adapters). - Cache.ETS: remove module-level `require Cache.OTPVersion` (only used inside __using__, which requires it itself). - mix.exs: move :preferred_cli_env into `def cli`, bump elixir to ~> 1.15. Update the test toolchain for 1.20: - Bump :credo 1.7.13 -> 1.7.18; 1.7.13 crashes on 1.20's new sigil token format. The newer Credo surfaced one expensive `length/1 > 0` check, rewritten as `!== []`. - Drop the unmaintained :faker test dependency, which fails to compile on 1.20 (raw U+0085 byte is now a hard syntax error). It was only used for three random-string helpers; replaced with a small test/support module. Co-Authored-By: Claude Opus 4.8 (1M context) --- .tool-versions | 2 +- lib/cache.ex | 80 +++++++++++++++++----------------- lib/cache/ets.ex | 1 - mix.exs | 18 +++++--- mix.lock | 5 +-- test/cache/con_cache_test.exs | 6 +-- test/cache/redis_hash_test.exs | 2 +- test/cache_strategy_test.exs | 34 +++++++-------- test/cache_test.exs | 10 ++--- test/support/gen.ex | 17 ++++++++ 10 files changed, 100 insertions(+), 75 deletions(-) create mode 100644 test/support/gen.ex diff --git a/.tool-versions b/.tool-versions index 30d9cfb..da25f5c 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -elixir 1.18.4-otp-28 +elixir 1.20.0-otp-28 erlang 28.0.2 diff --git a/lib/cache.ex b/lib/cache.ex index 4c8de4f..51d083a 100644 --- a/lib/cache.ex +++ b/lib/cache.ex @@ -114,25 +114,28 @@ defmodule Cache do end end - if match?({_, _, _}, @adapter_opts) do - defp adapter_options!({module, fun, args}), do: apply(module, fun, args) + # Emit exactly one adapter_options!/1 clause matching the compile-time + # shape of @adapter_opts. The catch-all is only generated for the + # keyword-list/fallback case, so a specific clause never leaves a dead + # catch-all behind (which the 1.20 type checker flags as never used). + cond do + match?({_, _, _}, @adapter_opts) -> + defp adapter_options!({module, fun, args}), do: apply(module, fun, args) + + match?({_, _}, @adapter_opts) -> + defp adapter_options!({app, key}), do: Application.fetch_env!(app, key) + + is_atom(@adapter_opts) and not is_nil(@adapter_opts) -> + defp adapter_options!(app_name) when is_atom(app_name), + do: Application.fetch_env!(app_name, __MODULE__) + + is_function(@adapter_opts, 0) -> + defp adapter_options!(fun) when is_function(fun, 0), do: fun.() + + true -> + defp adapter_options!(options), do: options end - if match?({_, _}, @adapter_opts) do - defp adapter_options!({app, key}), do: Application.fetch_env!(app, key) - end - - if is_atom(@adapter_opts) and not is_nil(@adapter_opts) and not is_list(@adapter_opts) do - defp adapter_options!(app_name) when is_atom(app_name), - do: Application.fetch_env!(app_name, __MODULE__) - end - - if is_function(@adapter_opts, 0) do - defp adapter_options!(fun) when is_function(fun, 0), do: fun.() - end - - defp adapter_options!(options), do: options - defp handle_adapter_result({:error, error} = result, operation, cache_name) do :telemetry.execute( [:elixir_cache, :cache, operation, :error], @@ -186,11 +189,8 @@ defmodule Cache do res - {:ok, _} = res -> - res - - {:error, _} = error -> - error + other -> + other end {result, %{cache_name: @cache_name}} @@ -295,25 +295,27 @@ defmodule Cache do def adapter_options, do: adapter_options!(@adapter_opts) - # Generate only the needed adapter_options!/1 clauses based on the actual adapter_opts - if match?({_, _, _}, @adapter_opts) do - defp adapter_options!({module, fun, args}), do: apply(module, fun, args) - end + # Emit exactly one adapter_options!/1 clause matching the compile-time + # shape of @adapter_opts. The catch-all is only generated for the + # keyword-list/fallback case, so a specific clause never leaves a dead + # catch-all behind (which the 1.20 type checker flags as never used). + cond do + match?({_, _, _}, @adapter_opts) -> + defp adapter_options!({module, fun, args}), do: apply(module, fun, args) - if match?({_, _}, @adapter_opts) do - defp adapter_options!({app, key}), do: Application.fetch_env!(app, key) - end + match?({_, _}, @adapter_opts) -> + defp adapter_options!({app, key}), do: Application.fetch_env!(app, key) - if is_atom(@adapter_opts) and not is_nil(@adapter_opts) and not is_list(@adapter_opts) do - defp adapter_options!(app_name) when is_atom(app_name), - do: Application.fetch_env!(app_name, __MODULE__) - end + is_atom(@adapter_opts) and not is_nil(@adapter_opts) -> + defp adapter_options!(app_name) when is_atom(app_name), + do: Application.fetch_env!(app_name, __MODULE__) - if is_function(@adapter_opts, 0) do - defp adapter_options!(fun) when is_function(fun, 0), do: fun.() - end + is_function(@adapter_opts, 0) -> + defp adapter_options!(fun) when is_function(fun, 0), do: fun.() - defp adapter_options!(options), do: options + true -> + defp adapter_options!(options), do: options + end defp handle_adapter_result({:error, error} = result, operation, cache_name) do :telemetry.execute( @@ -372,8 +374,8 @@ defmodule Cache do {:ok, value} -> {:ok, Cache.TermEncoder.decode(value)} - {:error, _} = error -> - error + other -> + other end {result, %{cache_name: @cache_name}} diff --git a/lib/cache/ets.ex b/lib/cache/ets.ex index f23169b..0b50049 100644 --- a/lib/cache/ets.ex +++ b/lib/cache/ets.ex @@ -1,6 +1,5 @@ defmodule Cache.ETS do require Logger - require Cache.OTPVersion @exit_signals [ :sigabrt, diff --git a/mix.exs b/mix.exs index 6f638d0..b475afa 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,8 @@ defmodule ElixirCache.MixProject do [ app: :elixir_cache, version: "0.4.9", - elixir: "~> 1.11", + elixir: "~> 1.15", + elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, description: "Standardized and testable caching across your app. In test caches are isolated.", @@ -19,14 +20,19 @@ defmodule ElixirCache.MixProject do plt_local_path: "dialyzer", plt_core_path: "dialyzer" ], - preferred_cli_env: [ + aliases: aliases() + ] + end + + def cli do + [ + preferred_envs: [ dialyzer: :test, coveralls: :test, "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test - ], - aliases: aliases() + ] ] end @@ -51,7 +57,6 @@ defmodule ElixirCache.MixProject do {:telemetry_metrics, "~> 1.0"}, {:prometheus_telemetry, "~> 0.3", optional: true}, {:libring, "~> 1.7"}, - {:faker, "~> 0.17", only: [:test]}, {:credo, "~> 1.6", only: [:test, :dev], runtime: false}, {:blitz_credo_checks, "~> 0.1", only: [:test, :dev], runtime: false}, {:excoveralls, "~> 0.10", only: :test}, @@ -69,6 +74,9 @@ defmodule ElixirCache.MixProject do ] end + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] + defp aliases do [ compile: "compile --warnings-as-errors", diff --git a/mix.lock b/mix.lock index c42dc4d..d4cdbea 100644 --- a/mix.lock +++ b/mix.lock @@ -6,18 +6,17 @@ "cowboy": {:hex, :cowboy, "2.13.0", "09d770dd5f6a22cc60c071f432cd7cb87776164527f205c5a6b0f24ff6b38990", [:make, :rebar3], [{:cowlib, ">= 2.14.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, ">= 1.8.0 and < 3.0.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "e724d3a70995025d654c1992c7b11dbfea95205c047d86ff9bf1cda92ddc5614"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.14.0", "623791c56c1cc9df54a71a9c55147a401549917f00a2e48a6ae12b812c586ced", [:make, :rebar3], [], "hexpm", "0af652d1550c8411c3b58eed7a035a7fb088c0b86aff6bc504b0bc3b7f791aa2"}, - "credo": {:hex, :credo, "1.7.13", "126a0697df6b7b71cd18c81bc92335297839a806b6f62b61d417500d1070ff4e", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "47641e6d2bbff1e241e87695b29f617f1a8f912adea34296fb10ecc3d7e9e84f"}, + "credo": {:hex, :credo, "1.7.18", "5c5596bf7aedf9c8c227f13272ac499fe8eae6237bd326f2f07dfc173786f042", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "a189d164685fd945809e862fe76a7420c4398fa288d76257662aecb909d6b3e5"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "error_message": {:hex, :error_message, "0.3.2", "01fe015ba807b515ad1d9fcfcbeb49c399374393ef3fecf9de148a471198b300", [:mix], [{:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "b3c31bf0c618f7d5b812f581fdedff5829c89439134c724aab26aa958b5ad8fa"}, "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, "excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"}, - "faker": {:hex, :faker, "0.18.0", "943e479319a22ea4e8e39e8e076b81c02827d9302f3d32726c5bf82f430e6e14", [:mix], [], "hexpm", "bfbdd83958d78e2788e99ec9317c4816e651ad05e24cfd1196ce5db5b3e81797"}, "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, - "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"}, "libring": {:hex, :libring, "1.7.0", "4f245d2f1476cd7ed8f03740f6431acba815401e40299208c7f5c640e1883bda", [:mix], [], "hexpm", "070e3593cb572e04f2c8470dd0c119bc1817a7a0a7f88229f43cf0345268ec42"}, "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, diff --git a/test/cache/con_cache_test.exs b/test/cache/con_cache_test.exs index a6a16a5..d06804a 100644 --- a/test/cache/con_cache_test.exs +++ b/test/cache/con_cache_test.exs @@ -48,7 +48,7 @@ defmodule Cache.ConCacheTest do @ttl :timer.seconds(5) setup do - key = Faker.UUID.v4() + key = Cache.Gen.key() start_supervised!({Cache, [ConCacheAdapter]}) @@ -107,13 +107,13 @@ defmodule Cache.ConCacheTest do end test "put without TTL uses ConCache.put" do - key = Faker.UUID.v4() + key = Cache.Gen.key() assert :ok === NonDirtyConCacheAdapter.put(key, "clean_value") assert {:ok, "clean_value"} === NonDirtyConCacheAdapter.get(key) end test "put with TTL uses ConCache.put with Item" do - key = Faker.UUID.v4() + key = Cache.Gen.key() assert :ok === NonDirtyConCacheAdapter.put(key, :timer.seconds(5), "ttl_clean") assert {:ok, "ttl_clean"} === NonDirtyConCacheAdapter.get(key) end diff --git a/test/cache/redis_hash_test.exs b/test/cache/redis_hash_test.exs index 7da6fab..71bdb3c 100644 --- a/test/cache/redis_hash_test.exs +++ b/test/cache/redis_hash_test.exs @@ -27,7 +27,7 @@ defmodule Cache.RedisHashTest do keys = Cache.Redis.command!(@cache_name, ["KEYS", "#{@cache_name}:#{test_key(test, "*")}"]) - if length(keys) > 0 do + if keys !== [] do Cache.Redis.command!(@cache_name, ["DEL"] ++ keys) end diff --git a/test/cache_strategy_test.exs b/test/cache_strategy_test.exs index 4ef33cc..23258ed 100644 --- a/test/cache_strategy_test.exs +++ b/test/cache_strategy_test.exs @@ -80,8 +80,8 @@ defmodule CacheStrategyTest do end test "puts into the cache and can get it back after" do - test_key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" - value = %{some_value: Faker.App.name()} + test_key = Cache.Gen.key() + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert {:ok, nil} = cache_module.get(test_key) @@ -93,8 +93,8 @@ defmodule CacheStrategyTest do end test "deleting from cache works" do - test_key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" - value = %{some_value: Faker.App.name()} + test_key = Cache.Gen.key() + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert :ok = cache_module.put(test_key, value) @@ -109,8 +109,8 @@ defmodule CacheStrategyTest do end test "puts into the cache with nil acts like deleting" do - test_key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" - value = %{some_value: Faker.App.name()} + test_key = Cache.Gen.key() + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert {:ok, nil} = cache_module.get(test_key) @@ -146,8 +146,8 @@ defmodule CacheStrategyTest do end test "finds an item in the cache that already exists" do - test_key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" - value = %{some_value: Faker.App.name()} + test_key = Cache.Gen.key() + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert :ok = cache_module.put(test_key, value) @@ -163,8 +163,8 @@ defmodule CacheStrategyTest do end test "creates a value for key when key doesn't exist in cache" do - test_key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" - value = %{some_value: Faker.App.name()} + test_key = Cache.Gen.key() + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert {:ok, nil} = cache_module.get(test_key) @@ -242,21 +242,21 @@ defmodule CacheStrategyTest do end test "reads from layer1 first when value is present" do - key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" + key = Cache.Gen.key() TestCache.Layer1.put(key, "from_layer1") assert {:ok, "from_layer1"} === TestCache.MultiLayerModules.get(key) end test "falls through to layer2 when layer1 misses" do - key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" + key = Cache.Gen.key() TestCache.Layer2.put(key, "from_layer2") assert {:ok, "from_layer2"} === TestCache.MultiLayerModules.get(key) end test "backfills layer1 after a hit in layer2" do - key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" + key = Cache.Gen.key() TestCache.Layer2.put(key, "from_layer2") assert {:ok, "from_layer2"} === TestCache.MultiLayerModules.get(key) @@ -265,7 +265,7 @@ defmodule CacheStrategyTest do end test "returns nil when all layers miss" do - key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" + key = Cache.Gen.key() assert {:ok, nil} === TestCache.MultiLayerModules.get(key) end @@ -290,7 +290,7 @@ defmodule CacheStrategyTest do end test "put writes to all layers" do - key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" + key = Cache.Gen.key() assert :ok = TestCache.MultiLayerModules.put(key, "value") @@ -299,7 +299,7 @@ defmodule CacheStrategyTest do end test "delete removes from all layers" do - key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" + key = Cache.Gen.key() TestCache.MultiLayerModules.put(key, "value") assert :ok = TestCache.MultiLayerModules.delete(key) @@ -325,7 +325,7 @@ defmodule CacheStrategyTest do end test "invokes fetch callback on total miss and backfills layers" do - key = "#{Faker.Pokemon.name()}_#{Enum.random(1..100_000_000_000)}" + key = Cache.Gen.key() assert {:ok, "fetched:#{key}"} === TestCache.MultiLayerFetch.get(key) diff --git a/test/cache_test.exs b/test/cache_test.exs index 0993fc6..43e0342 100644 --- a/test/cache_test.exs +++ b/test/cache_test.exs @@ -41,7 +41,7 @@ defmodule CacheTest do test "puts into the cache and can get it back after" do test_key = Enum.random(1..100_000_000) - value = %{some_value: Faker.App.name()} + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert {:ok, nil} = cache_module.get(test_key) @@ -54,7 +54,7 @@ defmodule CacheTest do test "deleting from cache works" do test_key = Enum.random(1..100_000_000) - value = %{some_value: Faker.App.name()} + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert :ok = cache_module.put(test_key, value) @@ -70,7 +70,7 @@ defmodule CacheTest do test "puts into the cache with nil acts like deleting" do test_key = Enum.random(1..100_000_000) - value = %{some_value: Faker.App.name()} + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert {:ok, nil} = cache_module.get(test_key) @@ -98,7 +98,7 @@ defmodule CacheTest do test "finds an item in the cache that already exists" do test_key = Enum.random(1..100_000_000) - value = %{some_value: Faker.App.name()} + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert :ok = cache_module.put(test_key, value) @@ -115,7 +115,7 @@ defmodule CacheTest do test "creates a value for key when key doesn't exist in cache" do test_key = Enum.random(1..100_000_000) - value = %{some_value: Faker.App.name()} + value = %{some_value: Cache.Gen.value()} cache_module = unquote(adapter) assert {:ok, nil} = cache_module.get(test_key) diff --git a/test/support/gen.ex b/test/support/gen.ex new file mode 100644 index 0000000..214b7b2 --- /dev/null +++ b/test/support/gen.ex @@ -0,0 +1,17 @@ +defmodule Cache.Gen do + @moduledoc """ + Tiny unique-data generators for the test suite. + + Replaces the (unmaintained) `:faker` dependency, which the tests only ever + used to produce unique cache keys and values. Uniqueness is all the tests + need, so these lean on `System.unique_integer/1`. + """ + + @doc ~S(Unique cache key string, e.g. `"key-12"`.) + @spec key() :: String.t() + def key, do: "key-#{System.unique_integer([:positive])}" + + @doc ~S(Unique cache value string, e.g. `"value-13"`.) + @spec value() :: String.t() + def value, do: "value-#{System.unique_integer([:positive])}" +end