Skip to content

Commit b03922e

Browse files
committed
Merge modules
1 parent 3a7f43b commit b03922e

File tree

2 files changed

+202
-206
lines changed

2 files changed

+202
-206
lines changed

lib/mix/test/mix/tasks/compile.elixir_test.exs

Lines changed: 202 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,29 @@ defmodule Mix.Tasks.Compile.ElixirTest do
66
import ExUnit.CaptureIO
77
alias Mix.Task.Compiler.Diagnostic
88

9+
@old_time {{2010, 1, 1}, {0, 0, 0}}
10+
@elixir_otp_version {System.version(), :erlang.system_info(:otp_release)}
11+
912
def trace(event, env) do
1013
send(__MODULE__, {event, env})
1114
:ok
1215
end
1316

14-
@old_time {{2010, 1, 1}, {0, 0, 0}}
15-
@elixir_otp_version {System.version(), :erlang.system_info(:otp_release)}
17+
defp mtime(path) do
18+
File.stat!(path).mtime
19+
end
20+
21+
defp mark_as_old!(path) do
22+
mtime = mtime(path)
23+
File.touch!(path, @old_time)
24+
mtime
25+
end
26+
27+
defp purge_protocol(module) do
28+
:code.del_path(:filename.absname(~c"_build/dev/lib/sample/consolidated"))
29+
:code.purge(module)
30+
:code.delete(module)
31+
end
1632

1733
test "compiles a project without per environment build" do
1834
Mix.ProjectStack.post_config(build_per_environment: false)
@@ -128,7 +144,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
128144
assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
129145
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
130146
refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]}
131-
assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time
147+
assert mtime("_build/dev/lib/sample/.mix/compile.elixir") > @old_time
132148

133149
ensure_touched(__ENV__.file, "_build/dev/lib/sample/.mix/compile.elixir")
134150
assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
@@ -245,7 +261,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
245261
assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
246262
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
247263
refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]}
248-
assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time
264+
assert mtime("_build/dev/lib/sample/.mix/compile.elixir") > @old_time
249265
end)
250266
after
251267
Application.put_env(:elixir, :dbg_callback, {Macro, :dbg, []})
@@ -482,7 +498,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
482498
assert recompile.() == {:ok, []}
483499
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
484500
refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]}
485-
assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time
501+
assert mtime("_build/dev/lib/sample/.mix/compile.elixir") > @old_time
486502

487503
# Changing lock recompiles
488504
File.write!("mix.lock", """
@@ -494,7 +510,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
494510
assert recompile.() == {:ok, []}
495511
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
496512
refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]}
497-
assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time
513+
assert mtime("_build/dev/lib/sample/.mix/compile.elixir") > @old_time
498514

499515
# Removing a lock recompiles
500516
File.write!("mix.lock", """
@@ -506,7 +522,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
506522
assert recompile.() == {:ok, []}
507523
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
508524
refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]}
509-
assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time
525+
assert mtime("_build/dev/lib/sample/.mix/compile.elixir") > @old_time
510526

