|
16 | 16 | from __future__ import annotations |
17 | 17 |
|
18 | 18 | import subprocess |
| 19 | +import sys |
19 | 20 |
|
20 | 21 | import pytest |
21 | 22 |
|
@@ -86,26 +87,39 @@ def fake_run(*args, **_kwargs): |
86 | 87 | assert source == "python3 in PATH" |
87 | 88 |
|
88 | 89 |
|
89 | | -# TODO(you): implement the remaining two branches of the fallback chain. |
90 | | -# |
91 | | -# These are the cases where the test *design* matters most — you have to |
92 | | -# neutralize the branches above the one under test. Both start from an empty |
93 | | -# cwd so no real .python-version interferes: |
94 | | -# |
95 | | -# monkeypatch.chdir(tmp_path) # escape any real .python-version |
96 | | -# |
97 | | -# 1) test_detects_from_path_probe: |
98 | | -# - Patch detection.subprocess.run to return a CompletedProcess with |
99 | | -# returncode=0 and stdout="Python 3.10.9\n". |
100 | | -# - Assert (version, source) == ("3.10", "python3 in PATH"). |
101 | | -# |
102 | | -# 2) test_falls_back_to_runtime_when_no_python3: |
103 | | -# - Make the PATH probe fail: patch detection.subprocess.run to raise |
104 | | -# FileNotFoundError (python3 absent). Decide what the function should |
105 | | -# return — it falls back to the server's own interpreter. Assert the |
106 | | -# source is "server runtime" and the version matches |
107 | | -# f"{sys.version_info.major}.{sys.version_info.minor}". |
108 | | -# |
109 | | -# Why this is the meaningful part: detection is order-dependent, so a test that |
110 | | -# forgets to chdir() or forgets to stub subprocess will pass on your machine |
111 | | -# and fail in CI (or vice-versa). The isolation is the assertion. |
| 90 | +def test_detects_from_path_probe(tmp_path, monkeypatch) -> None: |
| 91 | + """Branch 2: no .python-version file, so the python3 PATH probe wins. |
| 92 | +
|
| 93 | + chdir to an empty tmp dir to neutralize branch 1 (any real |
| 94 | + .python-version on the host), then stub the probe deterministically. |
| 95 | + """ |
| 96 | + monkeypatch.chdir(tmp_path) |
| 97 | + |
| 98 | + def fake_run(*args, **_kwargs): |
| 99 | + return subprocess.CompletedProcess(args, 0, stdout="Python 3.10.9\n", stderr="") |
| 100 | + |
| 101 | + monkeypatch.setattr(detection.subprocess, "run", fake_run) |
| 102 | + |
| 103 | + version, source = detect_python_version() |
| 104 | + |
| 105 | + assert version == "3.10" |
| 106 | + assert source == "python3 in PATH" |
| 107 | + |
| 108 | + |
| 109 | +def test_falls_back_to_runtime_when_no_python3(tmp_path, monkeypatch) -> None: |
| 110 | + """Branch 3: no file and no python3 on PATH -> server's own interpreter. |
| 111 | +
|
| 112 | + Neutralize branch 1 (empty cwd) and force branch 2 to fail by making the |
| 113 | + probe raise FileNotFoundError, exactly as a missing python3 would. |
| 114 | + """ |
| 115 | + monkeypatch.chdir(tmp_path) |
| 116 | + |
| 117 | + def boom(*args, **_kwargs): |
| 118 | + raise FileNotFoundError("python3 not found") |
| 119 | + |
| 120 | + monkeypatch.setattr(detection.subprocess, "run", boom) |
| 121 | + |
| 122 | + version, source = detect_python_version() |
| 123 | + |
| 124 | + assert source == "server runtime" |
| 125 | + assert version == f"{sys.version_info.major}.{sys.version_info.minor}" |
0 commit comments