1Code.require_file("../test_helper.exs", __DIR__)
2
3defmodule ExUnit.CaptureLogTest do
4  use ExUnit.Case
5
6  require Logger
7
8  import ExUnit.CaptureLog
9
10  setup_all do
11    :ok = Logger.remove_backend(:console)
12    on_exit(fn -> Logger.add_backend(:console, flush: true) end)
13  end
14
15  test "no output" do
16    assert capture_log(fn -> nil end) == ""
17  end
18
19  test "assert inside" do
20    group_leader = Process.group_leader()
21
22    try do
23      capture_log(fn ->
24        assert false
25      end)
26    rescue
27      error in [ExUnit.AssertionError] ->
28        assert error.message == "Expected truthy, got false"
29    end
30
31    # Ensure no leakage on failures
32    assert group_leader == Process.group_leader()
33    refute_received {:gen_event_EXIT, _, _}
34  end
35
36  test "level aware" do
37    assert capture_log([level: :warn], fn ->
38             Logger.info("here")
39           end) == ""
40  end
41
42  @tag timeout: 2000
43  test "capture removal on exit" do
44    {_pid, ref} =
45      spawn_monitor(fn ->
46        capture_log(fn ->
47          spawn_link(Kernel, :exit, [:shutdown])
48          Process.sleep(:infinity)
49        end)
50      end)
51
52    assert_receive {:DOWN, ^ref, _, _, :shutdown}
53    wait_capture_removal()
54  end
55
56  test "log tracking" do
57    logged =
58      capture_log(fn ->
59        Logger.info("one")
60
61        logged = capture_log(fn -> Logger.error("one") end)
62        send(test = self(), {:nested, logged})
63
64        Logger.warn("two")
65
66        spawn(fn ->
67          Logger.debug("three")
68          send(test, :done)
69        end)
70
71        receive do: (:done -> :ok)
72      end)
73
74    assert logged
75    assert logged =~ "[info]  one\n"
76    assert logged =~ "[warning] two\n"
77    assert logged =~ "[debug] three\n"
78    assert logged =~ "[error] one\n"
79
80    receive do
81      {:nested, logged} ->
82        assert logged =~ "[error] one\n"
83        refute logged =~ "[warning] two\n"
84    end
85  end
86
87  test "with_log" do
88    {4, log} =
89      with_log(fn ->
90        Logger.error("calculating...")
91        2 + 2
92      end)
93
94    assert log =~ "calculating..."
95  end
96
97  defp wait_capture_removal() do
98    case :gen_event.which_handlers(Logger) do
99      [Logger.Config] ->
100        :ok
101
102      _otherwise ->
103        Process.sleep(20)
104        wait_capture_removal()
105    end
106  end
107end
108