1Code.require_file("../test_helper.exs", __DIR__)
2
3defmodule Kernel.ImportTest do
4  use ExUnit.Case, async: true
5
6  # This should not warn due to the empty only
7  import URI, only: []
8
9  defmodule ImportAvailable do
10    defmacro flatten do
11      [flatten: 1]
12    end
13  end
14
15  test "multi-call" do
16    assert [List, String] = import(Elixir.{List, unquote(:String)})
17    assert keymember?([a: 1], :a, 0)
18    assert valid?("ø")
19  end
20
21  test "blank multi-call" do
22    assert [] = import(List.{})
23    # Buggy local duplicate is untouched
24    assert duplicate([1], 2) == [1]
25  end
26
27  test "multi-call with options" do
28    assert [List] = import(Elixir.{List}, only: [])
29    # Buggy local duplicate is untouched
30    assert duplicate([1], 2) == [1]
31  end
32
33  test "import all" do
34    assert :lists = import(:lists)
35    assert flatten([1, [2], 3]) == [1, 2, 3]
36  end
37
38  test "import except none" do
39    import :lists, except: []
40    assert flatten([1, [2], 3]) == [1, 2, 3]
41  end
42
43  test "import except one" do
44    import :lists, except: [duplicate: 2]
45    assert flatten([1, [2], 3]) == [1, 2, 3]
46    # Buggy local duplicate is untouched
47    assert duplicate([1], 2) == [1]
48  end
49
50  test "import only via macro" do
51    require ImportAvailable
52    import :lists, only: ImportAvailable.flatten()
53    assert flatten([1, [2], 3]) == [1, 2, 3]
54  end
55
56  defmacrop dynamic_opts do
57    [only: [flatten: 1]]
58  end
59
60  test "import with options via macro" do
61    import :lists, dynamic_opts()
62    assert flatten([1, [2], 3]) == [1, 2, 3]
63  end
64
65  test "import with double except" do
66    import :lists, except: [duplicate: 2]
67    import :lists, except: [each: 2]
68    assert append([1], [2, 3]) == [1, 2, 3]
69    # Buggy local duplicate is untouched
70    assert duplicate([1], 2) == [1]
71  end
72
73  test "import except none respects previous import with except" do
74    import :lists, except: [duplicate: 2]
75    import :lists, except: []
76    assert append([1], [2, 3]) == [1, 2, 3]
77    # Buggy local duplicate is untouched
78    assert duplicate([1], 2) == [1]
79  end
80
81  test "import except none respects previous import with only" do
82    import :lists, only: [append: 2]
83    import :lists, except: []
84    assert append([1], [2, 3]) == [1, 2, 3]
85    # Buggy local duplicate is untouched
86    assert duplicate([1], 2) == [1]
87  end
88
89  defmodule Underscored do
90    def hello(x), do: x
91    def __underscore__(x), do: x
92  end
93
94  defmodule ExplicitUnderscored do
95    def __underscore__(x), do: x * 2
96  end
97
98  test "import only with underscore" do
99    import Underscored, only: [__underscore__: 1]
100    assert __underscore__(3) == 3
101  end
102
103  test "import non-underscored" do
104    import ExplicitUnderscored, only: [__underscore__: 1]
105    import Underscored
106    assert hello(2) == 2
107    assert __underscore__(3) == 6
108  end
109
110  defmodule MessedBitwise do
111    defmacro bnot(x), do: x
112    defmacro bor(x, _), do: x
113  end
114
115  import Bitwise, only: :functions
116
117  test "conflicting imports with only and except" do
118    import Bitwise, only: :functions, except: [bnot: 1]
119    import MessedBitwise, only: [bnot: 1]
120    assert bnot(0) == 0
121    assert bor(0, 1) == 1
122  end
123
124  # This test is asserting that the imports in the
125  # test above do not affect this test.
126  test "imports from other functions do not leak" do
127    assert band(1, 1) == 1
128    assert bor(0, 1) == 1
129    assert bnot(0) == -1
130  end
131
132  test "import ambiguous" do
133    # Simply make sure that we can indeed import functions with
134    # the same name and arity from different modules without the
135    # import itself causing any errors.
136    import List
137    import String
138  end
139
140  test "import many" do
141    [import(List), import(String)]
142    assert capitalize("foo") == "Foo"
143    assert flatten([1, [2], 3]) == [1, 2, 3]
144  end
145
146  defmodule ModuleWithSigils do
147    def sigil_i(string, []), do: String.to_integer(string)
148
149    defmacro sigil_I(string, []) do
150      quote do
151        String.to_integer(unquote(string))
152      end
153    end
154
155    def sigil_w(_string, []), do: []
156
157    def bnot(x), do: x
158    defmacro bor(x, _), do: x
159  end
160
161  test "import only sigils" do
162    import Kernel, except: [sigil_w: 2]
163    import ModuleWithSigils, only: :sigils
164
165    # Ensure that both function and macro sigils are imported
166    assert ~i'10' == 10
167    assert ~I'10' == 10
168    assert ~w(abc def) == []
169
170    # Ensure that non-sigil functions and macros from ModuleWithSigils were not loaded
171    assert bnot(0) == -1
172    assert bor(0, 1) == 1
173  end
174
175  test "import only sigils with except" do
176    import ModuleWithSigils, only: :sigils, except: [sigil_w: 2]
177
178    assert ~i'10' == 10
179    assert ~I'10' == 10
180    assert ~w(abc def) == ["abc", "def"]
181  end
182
183  test "import only removes the non-import part" do
184    import List
185    import List, only: :macros
186    # Buggy local duplicate is used because we asked only for macros
187    assert duplicate([1], 2) == [1]
188  end
189
190  test "import lexical on if" do
191    if false do
192      import List
193      flatten([1, [2], 3])
194      flunk()
195    else
196      # Buggy local duplicate is untouched
197      assert duplicate([1], 2) == [1]
198    end
199  end
200
201  test "import lexical on case" do
202    case true do
203      false ->
204        import List
205        flatten([1, [2], 3])
206        flunk()
207
208      true ->
209        # Buggy local duplicate is untouched
210        assert duplicate([1], 2) == [1]
211    end
212  end
213
214  test "import lexical on for" do
215    for x <- [1, 2, 3], x > 10 do
216      import List
217      flatten([1, [2], 3])
218      flunk()
219    end
220
221    # Buggy local duplicate is untouched
222    assert duplicate([1], 2) == [1]
223  end
224
225  test "import lexical on with" do
226    with true <- false do
227      import List
228      flatten([1, [2], 3])
229      flunk()
230    end
231
232    # Buggy local duplicate is untouched
233    assert duplicate([1], 2) == [1]
234  end
235
236  test "import lexical on try" do
237    try do
238      import List
239      flatten([1, [2], 3])
240      flunk()
241    catch
242      _, _ ->
243        # Buggy local duplicate is untouched
244        assert duplicate([1], 2) == [1]
245    end
246
247    # Buggy local duplicate is untouched
248    assert duplicate([1], 2) == [1]
249  end
250
251  defp duplicate(list, _), do: list
252end
253