511527
# Adding an unknown dependency returns :ok but does not recompile
512528
File.write!("mix.lock", """
@@ -584,9 +600,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
584600
Mix.Tasks.Compile.run([])
585601
assert Mix.Dep.ElixirSCM.read() == {:ok, @elixir_otp_version, Mix.SCM.Path}
586602

587-
assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir_scm").mtime >
588-
@old_time
589-
603+
assert mtime("_build/dev/lib/sample/.mix/compile.elixir_scm") > @old_time
590604
refute File.exists?("_build/dev/lib/sample/consolidated/.to_be_removed")
591605
end)
592606
end
@@ -608,8 +622,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
608622
Mix.Tasks.Compile.run([])
609623
assert Mix.Dep.ElixirSCM.read() == {:ok, @elixir_otp_version, Mix.SCM.Path}
610624

611-
assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir_scm").mtime >
612-
@old_time
625+
assert mtime("_build/dev/lib/sample/.mix/compile.elixir_scm") > @old_time
613626
end)
614627
end
615628

@@ -720,38 +733,6 @@ defmodule Mix.Tasks.Compile.ElixirTest do
720733
end)
721734
end
722735

723-
test "purges consolidation path if asked" do
724-
in_fixture("no_mixfile", fn ->
725-
File.write!("lib/a.ex", """
726-
defmodule A do
727-
defstruct []
728-
end
729-
730-
defimpl Inspect, for: A do
731-
def inspect(_, _), do: "sample"
732-
end
733-
""")
734-
735-
Mix.Project.push(MixTest.Case.Sample)
736-
assert Mix.Tasks.Compile.run([]) == {:ok, []}
737-
assert inspect(struct(A, [])) == "sample"
738-
739-
purge([A, B, Inspect.A])
740-
Mix.Task.clear()
741-
742-
assert capture_io(:stderr, fn ->
743-
{:ok, [_]} = Mix.Tasks.Compile.run(["--force"])
744-
end) =~
745-
"the Inspect protocol has already been consolidated"
746-
747-
purge([A, B, Inspect.A])
748-
Mix.Task.clear()
749-
consolidation = Mix.Project.consolidation_path()
750-
args = ["--force", "--purge-consolidation-path-if-stale", consolidation]
751-
assert Mix.Tasks.Compile.run(args) == {:ok, []}
752-
end)
753-
end
754-
755736
test "recompiles mtime changed files if content changed but not length" do
756737
in_fixture("no_mixfile", fn ->
757738
Mix.Project.push(MixTest.Case.Sample)
@@ -1344,7 +1325,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
13441325
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
13451326

13461327
assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:noop, []}
1347-
assert File.stat!("lib/a.ex").mtime == @old_time
1328+
assert mtime("lib/a.ex") == @old_time
13481329

13491330
Agent.update(:mix_recompile_raise, fn _ -> true end)
13501331

@@ -1729,4 +1710,180 @@ defmodule Mix.Tasks.Compile.ElixirTest do
17291710
assert Mix.Tasks.Compile.Elixir.run(["--no-optional-deps"]) == {:ok, []}
17301711
end)
17311712
end
1713+
1714+
describe "consolidation protocols" do
1715+
test "with local protocols", context do
1716+
in_tmp(context.test, fn ->
1717+
Mix.Project.push(MixTest.Case.Sample)
1718+
1719+
File.mkdir_p!("lib")
1720+
assert Mix.Task.run("compile")
1721+
1722+
# Define a local protocol
1723+
File.write!("lib/protocol.ex", """
1724+
defprotocol Compile.Protocol do
1725+
def foo(a, b)
1726+
end
1727+
""")
1728+
1729+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1730+
mark_as_old!("_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam")
1731+
1732+
# Implement a local protocol
1733+
File.write!("lib/impl.ex", """
1734+
defimpl Compile.Protocol, for: Integer do
1735+
def foo(a, b), do: a + b
1736+
end
1737+
""")
1738+
1739+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1740+
1741+
assert mark_as_old!("_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam") !=
1742+
@old_time
1743+
1744+
# Delete a local implementation
1745+
File.rm!("lib/impl.ex")
1746+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1747+
1748+
assert mark_as_old!("_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam") !=
1749+
@old_time
1750+
1751+
# Delete a local protocol
1752+
File.rm!("lib/protocol.ex")
1753+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1754+
refute File.regular?("_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam")
1755+
end)
1756+
end
1757+
1758+
test "compiles after converting a protocol into a standard module", context do
1759+
in_tmp(context.test, fn ->
1760+
Mix.Project.push(MixTest.Case.Sample)
1761+
1762+
File.mkdir_p!("lib")
1763+
Mix.Task.run("compile")
1764+
purge_protocol(Compile.Protocol)
1765+
1766+
# Define a local protocol
1767+
File.write!("lib/protocol.ex", """
1768+
defprotocol Compile.Protocol do
1769+
def foo(a)
1770+
end
1771+
1772+
defimpl Compile.Protocol, for: Integer do
1773+
def foo(a), do: a
1774+
end
1775+
""")
1776+
1777+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1778+
mark_as_old!("_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam")
1779+
File.rm!("lib/protocol.ex")
1780+
1781+
# Define a standard module
1782+
File.write!("lib/protocol.ex", """
1783+
defmodule Compile.Protocol do
1784+
end
1785+
""")
1786+
1787+
purge_protocol(Compile.Protocol)
1788+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1789+
1790+
# Delete a local protocol
1791+
File.rm!("lib/protocol.ex")
1792+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1793+
refute File.regular?("_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam")
1794+
end)
1795+
end
1796+
1797+
test "with deps protocols", context do
1798+
in_tmp(context.test, fn ->
1799+
Mix.Project.push(MixTest.Case.Sample)
1800+
1801+
File.mkdir_p!("lib")
1802+
Mix.Task.run("compile")
1803+
purge_protocol(String.Chars)
1804+
mark_as_old!("_build/dev/lib/sample/consolidated/Elixir.String.Chars.beam")
1805+
1806+
assert Mix.Tasks.Compile.Elixir.run([]) == {:noop, []}
1807+
assert mtime("_build/dev/lib/sample/consolidated/Elixir.String.Chars.beam") == @old_time
1808+
1809+
# Implement a deps protocol
1810+
File.write!("lib/struct.ex", """
1811+
defmodule Compile.Protocol.Struct do
1812+
defstruct a: nil
1813+
defimpl String.Chars do
1814+
def to_string(_), do: "ok"
1815+
end
1816+
end
1817+
""")
1818+
1819+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1820+
1821+
assert mark_as_old!("_build/dev/lib/sample/consolidated/Elixir.String.Chars.beam") !=
1822+
@old_time
1823+
1824+
# Delete the local implementation
1825+
File.rm!("lib/struct.ex")
1826+
assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}
1827+
1828+
assert mark_as_old!("_build/dev/lib/sample/consolidated/Elixir.String.Chars.beam") !=
1829+
@old_time
1830+
end)
1831+
end
1832+
1833+
test "keep relative path to their source" do
1834+
in_fixture("no_mixfile", fn ->
1835+
Mix.Project.push(MixTest.Case.Sample)
1836+
Mix.Task.run("compile")
1837+
1838+
# Load consolidated
1839+
:code.add_patha(~c"_build/dev/lib/sample/consolidated")
1840+
:code.purge(Enumerable)
1841+
:code.delete(Enumerable)
1842+
1843+
try do
1844+
Enumerable.impl_for!(:oops)
1845+
rescue
1846+
Protocol.UndefinedError ->
1847+
assert [{_, _, _, [file: ~c"lib/enum.ex"] ++ _} | _] = __STACKTRACE__
1848+
else
1849+
_ ->
1850+
flunk("Enumerable.impl_for!/1 should have failed")
1851+
after
1852+
purge_protocol(Enumerable)
1853+
end
1854+
end)
1855+
end
1856+
1857+
test "purges consolidation path if asked" do
1858+
in_fixture("no_mixfile", fn ->
1859+
File.write!("lib/a.ex", """
1860+
defmodule A do
1861+
defstruct []
1862+
end
1863+
1864+
defimpl Inspect, for: A do
1865+
def inspect(_, _), do: "sample"
1866+
end
1867+
""")
1868+
1869+
Mix.Project.push(MixTest.Case.Sample)
1870+
assert Mix.Tasks.Compile.run([]) == {:ok, []}
1871+
assert inspect(struct(A, [])) == "sample"
1872+
1873+
purge([A, B, Inspect.A])
1874+
Mix.Task.clear()
1875+
1876+
assert capture_io(:stderr, fn ->
1877+
{:ok, [_]} = Mix.Tasks.Compile.run(["--force"])
1878+
end) =~
1879+
"the Inspect protocol has already been consolidated"
1880+
1881+
purge([A, B, Inspect.A])
1882+
Mix.Task.clear()
1883+
consolidation = Mix.Project.consolidation_path()
1884+
args = ["--force", "--purge-consolidation-path-if-stale", consolidation]
1885+
assert Mix.Tasks.Compile.run(args) == {:ok, []}
1886+
end)
1887+
end
1888+
end
17321889
end

0 commit comments

Comments
 (0)