1Code.require_file "test_helper.exs", __DIR__
2Code.require_file "../lib/server.exs", __DIR__
3
4defmodule ServerTest do
5  use ExUnit.Case
6  import ExUnit.CaptureIO
7
8  setup_all do
9    on_exit fn ->
10      {_status, files} = File.ls Path.expand("fixtures", __DIR__)
11      files |> Enum.each(fn(file) ->
12        unless file == ".gitkeep" do
13          File.rm Path.expand("fixtures/#{file}", __DIR__)
14        end
15      end)
16    end
17  end
18
19  test "Expression completion" do
20    assert send_signal("COMP { 'def', [context: Elixir, imports: [], aliases: []]}") =~ """
21    defoverridable/1
22    """
23  end
24
25  test "Documentation lookup" do
26    assert send_signal("DOCL { 'List', [context: Elixir, imports: [], aliases: []]}") =~ """
27    \e[0m\n\e[7m\e[33m                                      List                                      \e[0m\n\e[0m
28    """
29  end
30
31  test "Getting the definition source file information of code" do
32    assert send_signal("DEFL {\"List,delete\", [context: Elixir, imports: [], aliases: []]}") =~ "/lib/elixir/lib/list.ex"
33  end
34
35  test "Evaluate the content of a file" do
36    filename = Path.expand("fixtures/eval_fixture.exs", __DIR__)
37    File.write(filename, "1+1")
38    assert send_signal("EVAL { :eval, '#{filename}' }") =~ "2"
39  end
40
41  test "Evaluate and quote the content of a file" do
42    filename = Path.expand("fixtures/eval_and_quote_fixture.exs", __DIR__)
43    File.write(filename, "[4,2,1,3] |> Enum.sort")
44    assert send_signal("EVAL { :quote, '#{filename}' }") =~ """
45    {{:., [line: 1], [{:__aliases__, [counter: 0, line: 1], [:Enum]}, :sort]},\n   [line: 1], []}]}
46    """
47  end
48
49  test "Expand macro once" do
50    filename = Path.expand("fixtures/macro_expand_once_fixture.exs", __DIR__)
51    File.write(filename, "unless true, do: IO.puts \"this should never be printed\"")
52    assert send_signal("EVAL { :expand_once, '#{filename}' }") =~ """
53    if(true) do
54      nil
55    else
56      IO.puts("this should never be printed")
57    end
58    """
59  end
60
61  test "Expand macro" do
62    filename = Path.expand("fixtures/macro_expand_fixture.exs", __DIR__)
63    File.write(filename, "unless true, do: IO.puts \"this should never be printed\"")
64    assert send_signal("EVAL { :expand, '#{filename}' }") =~ """
65    case(true) do
66      x when x in [false, nil] ->
67        IO.puts("this should never be printed")
68      _ ->
69        nil
70    end
71    """
72  end
73
74  test "Get all available application modules" do
75    assert send_signal("INFO { :type, :modules }") =~ """
76    Elixir.Logger
77    Elixir.Logger.Formatter
78    Elixir.Logger.Translator
79    """
80  end
81
82  test "Get all available mix tasks by name" do
83    assert send_signal("INFO { :type, :mixtasks }") =~ """
84    app.start
85    archive
86    archive.build
87    archive.install
88    archive.uninstall
89    clean
90    cmd
91    compile
92    """
93  end
94
95  # The IEx.Helpers.t and IEx.Helpers.i are functionality which come with
96  # Elixir version 1.2.0
97  if Version.match?(System.version, ">=1.2.0-rc") do
98    test "Get information from data type" do
99      assert send_signal("INFO { :type, :info, List}") =~ """
100      Reference modules\e[0m\n\e[22m  Module, Atom\e[0m\nEND-OF-INFO
101      """
102    end
103
104    test "Don't crash server if data type argument is faulty" do
105      assert send_signal("INFO { :type, :info, whatever}") =~ """
106      END-OF-INFO
107      """
108    end
109
110    test "Prints the types for the given module or for the given function/arity pair" do
111      assert send_signal("INFO { :type, :types, 'Agent'}") =~ """
112      @type agent() :: pid() | {atom(), node()} | name()\e[0m\n\e[22m@type state() :: term()\e[0m\nEND-OF-INFO
113      """
114
115      assert send_signal("INFO { :type, :types, 'Agent.on_start/0'}") =~ """
116      @type on_start() :: {:ok, pid()} | {:error, {:already_started, pid()} | term()}\e[0m
117      """
118    end
119  end
120
121  defp send_signal(signal) do
122    capture_io(fn ->
123      Alchemist.Server.read_input(signal)
124    end)
125  end
126end
127