-
Notifications
You must be signed in to change notification settings - Fork 196
/
mix_test.case.ex
143 lines (120 loc) · 3.29 KB
/
mix_test.case.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
defmodule ElixirLS.Utils.MixTest.Case do
# This module is based heavily on MixTest.Case in Elixir's tests
# https://github.com/elixir-lang/elixir/blob/db64b413a036c01c8e1cac8dd5e1c65107d90176/lib/mix/test/test_helper.exs#L29
use ExUnit.CaseTemplate
using do
quote do
import ElixirLS.Utils.MixTest.Case
end
end
@apps Enum.map(Application.loaded_applications(), &elem(&1, 0))
@allowed_apps ~w(
iex
elixir_sense
debug_adapter
elixir_ls_utils
language_server
stream_data
statistex
patch
deep_merge
erlex_vendored
benchee
path_glob_vendored
dialyzer
dialyxir_vendored
erl2ex_vendored
jason_v
)a
setup do
on_exit(fn ->
Application.start(:logger)
Mix.env(:dev)
Mix.target(:host)
Mix.Task.clear()
Mix.Shell.Process.flush()
Mix.State.clear_cache()
Mix.ProjectStack.clear_stack()
delete_tmp_paths()
for {app, _, _} <- Application.loaded_applications(),
app not in @apps,
app not in @allowed_apps do
Application.stop(app)
Application.unload(app)
end
end)
:ok
end
def fixture_path(dir) do
Path.expand("fixtures", dir)
end
def fixture_path(dir, extension) do
Path.join(fixture_path(dir), remove_colons(extension))
end
def tmp_path do
Path.expand("../../.tmp", __DIR__)
end
def tmp_path(extension) do
Path.join(tmp_path(), remove_colons(extension))
end
defp remove_colons(term) do
term
|> to_string()
|> String.replace(":", "")
end
def purge(modules) do
Enum.each(modules, fn m ->
:code.purge(m)
:code.delete(m)
end)
end
def in_tmp(which, function) do
path = tmp_path(which)
File.rm_rf!(path)
File.mkdir_p!(path)
File.cd!(path, function)
end
defmacro in_fixture(dir, which, block) do
module = inspect(__CALLER__.module)
function = Atom.to_string(elem(__CALLER__.function, 0))
tmp = Path.join(module, function)
quote do
unquote(__MODULE__).in_fixture(unquote(dir), unquote(which), unquote(tmp), unquote(block))
end
end
def in_fixture(dir, which, tmp, function) do
src = fixture_path(dir, which)
dest = tmp_path(String.replace(tmp, ":", "_"))
flag = String.to_charlist(tmp_path())
File.rm_rf!(dest)
File.mkdir_p!(dest)
File.cp_r!(src, dest)
get_path = :code.get_path()
previous = :code.all_loaded()
try do
File.cd!(dest, function)
after
:code.set_path(get_path)
for {mod, file} <- :code.all_loaded() -- previous,
file == [] or (is_list(file) and List.starts_with?(file, flag)) do
purge([mod])
end
end
end
defp delete_tmp_paths do
tmp = tmp_path() |> String.to_charlist()
for path <- :code.get_path(), :string.str(path, tmp) != 0, do: :code.del_path(path)
end
def capture_log_and_io(device, fun) when is_function(fun, 0) do
# Logger gets stopped during some tests so restart it to be able to capture logs (and kept the
# test output clean)
Application.ensure_started(:logger)
log =
ExUnit.CaptureLog.capture_log(fn ->
io = ExUnit.CaptureIO.capture_io(device, fun)
send(self(), {:block_result, io})
end)
assert_received {:block_result, io_result}
{log, io_result}
end
end