|
6 | 6 | from pathlib import Path |
7 | 7 | from unittest.mock import patch |
8 | 8 |
|
9 | | -from cocoindex_code.config import Config, _detect_device |
| 9 | +import pytest |
10 | 10 |
|
| 11 | +from cocoindex_code.config import Config |
11 | 12 |
|
12 | | -class TestDetectDevice: |
13 | | - """Tests for device auto-detection.""" |
14 | 13 |
|
15 | | - def test_returns_cuda_when_available(self) -> None: |
16 | | - with patch.dict(os.environ, {}, clear=False): |
17 | | - # Ensure env var is unset |
18 | | - os.environ.pop("COCOINDEX_CODE_DEVICE", None) |
19 | | - with patch("torch.cuda.is_available", return_value=True): |
20 | | - assert _detect_device() == "cuda" |
| 14 | +class TestConfigDevice: |
| 15 | + """Tests for COCOINDEX_CODE_DEVICE env var handling.""" |
21 | 16 |
|
22 | | - def test_returns_cpu_when_cuda_unavailable(self) -> None: |
23 | | - with patch.dict(os.environ, {}, clear=False): |
| 17 | + def test_none_by_default(self, tmp_path: Path) -> None: |
| 18 | + with patch.dict( |
| 19 | + os.environ, |
| 20 | + {"COCOINDEX_CODE_ROOT_PATH": str(tmp_path)}, |
| 21 | + ): |
24 | 22 | os.environ.pop("COCOINDEX_CODE_DEVICE", None) |
25 | | - with patch("torch.cuda.is_available", return_value=False): |
26 | | - assert _detect_device() == "cpu" |
27 | | - |
28 | | - def test_env_var_overrides_auto_detection(self) -> None: |
29 | | - with patch.dict(os.environ, {"COCOINDEX_CODE_DEVICE": "cpu"}): |
30 | | - with patch("torch.cuda.is_available", return_value=True): |
31 | | - assert _detect_device() == "cpu" |
| 23 | + config = Config.from_env() |
| 24 | + assert config.device is None |
32 | 25 |
|
33 | | - def test_returns_cpu_when_torch_missing(self) -> None: |
34 | | - with patch.dict(os.environ, {}, clear=False): |
35 | | - os.environ.pop("COCOINDEX_CODE_DEVICE", None) |
36 | | - with patch.dict("sys.modules", {"torch": None}): |
37 | | - assert _detect_device() == "cpu" |
| 26 | + def test_env_var_overrides_device(self, tmp_path: Path) -> None: |
| 27 | + with patch.dict( |
| 28 | + os.environ, |
| 29 | + { |
| 30 | + "COCOINDEX_CODE_ROOT_PATH": str(tmp_path), |
| 31 | + "COCOINDEX_CODE_DEVICE": "cpu", |
| 32 | + }, |
| 33 | + ): |
| 34 | + config = Config.from_env() |
| 35 | + assert config.device == "cpu" |
38 | 36 |
|
39 | 37 |
|
40 | 38 | class TestConfigTrustRemoteCode: |
@@ -158,3 +156,105 @@ def test_mixed_with_and_without_lang(self, tmp_path: Path) -> None: |
158 | 156 | ): |
159 | 157 | config = Config.from_env() |
160 | 158 | assert config.extra_extensions == {".inc": "php", ".yaml": None, ".tpl": "html"} |
| 159 | + |
| 160 | + |
| 161 | +class TestExcludedPatterns: |
| 162 | + """Tests for COCOINDEX_CODE_EXCLUDED_PATTERNS env var.""" |
| 163 | + |
| 164 | + def test_empty_by_default(self, tmp_path: Path) -> None: |
| 165 | + with patch.dict( |
| 166 | + os.environ, |
| 167 | + {"COCOINDEX_CODE_ROOT_PATH": str(tmp_path)}, |
| 168 | + ): |
| 169 | + os.environ.pop("COCOINDEX_CODE_EXCLUDED_PATTERNS", None) |
| 170 | + config = Config.from_env() |
| 171 | + assert config.excluded_patterns == [] |
| 172 | + |
| 173 | + def test_parses_json_array(self, tmp_path: Path) -> None: |
| 174 | + with patch.dict( |
| 175 | + os.environ, |
| 176 | + { |
| 177 | + "COCOINDEX_CODE_ROOT_PATH": str(tmp_path), |
| 178 | + "COCOINDEX_CODE_EXCLUDED_PATTERNS": '["**/migration.sql", "**/*.d.ts"]', |
| 179 | + }, |
| 180 | + ): |
| 181 | + config = Config.from_env() |
| 182 | + assert config.excluded_patterns == ["**/migration.sql", "**/*.d.ts"] |
| 183 | + |
| 184 | + def test_preserves_commas_inside_globs(self, tmp_path: Path) -> None: |
| 185 | + with patch.dict( |
| 186 | + os.environ, |
| 187 | + { |
| 188 | + "COCOINDEX_CODE_ROOT_PATH": str(tmp_path), |
| 189 | + "COCOINDEX_CODE_EXCLUDED_PATTERNS": '["{**/*.md,**/*.txt}"]', |
| 190 | + }, |
| 191 | + ): |
| 192 | + config = Config.from_env() |
| 193 | + assert config.excluded_patterns == ["{**/*.md,**/*.txt}"] |
| 194 | + |
| 195 | + def test_trims_whitespace_and_ignores_empty_entries(self, tmp_path: Path) -> None: |
| 196 | + with patch.dict( |
| 197 | + os.environ, |
| 198 | + { |
| 199 | + "COCOINDEX_CODE_ROOT_PATH": str(tmp_path), |
| 200 | + "COCOINDEX_CODE_EXCLUDED_PATTERNS": '[" **/migration.sql ", " ", "**/*.d.ts"]', |
| 201 | + }, |
| 202 | + ): |
| 203 | + config = Config.from_env() |
| 204 | + assert config.excluded_patterns == ["**/migration.sql", "**/*.d.ts"] |
| 205 | + |
| 206 | + def test_empty_string_gives_empty_list(self, tmp_path: Path) -> None: |
| 207 | + with patch.dict( |
| 208 | + os.environ, |
| 209 | + { |
| 210 | + "COCOINDEX_CODE_ROOT_PATH": str(tmp_path), |
| 211 | + "COCOINDEX_CODE_EXCLUDED_PATTERNS": "", |
| 212 | + }, |
| 213 | + ): |
| 214 | + config = Config.from_env() |
| 215 | + assert config.excluded_patterns == [] |
| 216 | + |
| 217 | + def test_rejects_invalid_json(self, tmp_path: Path) -> None: |
| 218 | + with patch.dict( |
| 219 | + os.environ, |
| 220 | + { |
| 221 | + "COCOINDEX_CODE_ROOT_PATH": str(tmp_path), |
| 222 | + "COCOINDEX_CODE_EXCLUDED_PATTERNS": "**/migration.sql,**/*.d.ts", |
| 223 | + }, |
| 224 | + ): |
| 225 | + with pytest.raises( |
| 226 | + ValueError, |
| 227 | + match=( |
| 228 | + "COCOINDEX_CODE_EXCLUDED_PATTERNS must be a JSON array of strings, " |
| 229 | + "got invalid JSON" |
| 230 | + ), |
| 231 | + ): |
| 232 | + Config.from_env() |
| 233 | + |
| 234 | + def test_rejects_valid_json_non_list(self, tmp_path: Path) -> None: |
| 235 | + with patch.dict( |
| 236 | + os.environ, |
| 237 | + { |
| 238 | + "COCOINDEX_CODE_ROOT_PATH": str(tmp_path), |
| 239 | + "COCOINDEX_CODE_EXCLUDED_PATTERNS": "{}", |
| 240 | + }, |
| 241 | + ): |
| 242 | + with pytest.raises( |
| 243 | + ValueError, |
| 244 | + match="COCOINDEX_CODE_EXCLUDED_PATTERNS must be a JSON array of strings", |
| 245 | + ): |
| 246 | + Config.from_env() |
| 247 | + |
| 248 | + def test_rejects_non_string_entries(self, tmp_path: Path) -> None: |
| 249 | + with patch.dict( |
| 250 | + os.environ, |
| 251 | + { |
| 252 | + "COCOINDEX_CODE_ROOT_PATH": str(tmp_path), |
| 253 | + "COCOINDEX_CODE_EXCLUDED_PATTERNS": '["**/*.py", 1]', |
| 254 | + }, |
| 255 | + ): |
| 256 | + with pytest.raises( |
| 257 | + ValueError, |
| 258 | + match="COCOINDEX_CODE_EXCLUDED_PATTERNS must be a JSON array of strings", |
| 259 | + ): |
| 260 | + Config.from_env() |
0 commit comments