Extracted from qwan-tracker
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
defmodule Microprints.MicroprintCacheTest do
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
alias Microprints.MicroprintCache
|
||||
|
||||
@fixture_path Path.expand("../support/fixtures/sample.ex", __DIR__)
|
||||
|
||||
setup do
|
||||
# Start a fresh test PubSub server with a unique name
|
||||
pubsub_name = Module.concat(Microprints.TestPubSub, inspect(System.unique_integer([:positive])))
|
||||
|
||||
child_spec = Phoenix.PubSub.child_spec(name: pubsub_name, adapter: Phoenix.PubSub.PG2)
|
||||
{:ok, sup_pid} = Supervisor.start_link([child_spec], strategy: :one_for_one)
|
||||
Process.put(:test_pubsub_supervisor, sup_pid)
|
||||
|
||||
# Stop any existing cache first
|
||||
if pid = GenServer.whereis(MicroprintCache) do
|
||||
GenServer.stop(pid, :normal, 5000)
|
||||
end
|
||||
|
||||
# Start fresh cache for this test
|
||||
{:ok, _pid} = MicroprintCache.start_link(pubsub: pubsub_name)
|
||||
|
||||
on_exit(fn ->
|
||||
if sup_pid = Process.get(:test_pubsub_supervisor) do
|
||||
Supervisor.stop(sup_pid)
|
||||
Process.delete(:test_pubsub_supervisor)
|
||||
end
|
||||
end)
|
||||
|
||||
%{pubsub_name: pubsub_name}
|
||||
end
|
||||
|
||||
describe "get_microprint/1" do
|
||||
test "returns microprint for valid file" do
|
||||
assert {:ok, microprint} = MicroprintCache.get_microprint(@fixture_path)
|
||||
assert is_map(microprint)
|
||||
assert is_list(microprint.lines)
|
||||
end
|
||||
|
||||
test "caches microprint on first access" do
|
||||
# First call generates and caches
|
||||
{:ok, mp1} = MicroprintCache.get_microprint(@fixture_path)
|
||||
|
||||
# Second call should return cached version (same reference)
|
||||
{:ok, mp2} = MicroprintCache.get_microprint(@fixture_path)
|
||||
|
||||
assert mp1 == mp2
|
||||
end
|
||||
|
||||
test "returns error for missing file" do
|
||||
assert {:error, :enoent} = MicroprintCache.get_microprint("/nonexistent/file.ex")
|
||||
end
|
||||
end
|
||||
|
||||
describe "invalidate/1" do
|
||||
test "removes cached entry for path" do
|
||||
# Cache a microprint
|
||||
{:ok, _} = MicroprintCache.get_microprint(@fixture_path)
|
||||
|
||||
# Invalidate it
|
||||
MicroprintCache.invalidate(@fixture_path)
|
||||
|
||||
# The ETS table should not have this entry anymore
|
||||
# (We verify by checking it's regenerated on next access)
|
||||
{:ok, mp} = MicroprintCache.get_microprint(@fixture_path)
|
||||
assert is_map(mp)
|
||||
end
|
||||
end
|
||||
|
||||
describe "clear_all/0" do
|
||||
test "removes all cached entries" do
|
||||
# Cache a microprint
|
||||
{:ok, _} = MicroprintCache.get_microprint(@fixture_path)
|
||||
|
||||
# Clear all
|
||||
MicroprintCache.clear_all()
|
||||
|
||||
# Should still work (regenerates)
|
||||
{:ok, mp} = MicroprintCache.get_microprint(@fixture_path)
|
||||
assert is_map(mp)
|
||||
end
|
||||
end
|
||||
|
||||
describe "PubSub integration" do
|
||||
test "invalidates cache on live_reload message", %{pubsub_name: pubsub_name} do
|
||||
# Cache a microprint
|
||||
{:ok, _} = MicroprintCache.get_microprint(@fixture_path)
|
||||
|
||||
# Simulate LiveReload notification
|
||||
Phoenix.PubSub.broadcast(
|
||||
pubsub_name,
|
||||
"dev_tools_files",
|
||||
{:phoenix_live_reload, "dev_tools_files", @fixture_path}
|
||||
)
|
||||
|
||||
# Give the GenServer time to process
|
||||
Process.sleep(10)
|
||||
|
||||
# The cache entry should have been invalidated
|
||||
# (We can't directly check ETS, but the behavior is verified by the flow)
|
||||
{:ok, mp} = MicroprintCache.get_microprint(@fixture_path)
|
||||
assert is_map(mp)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,158 @@
|
||||
defmodule Microprints.MicroprintTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias Microprints.Microprint
|
||||
|
||||
@fixture_path Path.expand("../support/fixtures/sample.ex", __DIR__)
|
||||
|
||||
describe "generate/1" do
|
||||
test "returns microprint structure for valid file" do
|
||||
assert {:ok, microprint} = Microprint.generate(@fixture_path)
|
||||
assert is_map(microprint)
|
||||
assert is_list(microprint.lines)
|
||||
assert is_integer(microprint.line_count)
|
||||
assert microprint.line_count == length(microprint.lines)
|
||||
end
|
||||
|
||||
test "returns error for missing file" do
|
||||
assert {:error, :enoent} = Microprint.generate("/nonexistent/file.ex")
|
||||
end
|
||||
|
||||
test "all lines have color, indent, and length" do
|
||||
{:ok, microprint} = Microprint.generate(@fixture_path)
|
||||
|
||||
Enum.each(microprint.lines, fn line_info ->
|
||||
assert is_map(line_info)
|
||||
assert String.starts_with?(line_info.color, "#"), "Expected hex color"
|
||||
assert String.length(line_info.color) == 7, "Expected 7-char hex color"
|
||||
assert is_integer(line_info.indent)
|
||||
assert line_info.indent >= 0
|
||||
assert is_integer(line_info.length)
|
||||
assert line_info.length >= 0
|
||||
end)
|
||||
end
|
||||
|
||||
test "captures indentation levels" do
|
||||
{:ok, microprint} = Microprint.generate(@fixture_path)
|
||||
|
||||
# First line (defmodule) should have 0 indent
|
||||
first_line = List.first(microprint.lines)
|
||||
assert first_line.indent == 0
|
||||
|
||||
# Find a line with indent (function body lines should be indented)
|
||||
indented_lines = Enum.filter(microprint.lines, &(&1.indent > 0))
|
||||
assert length(indented_lines) > 0, "Expected some indented lines"
|
||||
end
|
||||
|
||||
test "captures line lengths" do
|
||||
{:ok, microprint} = Microprint.generate(@fixture_path)
|
||||
|
||||
# First line "defmodule Sample do" has content
|
||||
first_line = List.first(microprint.lines)
|
||||
assert first_line.length > 0
|
||||
|
||||
# Empty lines should have length 0
|
||||
empty_lines = Enum.filter(microprint.lines, &(&1.length == 0))
|
||||
assert length(empty_lines) > 0, "Expected some empty lines"
|
||||
|
||||
# Lines vary in length
|
||||
lengths = Enum.map(microprint.lines, & &1.length) |> Enum.uniq()
|
||||
assert length(lengths) > 1, "Expected varying line lengths"
|
||||
end
|
||||
end
|
||||
|
||||
describe "color classification for Elixir files" do
|
||||
test "module definitions get module color" do
|
||||
{:ok, microprint} = Microprint.generate(@fixture_path)
|
||||
# First line is "defmodule Sample do"
|
||||
first_line = List.first(microprint.lines)
|
||||
assert first_line.color == Microprint.color_for(:module)
|
||||
end
|
||||
|
||||
test "function definitions get function_def color" do
|
||||
{:ok, microprint} = Microprint.generate(@fixture_path)
|
||||
colors = Enum.map(microprint.lines, & &1.color)
|
||||
assert Microprint.color_for(:function_def) in colors
|
||||
end
|
||||
|
||||
test "comments get comment color" do
|
||||
{:ok, microprint} = Microprint.generate(@fixture_path)
|
||||
colors = Enum.map(microprint.lines, & &1.color)
|
||||
assert Microprint.color_for(:comment) in colors
|
||||
end
|
||||
|
||||
test "atom-heavy lines get atom color" do
|
||||
{:ok, microprint} = Microprint.generate(@fixture_path)
|
||||
colors = Enum.map(microprint.lines, & &1.color)
|
||||
assert Microprint.color_for(:atom) in colors
|
||||
end
|
||||
end
|
||||
|
||||
describe "color_for/1" do
|
||||
test "returns expected colors for known types" do
|
||||
assert Microprint.color_for(:keyword) == "#8B5CF6"
|
||||
assert Microprint.color_for(:string) == "#10B981"
|
||||
assert Microprint.color_for(:comment) == "#6B7280"
|
||||
assert Microprint.color_for(:function_def) == "#EF4444"
|
||||
assert Microprint.color_for(:atom) == "#F59E0B"
|
||||
assert Microprint.color_for(:number) == "#3B82F6"
|
||||
assert Microprint.color_for(:module) == "#EC4899"
|
||||
end
|
||||
|
||||
test "returns default color for unknown types" do
|
||||
assert Microprint.color_for(:unknown) == "#D1D5DB"
|
||||
end
|
||||
end
|
||||
|
||||
describe "color_legend/0" do
|
||||
test "returns list of label-color tuples" do
|
||||
legend = Microprint.color_legend()
|
||||
|
||||
assert is_list(legend)
|
||||
assert length(legend) == 8
|
||||
|
||||
for {label, color} <- legend do
|
||||
assert is_binary(label)
|
||||
assert String.starts_with?(color, "#")
|
||||
end
|
||||
end
|
||||
|
||||
test "includes key syntax types" do
|
||||
legend = Microprint.color_legend()
|
||||
labels = Enum.map(legend, fn {label, _} -> label end)
|
||||
|
||||
assert "Function" in labels
|
||||
assert "Module" in labels
|
||||
assert "Keyword" in labels
|
||||
assert "String" in labels
|
||||
assert "Comment" in labels
|
||||
end
|
||||
end
|
||||
|
||||
describe "non-Elixir files" do
|
||||
test "handles JavaScript-like files with generic colorization" do
|
||||
# Create a temp JS file
|
||||
tmp_path = Path.join(System.tmp_dir!(), "test_#{:rand.uniform(100_000)}.js")
|
||||
|
||||
File.write!(tmp_path, """
|
||||
// A comment
|
||||
function hello() {
|
||||
return "world";
|
||||
}
|
||||
""")
|
||||
|
||||
{:ok, microprint} = Microprint.generate(tmp_path)
|
||||
assert microprint.line_count == 5
|
||||
|
||||
# First line is a comment
|
||||
first_line = List.first(microprint.lines)
|
||||
assert first_line.color == Microprint.color_for(:comment)
|
||||
|
||||
# Third line has indent (inside function)
|
||||
third_line = Enum.at(microprint.lines, 2)
|
||||
assert third_line.indent > 0
|
||||
|
||||
File.rm!(tmp_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
defmodule Sample do
|
||||
@moduledoc """
|
||||
A sample module for testing microprint generation.
|
||||
"""
|
||||
|
||||
@my_attribute :value
|
||||
|
||||
@doc "Returns a greeting message"
|
||||
def greet(name) do
|
||||
"Hello, #{name}!"
|
||||
end
|
||||
|
||||
# Private helper
|
||||
defp format_name(name) do
|
||||
String.capitalize(name)
|
||||
end
|
||||
|
||||
@type status :: :ok | :error
|
||||
|
||||
def calculate(x, y) when is_number(x) and is_number(y) do
|
||||
x + y
|
||||
end
|
||||
|
||||
def list_items do
|
||||
:standalone_atom
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
defmodule Microprints.TestPubSub do
|
||||
@moduledoc """
|
||||
Test helper for starting a Phoenix.PubSub server.
|
||||
|
||||
Provides `start_link/1` to start a PubSub server and returns the
|
||||
server name for use with MicroprintCache.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Starts a test PubSub server and returns its name.
|
||||
"""
|
||||
def start_link(opts \\ []) do
|
||||
name = opts[:name] || Microprints.TestPubSub
|
||||
|
||||
child_spec = Phoenix.PubSub.child_spec(name: name, adapter: Phoenix.PubSub.PG2)
|
||||
|
||||
# Start a temporary supervisor to host the PubSub server
|
||||
case Supervisor.start_link([child_spec], strategy: :one_for_one) do
|
||||
{:ok, sup_pid} ->
|
||||
Process.put(:test_pubsub_supervisor, sup_pid)
|
||||
|
||||
{:error, {:already_started, sup_pid}} ->
|
||||
Process.put(:test_pubsub_supervisor, sup_pid)
|
||||
end
|
||||
|
||||
name
|
||||
end
|
||||
|
||||
@doc """
|
||||
Stops the test PubSub server.
|
||||
"""
|
||||
def stop do
|
||||
if sup_pid = Process.get(:test_pubsub_supervisor) do
|
||||
Supervisor.stop(sup_pid)
|
||||
Process.delete(:test_pubsub_supervisor)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
ExUnit.start()
|
||||
Reference in New Issue
Block a user