Coverage for tests / unit / tools / core / test_install_context.py: 100%
61 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Tests for lintro.tools.core.install_context module.
3Hint generation tests have moved to test_install_strategies.py.
4This file covers RuntimeContext construction, install context detection,
5and CI detection.
6"""
8from __future__ import annotations
10from unittest.mock import patch
12import pytest
13from assertpy import assert_that
15from lintro.enums.install_context import CISystem, InstallContext, PackageManager
16from lintro.tools.core.install_context import (
17 RuntimeContext,
18 _detect_install_context,
19 _is_ci,
20)
21from lintro.tools.core.install_strategies.environment import InstallEnvironment
23# ---------------------------------------------------------------------------
24# Helpers
25# ---------------------------------------------------------------------------
28def _make_ctx(
29 *,
30 install_context: InstallContext = InstallContext.PIP,
31 platform_label: str = "macOS arm64",
32 managers: frozenset[PackageManager] = frozenset(PackageManager),
33 is_ci: bool = False,
34 ci_name: CISystem | None = None,
35) -> RuntimeContext:
36 """Build a RuntimeContext with sensible defaults for testing.
38 Args:
39 install_context: How lintro was installed.
40 platform_label: Platform description.
41 managers: Available package manager names.
42 is_ci: Running in CI.
43 ci_name: CI system name.
45 Returns:
46 A RuntimeContext instance.
47 """
48 return RuntimeContext(
49 install_context=install_context,
50 platform_label=platform_label,
51 environment=InstallEnvironment(
52 install_context=install_context,
53 available_managers=managers,
54 ),
55 is_ci=is_ci,
56 ci_name=ci_name,
57 )
60# ---------------------------------------------------------------------------
61# RuntimeContext construction
62# ---------------------------------------------------------------------------
65def test_runtime_context_has_environment() -> None:
66 """RuntimeContext carries an InstallEnvironment."""
67 ctx = _make_ctx()
68 assert_that(ctx.environment).is_instance_of(InstallEnvironment)
69 assert_that(ctx.environment.has(PackageManager.UV)).is_true()
72def test_runtime_context_environment_reflects_managers() -> None:
73 """InstallEnvironment correctly reports available managers."""
74 ctx = _make_ctx(managers=frozenset({PackageManager.CARGO}))
75 assert_that(ctx.environment.has(PackageManager.CARGO)).is_true()
76 assert_that(ctx.environment.has(PackageManager.UV)).is_false()
79# ---------------------------------------------------------------------------
80# _detect_install_context
81# ---------------------------------------------------------------------------
84def test_detect_docker_via_dockerenv() -> None:
85 """Detect Docker context when /.dockerenv file exists."""
86 with patch(
87 "lintro.tools.core.install_context.os.path.exists",
88 return_value=True,
89 ):
90 result = _detect_install_context()
92 assert_that(result).is_equal_to(InstallContext.DOCKER)
95def test_detect_docker_via_env_var(
96 monkeypatch: pytest.MonkeyPatch,
97) -> None:
98 """Detect Docker context via LINTRO_DOCKER=1 env var."""
99 monkeypatch.setenv("LINTRO_DOCKER", "1")
100 with patch(
101 "lintro.tools.core.install_context.os.path.exists",
102 return_value=False,
103 ):
104 result = _detect_install_context()
106 assert_that(result).is_equal_to(InstallContext.DOCKER)
109def test_detect_docker_via_container_env_var(
110 monkeypatch: pytest.MonkeyPatch,
111) -> None:
112 """Detect Docker context via CONTAINER=docker env var.
114 Args:
115 monkeypatch: Pytest monkeypatch fixture.
116 """
117 monkeypatch.delenv("LINTRO_DOCKER", raising=False)
118 monkeypatch.setenv("CONTAINER", "docker")
119 with patch(
120 "lintro.tools.core.install_context.os.path.exists",
121 return_value=False,
122 ):
123 result = _detect_install_context()
125 assert_that(result).is_equal_to(InstallContext.DOCKER)
128def test_detect_pip_default(
129 monkeypatch: pytest.MonkeyPatch,
130) -> None:
131 """Default to PIP context when no special indicators are present."""
132 monkeypatch.delenv("LINTRO_DOCKER", raising=False)
133 monkeypatch.delenv("CONTAINER", raising=False)
135 with (
136 patch(
137 "lintro.tools.core.install_context.os.path.exists",
138 return_value=False,
139 ),
140 patch(
141 "lintro.tools.core.install_context.__file__",
142 "/usr/lib/python3.11/site-packages/lintro/tools/core/install_context.py",
143 create=True,
144 ),
145 patch(
146 "lintro.tools.core.install_context.sys.executable",
147 "/usr/bin/python3",
148 ),
149 ):
150 result = _detect_install_context()
152 assert_that(result).is_equal_to(InstallContext.PIP)
155# ---------------------------------------------------------------------------
156# CI detection
157# ---------------------------------------------------------------------------
160def test_is_ci_with_ci_env_var(
161 monkeypatch: pytest.MonkeyPatch,
162) -> None:
163 """Return True when generic CI env var is set."""
164 monkeypatch.setenv("CI", "true")
165 for var in (
166 "GITHUB_ACTIONS",
167 "GITLAB_CI",
168 "CIRCLECI",
169 "JENKINS_URL",
170 "BUILDKITE",
171 "TF_BUILD",
172 ):
173 monkeypatch.delenv(var, raising=False)
175 assert_that(_is_ci()).is_true()
178def test_is_ci_false(
179 monkeypatch: pytest.MonkeyPatch,
180) -> None:
181 """Return False when no CI env vars are set."""
182 monkeypatch.delenv("CI", raising=False)
183 for var in (
184 "GITHUB_ACTIONS",
185 "GITLAB_CI",
186 "CIRCLECI",
187 "JENKINS_URL",
188 "BUILDKITE",
189 "TF_BUILD",
190 ):
191 monkeypatch.delenv(var, raising=False)
193 assert_that(_is_ci()).is_false()
196@pytest.mark.parametrize(
197 ("env_var", "env_value", "expected"),
198 [
199 ("GITHUB_ACTIONS", "1", CISystem.GITHUB_ACTIONS),
200 ("GITLAB_CI", "1", CISystem.GITLAB_CI),
201 ("CIRCLECI", "true", CISystem.CIRCLECI),
202 ("JENKINS_URL", "https://ci.example.com", CISystem.JENKINS),
203 ("BUILDKITE", "true", CISystem.BUILDKITE),
204 ("TF_BUILD", "True", CISystem.AZURE_PIPELINES),
205 ],
206 ids=[
207 "github_actions",
208 "gitlab_ci",
209 "circleci",
210 "jenkins",
211 "buildkite",
212 "azure_pipelines",
213 ],
214)
215def test_detect_ci_system(
216 env_var: str,
217 env_value: str,
218 expected: CISystem,
219 monkeypatch: pytest.MonkeyPatch,
220) -> None:
221 """Detect specific CI system from its environment variable.
223 Args:
224 env_var: The CI-specific env var to set.
225 env_value: The value to set for the env var.
226 expected: Expected CISystem enum member.
227 monkeypatch: Pytest monkeypatch fixture.
228 """
229 for var in (
230 "GITHUB_ACTIONS",
231 "GITLAB_CI",
232 "CIRCLECI",
233 "JENKINS_URL",
234 "BUILDKITE",
235 "TF_BUILD",
236 ):
237 monkeypatch.delenv(var, raising=False)
239 monkeypatch.setenv(env_var, env_value)
241 assert_that(CISystem.detect()).is_equal_to(expected)
244def test_detect_ci_system_none(
245 monkeypatch: pytest.MonkeyPatch,
246) -> None:
247 """Return None when no CI env vars are set."""
248 for var in (
249 "GITHUB_ACTIONS",
250 "GITLAB_CI",
251 "CIRCLECI",
252 "JENKINS_URL",
253 "BUILDKITE",
254 "TF_BUILD",
255 ):
256 monkeypatch.delenv(var, raising=False)
258 assert_that(CISystem.detect()).is_none()
261def test_ci_system_is_str_enum() -> None:
262 """CISystem values are human-readable strings."""
263 assert_that(str(CISystem.GITHUB_ACTIONS)).is_equal_to("GitHub Actions")
264 assert_that(str(CISystem.AZURE_PIPELINES)).is_equal_to("Azure Pipelines")