1# -*- coding: utf-8 -*-
2"""Tests the xonsh main function."""
3from __future__ import unicode_literals, print_function
4from contextlib import contextmanager
5
6import builtins
7import os.path
8import sys
9
10import xonsh.main
11from xonsh.main import XonshMode
12from xonsh.environ import Env
13import pytest
14from tools import TEST_DIR
15
16
17def Shell(*args, **kwargs):
18    pass
19
20
21@pytest.fixture
22def shell(xonsh_builtins, xonsh_execer, monkeypatch):
23    """Xonsh Shell Mock"""
24    Shell.shell_type_aliases = {"rl": "readline"}
25    monkeypatch.setattr(xonsh.main, "Shell", Shell)
26
27
28def test_premain_no_arg(shell, monkeypatch):
29    monkeypatch.setattr(sys.stdin, "isatty", lambda: True)
30    xonsh.main.premain([])
31    assert builtins.__xonsh_env__.get("XONSH_LOGIN")
32
33
34def test_premain_interactive(shell):
35    xonsh.main.premain(["-i"])
36    assert builtins.__xonsh_env__.get("XONSH_INTERACTIVE")
37
38
39def test_premain_login_command(shell):
40    xonsh.main.premain(["-l", "-c", 'echo "hi"'])
41    assert builtins.__xonsh_env__.get("XONSH_LOGIN")
42
43
44def test_premain_login(shell):
45    xonsh.main.premain(["-l"])
46    assert builtins.__xonsh_env__.get("XONSH_LOGIN")
47
48
49def test_premain_D(shell):
50    xonsh.main.premain(["-DTEST1=1616", "-DTEST2=LOL"])
51    assert builtins.__xonsh_env__.get("TEST1") == "1616"
52    assert builtins.__xonsh_env__.get("TEST2") == "LOL"
53
54
55def test_premain_custom_rc(shell, tmpdir, monkeypatch):
56    monkeypatch.setattr(sys.stdin, "isatty", lambda: True)
57    builtins.__xonsh_env__ = Env(XONSH_CACHE_SCRIPTS=False)
58    f = tmpdir.join("wakkawakka")
59    f.write("print('hi')")
60    args = xonsh.main.premain(["--rc", f.strpath])
61    assert args.mode == XonshMode.interactive
62    assert f.strpath in builtins.__xonsh_env__.get("XONSHRC")
63
64
65def test_no_rc_with_script(shell, tmpdir):
66    args = xonsh.main.premain(["tests/sample.xsh"])
67    assert not (args.mode == XonshMode.interactive)
68
69
70def test_force_interactive_rc_with_script(shell, tmpdir):
71    args = xonsh.main.premain(["-i", "tests/sample.xsh"])
72    assert builtins.__xonsh_env__.get("XONSH_INTERACTIVE")
73
74
75def test_force_interactive_custom_rc_with_script(shell, tmpdir):
76    """Calling a custom RC file on a script-call with the interactive flag
77    should run interactively
78    """
79    builtins.__xonsh_env__ = Env(XONSH_CACHE_SCRIPTS=False)
80    f = tmpdir.join("wakkawakka")
81    f.write("print('hi')")
82    args = xonsh.main.premain(["-i", "--rc", f.strpath, "tests/sample.xsh"])
83    assert args.mode == XonshMode.interactive
84    assert f.strpath in builtins.__xonsh_env__.get("XONSHRC")
85
86
87def test_custom_rc_with_script(shell, tmpdir):
88    """Calling a custom RC file on a script-call without the interactive flag
89    should not run interactively
90    """
91    f = tmpdir.join("wakkawakka")
92    f.write("print('hi')")
93    args = xonsh.main.premain(["--rc", f.strpath, "tests/sample.xsh"])
94    assert not (args.mode == XonshMode.interactive)
95
96
97def test_premain_no_rc(shell, tmpdir):
98    xonsh.main.premain(["--no-rc"])
99    assert not builtins.__xonsh_env__.get("XONSHRC")
100
101
102@pytest.mark.parametrize(
103    "arg", ["", "-i", "-vERSION", "-hAALP", "TTTT", "-TT", "--TTT"]
104)
105def test_premain_with_file_argument(arg, shell):
106    xonsh.main.premain(["tests/sample.xsh", arg])
107    assert not (builtins.__xonsh_env__.get("XONSH_INTERACTIVE"))
108
109
110def test_premain_interactive__with_file_argument(shell):
111    xonsh.main.premain(["-i", "tests/sample.xsh"])
112    assert builtins.__xonsh_env__.get("XONSH_INTERACTIVE")
113
114
115@pytest.mark.parametrize("case", ["----", "--hep", "-TT", "--TTTT"])
116def test_premain_invalid_arguments(shell, case, capsys):
117    with pytest.raises(SystemExit):
118        xonsh.main.premain([case])
119    assert "unrecognized argument" in capsys.readouterr()[1]
120
121
122def test_xonsh_failback(shell, monkeypatch):
123    failback_checker = []
124    monkeypatch.setattr(sys, "stderr", open(os.devnull, "w"))
125
126    def mocked_main(*args):
127        raise Exception("A fake failure")
128
129    monkeypatch.setattr(xonsh.main, "main_xonsh", mocked_main)
130
131    def mocked_execlp(f, *args):
132        failback_checker.append(f)
133        failback_checker.append(args[0])
134
135    monkeypatch.setattr(os, "execlp", mocked_execlp)
136    monkeypatch.setattr(os.path, "exists", lambda x: True)
137    monkeypatch.setattr(sys, "argv", ["xonsh", "-i"])
138
139    @contextmanager
140    def mocked_open(*args):
141        yield ["/usr/bin/xonsh", "/usr/bin/screen", "bash", "/bin/xshell"]
142
143    monkeypatch.setattr(builtins, "open", mocked_open)
144
145    xonsh.main.main()
146    assert failback_checker == ["/bin/xshell", "/bin/xshell"]
147
148
149def test_xonsh_failback_single(shell, monkeypatch):
150    class FakeFailureError(Exception):
151        pass
152
153    def mocked_main(*args):
154        raise FakeFailureError()
155
156    monkeypatch.setattr(xonsh.main, "main_xonsh", mocked_main)
157    monkeypatch.setattr(sys, "argv", ["xonsh", "-c", "echo", "foo"])
158    monkeypatch.setattr(sys, "stderr", open(os.devnull, "w"))
159
160    with pytest.raises(FakeFailureError):
161        xonsh.main.main()
162
163
164def test_xonsh_failback_script_from_file(shell, monkeypatch):
165    checker = []
166
167    def mocked_execlp(f, *args):
168        checker.append(f)
169
170    monkeypatch.setattr(os, "execlp", mocked_execlp)
171
172    script = os.path.join(TEST_DIR, "scripts", "raise.xsh")
173    monkeypatch.setattr(sys, "argv", ["xonsh", script])
174    monkeypatch.setattr(sys, "stderr", open(os.devnull, "w"))
175    with pytest.raises(Exception):
176        xonsh.main.main()
177    assert len(checker) == 0
178