1# -*- coding: utf-8 -*-
2"""Tests the xonsh builtins."""
3from __future__ import unicode_literals, print_function
4import os
5import re
6import builtins
7import types
8from ast import AST
9
10import pytest
11
12from xonsh import built_ins
13from xonsh.built_ins import (
14    reglob,
15    pathsearch,
16    helper,
17    superhelper,
18    ensure_list_of_strs,
19    list_of_strs_or_callables,
20    list_of_list_of_strs_outer_product,
21    regexsearch,
22    globsearch,
23    expand_path,
24    convert_macro_arg,
25    in_macro_call,
26    call_macro,
27    enter_macro,
28)
29from xonsh.environ import Env
30
31from tools import skip_if_on_windows
32
33
34HOME_PATH = os.path.expanduser("~")
35
36
37@pytest.fixture(autouse=True)
38def xonsh_execer_autouse(xonsh_execer):
39    return xonsh_execer
40
41
42@pytest.mark.parametrize("testfile", reglob("test_.*"))
43def test_reglob_tests(testfile):
44    assert testfile.startswith("test_")
45
46
47@pytest.fixture
48def home_env(xonsh_builtins):
49    """Set `__xonsh_env__ ` to a new Env instance on `xonsh_builtins`"""
50    xonsh_builtins.__xonsh_env__ = Env(HOME=HOME_PATH)
51    return xonsh_builtins
52
53
54@skip_if_on_windows
55def test_repath_backslash(home_env):
56    exp = os.listdir(HOME_PATH)
57    exp = {p for p in exp if re.match(r"\w\w.*", p)}
58    exp = {os.path.join(HOME_PATH, p) for p in exp}
59    obs = set(pathsearch(regexsearch, r"~/\w\w.*"))
60    assert exp == obs
61
62
63@skip_if_on_windows
64def test_repath_HOME_PATH_itself(home_env):
65    exp = HOME_PATH
66    obs = pathsearch(regexsearch, "~")
67    assert 1 == len(obs)
68    assert exp == obs[0]
69
70
71@skip_if_on_windows
72def test_repath_HOME_PATH_contents(home_env):
73    exp = os.listdir(HOME_PATH)
74    exp = {os.path.join(HOME_PATH, p) for p in exp}
75    obs = set(pathsearch(regexsearch, "~/.*"))
76    assert exp == obs
77
78
79@skip_if_on_windows
80def test_repath_HOME_PATH_var(home_env):
81    exp = HOME_PATH
82    obs = pathsearch(regexsearch, "$HOME")
83    assert 1 == len(obs)
84    assert exp == obs[0]
85
86
87@skip_if_on_windows
88def test_repath_HOME_PATH_var_brace(home_env):
89    exp = HOME_PATH
90    obs = pathsearch(regexsearch, '${"HOME"}')
91    assert 1 == len(obs)
92    assert exp == obs[0]
93
94
95def test_helper_int(home_env):
96    helper(int, "int")
97
98
99def test_helper_helper(home_env):
100    helper(helper, "helper")
101
102
103def test_helper_env(home_env):
104    helper(Env, "Env")
105
106
107def test_superhelper_int(home_env):
108    superhelper(int, "int")
109
110
111def test_superhelper_helper(home_env):
112    superhelper(helper, "helper")
113
114
115def test_superhelper_env(home_env):
116    superhelper(Env, "Env")
117
118
119@pytest.mark.parametrize(
120    "exp, inp", [(["yo"], "yo"), (["yo"], ["yo"]), (["42"], 42), (["42"], [42])]
121)
122def test_ensure_list_of_strs(exp, inp):
123    obs = ensure_list_of_strs(inp)
124    assert exp == obs
125
126
127f = lambda x: 20
128
129
130@pytest.mark.parametrize(
131    "exp, inp",
132    [
133        (["yo"], "yo"),
134        (["yo"], ["yo"]),
135        (["42"], 42),
136        (["42"], [42]),
137        ([f], f),
138        ([f], [f]),
139    ],
140)
141def test_list_of_strs_or_callables(exp, inp):
142    obs = list_of_strs_or_callables(inp)
143    assert exp == obs
144
145
146@pytest.mark.parametrize(
147    "inp, exp",
148    [
149        (["x", ["y", "z"]], ["xy", "xz"]),
150        (["x", ["y", "z"], ["a"]], ["xya", "xza"]),
151        ([["y", "z"], ["a", "b"]], ["ya", "yb", "za", "zb"]),
152    ],
153)
154def test_list_of_list_of_strs_outer_product(xonsh_builtins, inp, exp):
155    obs = list_of_list_of_strs_outer_product(inp)
156    assert exp == obs
157
158
159@pytest.mark.parametrize(
160    "s",
161    [
162        "~",
163        "~/",
164        "x=~/place",
165        "x=one:~/place",
166        "x=one:~/place:~/yo",
167        "x=~/one:~/place:~/yo",
168    ],
169)
170def test_expand_path(s, home_env):
171    if os.sep != "/":
172        s = s.replace("/", os.sep)
173    if os.pathsep != ":":
174        s = s.replace(":", os.pathsep)
175    assert expand_path(s) == s.replace("~", HOME_PATH)
176
177
178@pytest.mark.parametrize("kind", [str, "s", "S", "str", "string"])
179def test_convert_macro_arg_str(kind):
180    raw_arg = "value"
181    arg = convert_macro_arg(raw_arg, kind, None, None)
182    assert arg is raw_arg
183
184
185@pytest.mark.parametrize("kind", [AST, "a", "Ast"])
186def test_convert_macro_arg_ast(kind):
187    raw_arg = "42"
188    arg = convert_macro_arg(raw_arg, kind, {}, None)
189    assert isinstance(arg, AST)
190
191
192@pytest.mark.parametrize("kind", [types.CodeType, compile, "c", "code", "compile"])
193def test_convert_macro_arg_code(kind):
194    raw_arg = "42"
195    arg = convert_macro_arg(raw_arg, kind, {}, None)
196    assert isinstance(arg, types.CodeType)
197
198
199@pytest.mark.parametrize("kind", [eval, None, "v", "eval"])
200def test_convert_macro_arg_eval(kind):
201    # literals
202    raw_arg = "42"
203    arg = convert_macro_arg(raw_arg, kind, {}, None)
204    assert arg == 42
205    # exprs
206    raw_arg = "x + 41"
207    arg = convert_macro_arg(raw_arg, kind, {}, {"x": 1})
208    assert arg == 42
209
210
211@pytest.mark.parametrize("kind", [exec, "x", "exec"])
212def test_convert_macro_arg_exec(kind):
213    # at global scope
214    raw_arg = "def f(x, y):\n    return x + y"
215    glbs = {}
216    arg = convert_macro_arg(raw_arg, kind, glbs, None)
217    assert arg is None
218    assert "f" in glbs
219    assert glbs["f"](1, 41) == 42
220    # at local scope
221    raw_arg = "def g(z):\n    return x + z\ny += 42"
222    glbs = {"x": 40}
223    locs = {"y": 1}
224    arg = convert_macro_arg(raw_arg, kind, glbs, locs)
225    assert arg is None
226    assert "g" in locs
227    assert locs["g"](1) == 41
228    assert "y" in locs
229    assert locs["y"] == 43
230
231
232@pytest.mark.parametrize("kind", [type, "t", "type"])
233def test_convert_macro_arg_eval(kind):
234    # literals
235    raw_arg = "42"
236    arg = convert_macro_arg(raw_arg, kind, {}, None)
237    assert arg is int
238    # exprs
239    raw_arg = "x + 41"
240    arg = convert_macro_arg(raw_arg, kind, {}, {"x": 1})
241    assert arg is int
242
243
244def test_in_macro_call():
245    def f():
246        pass
247
248    with in_macro_call(f, True, True):
249        assert f.macro_globals
250        assert f.macro_locals
251    assert not hasattr(f, "macro_globals")
252    assert not hasattr(f, "macro_locals")
253
254
255@pytest.mark.parametrize("arg", ["x", "42", "x + y"])
256def test_call_macro_str(arg):
257    def f(x: str):
258        return x
259
260    rtn = call_macro(f, [arg], None, None)
261    assert rtn is arg
262
263
264@pytest.mark.parametrize("arg", ["x", "42", "x + y"])
265def test_call_macro_ast(arg):
266    def f(x: AST):
267        return x
268
269    rtn = call_macro(f, [arg], {}, None)
270    assert isinstance(rtn, AST)
271
272
273@pytest.mark.parametrize("arg", ["x", "42", "x + y"])
274def test_call_macro_code(arg):
275    def f(x: compile):
276        return x
277
278    rtn = call_macro(f, [arg], {}, None)
279    assert isinstance(rtn, types.CodeType)
280
281
282@pytest.mark.parametrize("arg", ["x", "42", "x + y"])
283def test_call_macro_eval(arg):
284    def f(x: eval):
285        return x
286
287    rtn = call_macro(f, [arg], {"x": 42, "y": 0}, None)
288    assert rtn == 42
289
290
291@pytest.mark.parametrize(
292    "arg", ["if y:\n    pass", "if 42:\n    pass", "if x + y:\n    pass"]
293)
294def test_call_macro_exec(arg):
295    def f(x: exec):
296        return x
297
298    rtn = call_macro(f, [arg], {"x": 42, "y": 0}, None)
299    assert rtn is None
300
301
302@pytest.mark.parametrize("arg", ["x", "42", "x + y"])
303def test_call_macro_raw_arg(arg):
304    def f(x: str):
305        return x
306
307    rtn = call_macro(f, ["*", arg], {"x": 42, "y": 0}, None)
308    assert rtn == 42
309
310
311@pytest.mark.parametrize("arg", ["x", "42", "x + y"])
312def test_call_macro_raw_kwarg(arg):
313    def f(x: str):
314        return x
315
316    rtn = call_macro(f, ["*", "x=" + arg], {"x": 42, "y": 0}, None)
317    assert rtn == 42
318
319
320@pytest.mark.parametrize("arg", ["x", "42", "x + y"])
321def test_call_macro_raw_kwargs(arg):
322    def f(x: str):
323        return x
324
325    rtn = call_macro(f, ["*", '**{"x" :' + arg + "}"], {"x": 42, "y": 0}, None)
326    assert rtn == 42
327
328
329def test_enter_macro():
330    obj = lambda: None
331    rtn = enter_macro(obj, "wakka", True, True)
332    assert obj is rtn
333    assert obj.macro_block == "wakka"
334    assert obj.macro_globals
335    assert obj.macro_locals
336