-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest_cli.py
More file actions
135 lines (124 loc) · 6.28 KB
/
Copy pathtest_cli.py
File metadata and controls
135 lines (124 loc) · 6.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
from __future__ import annotations
import os
import subprocess
import tempfile
import unittest
import venv
from pathlib import Path
from unittest import mock
from yieldskill import _cli
class CliTest(unittest.TestCase):
def test_missing_runtime_fails_without_path_fallback(self) -> None:
with mock.patch.object(_cli.Path, "is_file", return_value=False):
with self.assertRaisesRegex(FileNotFoundError, "packaged Yield runtime is missing"):
_cli.runtime_path("linux")
def test_unix_replaces_process_and_forwards_arguments(self) -> None:
with tempfile.TemporaryDirectory() as directory:
binary = Path(directory) / "yskill"
binary.touch()
with mock.patch.object(_cli, "runtime_path", return_value=binary):
with mock.patch.dict(os.environ, {}, clear=True):
with mock.patch.object(
os, "execve", side_effect=RuntimeError("exec")
) as execute:
with self.assertRaisesRegex(RuntimeError, "exec"):
_cli.run(["test", "skill"], "linux")
call = execute.call_args
self.assertEqual(call.args[:2], (str(binary), [str(binary), "test", "skill"]))
self.assertEqual(call.args[2]["YIELD_LANGUAGE"], "python")
self.assertEqual(call.args[2]["YIELD_PYTHON"], os.sys.executable)
self.assertEqual(
call.args[2]["PATH"].split(os.pathsep)[0],
str(Path(os.sys.executable).absolute().parent),
)
def test_windows_preserves_exit_code_and_arguments(self) -> None:
with tempfile.TemporaryDirectory() as directory:
binary = Path(directory) / "yskill.exe"
binary.touch()
completed = mock.Mock(returncode=23)
with mock.patch.object(_cli, "runtime_path", return_value=binary):
with mock.patch.dict(os.environ, {}, clear=True):
with mock.patch.object(
_cli.subprocess, "run", return_value=completed
) as execute:
self.assertEqual(_cli.run(["--version"], "win32"), 23)
call = execute.call_args
self.assertEqual(call.args[0], [str(binary), "--version"])
self.assertFalse(call.kwargs["check"])
self.assertEqual(call.kwargs["env"]["YIELD_LANGUAGE"], "python")
self.assertEqual(call.kwargs["env"]["YIELD_PYTHON"], os.sys.executable)
self.assertEqual(
call.kwargs["env"]["PATH"].split(os.pathsep)[0],
str(Path(os.sys.executable).absolute().parent),
)
def test_selected_virtual_environment_is_first_on_path(self) -> None:
with tempfile.TemporaryDirectory() as directory:
binary = Path(directory) / "yskill"
binary.touch()
python = Path(directory) / ".venv" / "bin" / "python"
python.parent.mkdir(parents=True)
python.touch()
with mock.patch.object(_cli, "runtime_path", return_value=binary):
with mock.patch.dict(
os.environ, {"YIELD_PYTHON": str(python), "PATH": "/usr/bin"}, clear=True
):
with mock.patch.object(
os, "execve", side_effect=RuntimeError("exec")
) as execute:
with self.assertRaisesRegex(RuntimeError, "exec"):
_cli.run([], "linux")
environment = execute.call_args.args[2]
self.assertEqual(environment["YIELD_PYTHON"], str(python))
self.assertEqual(environment["PATH"], f"{python.absolute().parent}{os.pathsep}/usr/bin")
def test_virtual_environment_symlink_keeps_its_lexical_bin_directory(self) -> None:
with tempfile.TemporaryDirectory() as directory:
binary = Path(directory) / "yskill"
binary.touch()
system = Path(directory) / "system" / "python"
system.parent.mkdir(parents=True)
system.touch()
python = Path(directory) / ".venv" / "bin" / "python"
python.parent.mkdir(parents=True)
python.symlink_to(system)
with mock.patch.object(_cli, "runtime_path", return_value=binary):
with mock.patch.dict(
os.environ, {"YIELD_PYTHON": str(python), "PATH": "/usr/bin"}, clear=True
):
with mock.patch.object(
os, "execve", side_effect=RuntimeError("exec")
) as execute:
with self.assertRaisesRegex(RuntimeError, "exec"):
_cli.run([], "linux")
environment = execute.call_args.args[2]
self.assertEqual(environment["PATH"].split(os.pathsep)[0], str(python.parent))
@unittest.skipIf(os.name == "nt", "Unix execve integration test")
def test_unactivated_virtual_environment_commands_reach_the_runtime(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
environment = root / ".venv"
venv.EnvBuilder(with_pip=False).create(environment)
python = environment / "bin" / "python"
tool = environment / "bin" / "yield-venv-tool"
tool.write_text("#!/bin/sh\necho venv-tool-ready\n")
tool.chmod(0o755)
runtime = root / "runtime"
runtime.write_text("#!/bin/sh\npython --version >/dev/null && yield-venv-tool\n")
runtime.chmod(0o755)
script = (
"from yieldskill import _cli; "
f"_cli.runtime_path=lambda platform=None: __import__('pathlib').Path({str(runtime)!r}); "
"_cli.run([], 'linux')"
)
inherited = {**os.environ, "PATH": "/usr/bin:/bin", "YIELD_PYTHON": str(python)}
result = subprocess.run(
[str(python), "-c", script],
cwd=Path(__file__).parent,
env=inherited,
text=True,
capture_output=True,
check=False,
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("venv-tool-ready", result.stdout)
if __name__ == "__main__":
unittest.main()