From 300f0ca73f4b68470a59404ebe94c0da3ca8eb7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20M=C3=A4nnchen?= Date: Tue, 1 Apr 2025 14:24:15 +0200 Subject: [PATCH 1/2] Use Test Modules in tests instead of Elixir built-in modules Prep for Coverage Reporting in tests --- lib/elixir/test/elixir/exception_test.exs | 42 +++++-- lib/elixir/test/elixir/module_test.exs | 13 ++- .../elixir/protocol/consolidation_test.exs | 9 +- lib/elixir/test/elixir/test_helper.exs | 4 + lib/iex/test/iex/helpers_test.exs | 91 ++++++++------- lib/iex/test/iex/interaction_test.exs | 27 ++++- lib/iex/test/iex/pry_test.exs | 108 +++++++++--------- lib/iex/test/test_helper.exs | 39 +++++++ 8 files changed, 222 insertions(+), 111 deletions(-) diff --git a/lib/elixir/test/elixir/exception_test.exs b/lib/elixir/test/elixir/exception_test.exs index 36d6377f0c1..db476fa5b6e 100644 --- a/lib/elixir/test/elixir/exception_test.exs +++ b/lib/elixir/test/elixir/exception_test.exs @@ -556,20 +556,33 @@ defmodule ExceptionTest do end test "annotates function clause errors" do - assert blame_message(Access, & &1.fetch(:foo, :bar)) =~ """ - no function clause matching in Access.fetch/2 + import PathHelpers + + write_beam( + defmodule ExampleModule do + def fun(arg1, arg2) + def fun(:one, :one), do: :ok + def fun(:two, :two), do: :ok + end + ) + + message = blame_message(ExceptionTest.ExampleModule, & &1.fun(:three, :four)) + + assert message =~ """ + no function clause matching in ExceptionTest.ExampleModule.fun/2 - The following arguments were given to Access.fetch/2: + The following arguments were given to ExceptionTest.ExampleModule.fun/2: # 1 - :foo + :three # 2 - :bar + :four - Attempted function clauses (showing 5 out of 5): + Attempted function clauses (showing 2 out of 2): - def fetch(-%module{} = container-, key) + def fun(-:one-, -:one-) + def fun(-:two-, -:two-) """ end @@ -858,13 +871,22 @@ defmodule ExceptionTest do describe "blaming unit tests" do test "annotates clauses errors" do - args = [%{}, :key, nil] + import PathHelpers + + write_beam( + defmodule ExampleModule do + def fun(arg), do: arg + end + ) + + args = [nil] {exception, stack} = - Exception.blame(:error, :function_clause, [{Keyword, :pop, args, [line: 13]}]) + Exception.blame(:error, :function_clause, [{ExampleModule, :fun, args, [line: 13]}]) assert %FunctionClauseError{kind: :def, args: ^args, clauses: [_]} = exception - assert stack == [{Keyword, :pop, 3, [line: 13]}] + + assert stack == [{ExampleModule, :fun, 1, [line: 13]}] end test "annotates args and clauses from mfa" do diff --git a/lib/elixir/test/elixir/module_test.exs b/lib/elixir/test/elixir/module_test.exs index 8065ed2472c..c2ffc5146de 100644 --- a/lib/elixir/test/elixir/module_test.exs +++ b/lib/elixir/test/elixir/module_test.exs @@ -432,9 +432,18 @@ defmodule ModuleTest do end test "compiles to core" do - {:ok, {Atom, [{~c"Dbgi", dbgi}]}} = Atom |> :code.which() |> :beam_lib.chunks([~c"Dbgi"]) + import PathHelpers + + write_beam( + defmodule ExampleModule do + end + ) + + {:ok, {ExampleModule, [{~c"Dbgi", dbgi}]}} = + ExampleModule |> :code.which() |> :beam_lib.chunks([~c"Dbgi"]) + {:debug_info_v1, backend, data} = :erlang.binary_to_term(dbgi) - {:ok, core} = backend.debug_info(:core_v1, Atom, data, []) + {:ok, core} = backend.debug_info(:core_v1, ExampleModule, data, []) assert is_tuple(core) end diff --git a/lib/elixir/test/elixir/protocol/consolidation_test.exs b/lib/elixir/test/elixir/protocol/consolidation_test.exs index 3b1a08e0180..48ab0d6a328 100644 --- a/lib/elixir/test/elixir/protocol/consolidation_test.exs +++ b/lib/elixir/test/elixir/protocol/consolidation_test.exs @@ -247,11 +247,18 @@ defmodule Protocol.ConsolidationTest do end test "consolidation errors on missing BEAM files" do + import PathHelpers + + write_beam( + defmodule ExampleModule do + end + ) + defprotocol NoBeam do def example(arg) end - assert Protocol.consolidate(String, []) == {:error, :not_a_protocol} + assert Protocol.consolidate(ExampleModule, []) == {:error, :not_a_protocol} assert Protocol.consolidate(NoBeam, []) == {:error, :no_beam_info} end diff --git a/lib/elixir/test/elixir/test_helper.exs b/lib/elixir/test/elixir/test_helper.exs index ebc35dc3b30..9ac2de26b87 100644 --- a/lib/elixir/test/elixir/test_helper.exs +++ b/lib/elixir/test/elixir/test_helper.exs @@ -56,6 +56,10 @@ defmodule PathHelpers do File.mkdir_p!(unquote(path)) beam_path = Path.join(unquote(path), Atom.to_string(name) <> ".beam") File.write!(beam_path, bin) + + :code.purge(name) + :code.delete(name) + res end diff --git a/lib/iex/test/iex/helpers_test.exs b/lib/iex/test/iex/helpers_test.exs index 45f4eea29cb..11a76f13fcc 100644 --- a/lib/iex/test/iex/helpers_test.exs +++ b/lib/iex/test/iex/helpers_test.exs @@ -39,45 +39,45 @@ defmodule IEx.HelpersTest do end test "sets up a breakpoint with capture syntax" do - assert break!(URI.decode_query() / 2) == 1 - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 1}] + assert break!(PryExampleModule.two() / 2) == 1 + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}] end test "sets up a breakpoint with call syntax" do - assert break!(URI.decode_query(_, %{})) == 1 - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 1}] + assert break!(PryExampleModule.two(_, %{})) == 1 + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}] end test "sets up a breakpoint with guards syntax" do - assert break!(URI.decode_query(_, map) when is_map(map)) == 1 - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 1}] + assert break!(PryExampleModule.two(_, map) when is_map(map)) == 1 + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}] end test "sets up a breakpoint on the given module" do - assert break!(URI, :decode_query, 2) == 1 - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 1}] + assert break!(PryExampleModule, :two, 2) == 1 + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}] end test "resets breaks on the given ID" do - assert break!(URI, :decode_query, 2) == 1 + assert break!(PryExampleModule, :two, 2) == 1 assert reset_break(1) == :ok - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 0}] + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}] end test "resets breaks on the given module" do - assert break!(URI, :decode_query, 2) == 1 - assert reset_break(URI, :decode_query, 2) == :ok - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 0}] + assert break!(PryExampleModule, :two, 2) == 1 + assert reset_break(PryExampleModule, :two, 2) == :ok + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}] end test "removes breaks in the given module" do - assert break!(URI.decode_query() / 2) == 1 - assert remove_breaks(URI) == :ok + assert break!(PryExampleModule.two() / 2) == 1 + assert remove_breaks(PryExampleModule) == :ok assert IEx.Pry.breaks() == [] end test "removes breaks on all modules" do - assert break!(URI.decode_query() / 2) == 1 + assert break!(PryExampleModule.two() / 2) == 1 assert remove_breaks() == :ok assert IEx.Pry.breaks() == [] end @@ -85,7 +85,7 @@ defmodule IEx.HelpersTest do test "errors when setting up a breakpoint with invalid guard" do assert capture_io(:stderr, fn -> assert_raise CompileError, fn -> - break!(URI.decode_query(_, map) when is_whatever(map)) + break!(PryExampleModule.two(_, map) when is_whatever(map)) end end) =~ "cannot find or invoke local is_whatever/1" end @@ -98,44 +98,44 @@ defmodule IEx.HelpersTest do test "errors when setting up a break for unknown function" do assert_raise RuntimeError, - "could not set breakpoint, unknown function/macro URI.unknown/2", - fn -> break!(URI, :unknown, 2) end + "could not set breakpoint, unknown function/macro #{inspect(PryExampleModule)}.unknown/2", + fn -> break!(PryExampleModule, :unknown, 2) end end test "errors for non-Elixir modules" do assert_raise RuntimeError, - "could not set breakpoint, module :elixir was not written in Elixir", - fn -> break!(:elixir, :unknown, 2) end + "could not set breakpoint, module :maps was not written in Elixir", + fn -> break!(:maps, :unknown, 2) end end test "prints table with breaks" do - break!(URI, :decode_query, 2) + break!(PryExampleModule, :two, 2) assert capture_io(fn -> breaks() end) == """ - ID Module.function/arity Pending stops - ---- ----------------------- --------------- - 1 URI.decode_query/2 1 + ID Module.function/arity Pending stops + ---- ------------------------ --------------- + 1 PryExampleModule.two/2 1 """ - assert capture_io(fn -> URI.decode_query("foo=bar", %{}) end) != "" + assert capture_io(fn -> PryExampleModule.two("foo=bar", %{}) end) != "" assert capture_io(fn -> breaks() end) == """ - ID Module.function/arity Pending stops - ---- ----------------------- --------------- - 1 URI.decode_query/2 0 + ID Module.function/arity Pending stops + ---- ------------------------ --------------- + 1 PryExampleModule.two/2 0 """ - assert capture_io(fn -> URI.decode_query("foo=bar", %{}) end) == "" + assert capture_io(fn -> PryExampleModule.two("foo=bar", %{}) end) == "" assert capture_io(fn -> breaks() end) == """ - ID Module.function/arity Pending stops - ---- ----------------------- --------------- - 1 URI.decode_query/2 0 + ID Module.function/arity Pending stops + ---- ------------------------ --------------- + 1 PryExampleModule.two/2 0 """ end @@ -152,6 +152,7 @@ defmodule IEx.HelpersTest do @lists_erl Application.app_dir(:stdlib, "src/lists.erl") @httpc_erl "src/http_client/httpc.erl" @editor System.get_env("ELIXIR_EDITOR") + @example_module_path "lib/iex/test/test_helper.exs" test "opens __FILE__ and __LINE__" do System.put_env("ELIXIR_EDITOR", "echo __LINE__:__FILE__") @@ -163,7 +164,8 @@ defmodule IEx.HelpersTest do end test "opens Elixir module" do - assert capture_iex("open(IEx.Helpers)") |> maybe_trim_quotes() =~ ~r/#{@iex_helpers}:5$/ + assert capture_iex("open(HelperExampleModule)") |> maybe_trim_quotes() =~ + ~r/#{@example_module_path}:\d+$/ end test "opens function" do @@ -176,16 +178,19 @@ defmodule IEx.HelpersTest do end test "opens module.function" do - assert capture_iex("open(IEx.Helpers.b)") |> maybe_trim_quotes() =~ ~r/#{@iex_helpers}:\d+$/ - assert capture_iex("open(IEx.Helpers.h)") |> maybe_trim_quotes() =~ ~r/#{@iex_helpers}:\d+$/ + assert capture_iex("open(HelperExampleModule.fun)") |> maybe_trim_quotes() =~ + ~r/#{@example_module_path}:\d+$/ + + assert capture_iex("open(HelperExampleModule.macro)") |> maybe_trim_quotes() =~ + ~r/#{@example_module_path}:\d+$/ end test "opens module.function/arity" do - assert capture_iex("open(IEx.Helpers.b/1)") |> maybe_trim_quotes() =~ - ~r/#{@iex_helpers}:\d+$/ + assert capture_iex("open(HelperExampleModule.fun/1)") |> maybe_trim_quotes() =~ + ~r/#{@example_module_path}:\d+$/ - assert capture_iex("open(IEx.Helpers.h/0)") |> maybe_trim_quotes() =~ - ~r/#{@iex_helpers}:\d+$/ + assert capture_iex("open(HelperExampleModule.macro/1)") |> maybe_trim_quotes() =~ + ~r/#{@example_module_path}:\d+$/ end test "opens Erlang module" do @@ -1440,11 +1445,13 @@ defmodule IEx.HelpersTest do @tag :capture_log test "loads a given module on the given nodes" do assert nl([node()], :lists) == {:ok, [{:nonode@nohost, :error, :sticky_directory}]} - assert nl([node()], Enum) == {:ok, [{:nonode@nohost, :loaded, Enum}]} + + assert nl([node()], HelperExampleModule) == + {:ok, [{:nonode@nohost, :loaded, HelperExampleModule}]} assert nl(:nonexistent_module) == {:error, :nofile} - assert nl([:nosuchnode@badhost], Enum) == + assert nl([:nosuchnode@badhost], HelperExampleModule) == {:ok, [{:nosuchnode@badhost, :badrpc, :noconnection}]} end end diff --git a/lib/iex/test/iex/interaction_test.exs b/lib/iex/test/iex/interaction_test.exs index 540884366d6..247281a580e 100644 --- a/lib/iex/test/iex/interaction_test.exs +++ b/lib/iex/test/iex/interaction_test.exs @@ -232,11 +232,30 @@ defmodule IEx.InteractionTest do end test "blames function clause error" do + import PathHelpers + + write_beam( + defmodule ExampleModule do + def fun(:valid), do: :ok + end + ) + + content = capture_iex("IEx.InteractionTest.ExampleModule.fun(:invalid)") + + assert content =~ + "** (FunctionClauseError) no function clause matching in IEx.InteractionTest.ExampleModule.fun/1" + + assert content =~ + "The following arguments were given to IEx.InteractionTest.ExampleModule.fun/1" + + assert content =~ ":invalid" + assert content =~ "def fun(-:valid-)" + + assert content =~ + ~r"test/iex/interaction_test.exs:\d+: IEx\.InteractionTest\.ExampleModule\.fun/1" + content = capture_iex("Access.fetch(:foo, :bar)") - assert content =~ "** (FunctionClauseError) no function clause matching in Access.fetch/2" - assert content =~ "The following arguments were given to Access.fetch/2" - assert content =~ ":foo" - assert content =~ "def fetch(-%module{} = container-, key)" + assert content =~ ~r"\(elixir #{System.version()}\) lib/access\.ex:\d+: Access\.fetch/2" end diff --git a/lib/iex/test/iex/pry_test.exs b/lib/iex/test/iex/pry_test.exs index ea8125db377..d1038da5683 100644 --- a/lib/iex/test/iex/pry_test.exs +++ b/lib/iex/test/iex/pry_test.exs @@ -47,39 +47,39 @@ defmodule IEx.PryTest do describe "break" do test "sets up a breakpoint on the given module" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - assert instrumented?(URI) + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + assert instrumented?(PryExampleModule) assert [_] = IEx.Pry.breaks() end test "sets up multiple breakpoints in the same module" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - assert instrumented?(URI) - assert IEx.Pry.break(URI, :parse, 1) == {:ok, 2} - assert instrumented?(URI) + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + assert instrumented?(PryExampleModule) + assert IEx.Pry.break(PryExampleModule, :one, 1) == {:ok, 2} + assert instrumented?(PryExampleModule) assert [_, _] = IEx.Pry.breaks() end test "reinstruments if module has been reloaded" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - assert instrumented?(URI) - deinstrument!(URI) - refute instrumented?(URI) - assert IEx.Pry.break(URI, :parse, 1) == {:ok, 2} - assert instrumented?(URI) + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + assert instrumented?(PryExampleModule) + deinstrument!(PryExampleModule) + refute instrumented?(PryExampleModule) + assert IEx.Pry.break(PryExampleModule, :one, 1) == {:ok, 2} + assert instrumented?(PryExampleModule) assert [_, _] = IEx.Pry.breaks() end test "returns ID when breakpoint is already set" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} assert [_] = IEx.Pry.breaks() end test "returns ID even when breakpoint is already set on deinstrument" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - deinstrument!(URI) - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + deinstrument!(PryExampleModule) + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} assert [_] = IEx.Pry.breaks() end @@ -88,67 +88,71 @@ defmodule IEx.PryTest do end test "errors when setting up a break for unknown function" do - assert IEx.Pry.break(URI, :unknown, 2) == {:error, :unknown_function_arity} + assert IEx.Pry.break(PryExampleModule, :unknown, 2) == {:error, :unknown_function_arity} end test "errors for non-Elixir modules" do - assert IEx.Pry.break(:elixir, :unknown, 2) == {:error, :non_elixir_module} + assert IEx.Pry.break(:maps, :unknown, 2) == {:error, :non_elixir_module} end end describe "breaks" do test "returns all breaks" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 1}] + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}] - assert IEx.Pry.break(URI, :decode_query, 2, 10) == {:ok, 1} - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 10}] + assert IEx.Pry.break(PryExampleModule, :two, 2, 10) == {:ok, 1} + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 10}] - assert IEx.Pry.break(URI, :parse, 1, 1) == {:ok, 2} - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 10}, {2, URI, {:parse, 1}, 1}] + assert IEx.Pry.break(PryExampleModule, :one, 1, 1) == {:ok, 2} + + assert IEx.Pry.breaks() == [ + {1, PryExampleModule, {:two, 2}, 10}, + {2, PryExampleModule, {:one, 1}, 1} + ] end test "sets negative break to 0" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - :ets.insert(IEx.Pry, {1, URI, {:decode_query, 2}, {[], true}, -1}) - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 0}] + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + :ets.insert(IEx.Pry, {1, PryExampleModule, {:two, 2}, {[], true}, -1}) + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}] end test "do not return break points for deinstrumented modules" do - assert IEx.Pry.break(URI, :parse, 1) == {:ok, 1} - assert IEx.Pry.breaks() == [{1, URI, {:parse, 1}, 1}] - deinstrument!(URI) + assert IEx.Pry.break(PryExampleModule, :one, 1) == {:ok, 1} + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:one, 1}, 1}] + deinstrument!(PryExampleModule) assert IEx.Pry.breaks() == [] end end describe "reset_break" do test "resets break for given ID" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} assert IEx.Pry.reset_break(1) == :ok - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 0}] + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}] end test "resets break for given mfa" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - assert IEx.Pry.reset_break(URI, :decode_query, 2) == :ok - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 0}] + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + assert IEx.Pry.reset_break(PryExampleModule, :two, 2) == :ok + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}] end test "returns not_found if module is deinstrumented" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - deinstrument!(URI) - assert IEx.Pry.reset_break(URI, :decode_query, 2) == :not_found + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + deinstrument!(PryExampleModule) + assert IEx.Pry.reset_break(PryExampleModule, :two, 2) == :not_found assert IEx.Pry.breaks() == [] end test "returns not_found if mfa has no break" do - assert IEx.Pry.reset_break(URI, :decode_query, 2) == :not_found + assert IEx.Pry.reset_break(PryExampleModule, :two, 2) == :not_found end test "returns not_found if ID is deinstrumented" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - deinstrument!(URI) + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + deinstrument!(PryExampleModule) assert IEx.Pry.reset_break(1) == :not_found assert IEx.Pry.breaks() == [] end @@ -160,29 +164,29 @@ defmodule IEx.PryTest do describe "remove_breaks" do test "removes all breaks" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} assert IEx.Pry.remove_breaks() == :ok assert IEx.Pry.breaks() == [] end test "removes all breaks even if module is deinstrumented" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - deinstrument!(URI) + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + deinstrument!(PryExampleModule) assert IEx.Pry.remove_breaks() == :ok assert IEx.Pry.breaks() == [] end test "remove breaks in a given module" do - assert IEx.Pry.remove_breaks(Date.Range) == :ok - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - assert IEx.Pry.break(Date.Range, :__struct__, 1) == {:ok, 2} - assert IEx.Pry.remove_breaks(Date.Range) == :ok - assert IEx.Pry.breaks() == [{1, URI, {:decode_query, 2}, 1}] + assert IEx.Pry.remove_breaks(PryExampleStruct) == :ok + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + assert IEx.Pry.break(PryExampleStruct, :__struct__, 1) == {:ok, 2} + assert IEx.Pry.remove_breaks(PryExampleStruct) == :ok + assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}] end test "remove breaks in a given module even if deinstrumented" do - assert IEx.Pry.break(URI, :decode_query, 2) == {:ok, 1} - deinstrument!(URI) + assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1} + deinstrument!(PryExampleModule) assert IEx.Pry.breaks() == [] end end diff --git a/lib/iex/test/test_helper.exs b/lib/iex/test/test_helper.exs index 80859e417c3..7b016f140a8 100644 --- a/lib/iex/test/test_helper.exs +++ b/lib/iex/test/test_helper.exs @@ -2,6 +2,12 @@ # SPDX-FileCopyrightText: 2021 The Elixir Team # SPDX-FileCopyrightText: 2012 Plataformatec +# Beam files compiled on demand +path = Path.expand("../tmp/beams", __DIR__) +File.rm_rf!(path) +File.mkdir_p!(path) +Code.prepend_path(path) + assert_timeout = String.to_integer(System.get_env("ELIXIR_ASSERT_TIMEOUT") || "500") System.put_env("ELIXIR_EDITOR", "echo") @@ -103,3 +109,36 @@ defmodule IEx.Case do |> String.trim() end end + +defmodule PathHelpers do + def write_beam({:module, name, bin, _} = res) do + File.mkdir_p!(unquote(path)) + beam_path = Path.join(unquote(path), Atom.to_string(name) <> ".beam") + File.write!(beam_path, bin) + + :code.purge(name) + :code.delete(name) + + res + end +end + +PathHelpers.write_beam( + defmodule HelperExampleModule do + def fun(_arg), do: :ok + defmacro macro(_arg), do: :ok + end +) + +PathHelpers.write_beam( + defmodule PryExampleModule do + def one(_arg), do: :ok + def two(_arg1, _arg2), do: :ok + end +) + +PathHelpers.write_beam( + defmodule PryExampleStruct do + defstruct one: nil + end +) From 10affa15cbab461379b7bfebfad079b9104fa903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 7 Apr 2025 16:04:07 +0200 Subject: [PATCH 2/2] Apply suggestions from code review --- lib/elixir/test/elixir/exception_test.exs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/elixir/test/elixir/exception_test.exs b/lib/elixir/test/elixir/exception_test.exs index db476fa5b6e..e3fd9feb134 100644 --- a/lib/elixir/test/elixir/exception_test.exs +++ b/lib/elixir/test/elixir/exception_test.exs @@ -874,7 +874,7 @@ defmodule ExceptionTest do import PathHelpers write_beam( - defmodule ExampleModule do + defmodule BlameModule do def fun(arg), do: arg end ) @@ -882,11 +882,10 @@ defmodule ExceptionTest do args = [nil] {exception, stack} = - Exception.blame(:error, :function_clause, [{ExampleModule, :fun, args, [line: 13]}]) + Exception.blame(:error, :function_clause, [{BlameModule, :fun, args, [line: 13]}]) assert %FunctionClauseError{kind: :def, args: ^args, clauses: [_]} = exception - - assert stack == [{ExampleModule, :fun, 1, [line: 13]}] + assert stack == [{BlameModule, :fun, 1, [line: 13]}] end test "annotates args and clauses from mfa" do