/
/
/
1"""Tests for the CI test-scope selector (scripts/ci_test_scope.py)."""
2
3from __future__ import annotations
4
5from pathlib import Path
6
7import pytest
8
9from scripts.ci_test_scope import cov_source, decide, provider_name
10
11
12@pytest.fixture(name="repo")
13def repo_fixture(tmp_path: Path) -> Path:
14 """Build a fake repo with two provider test folders (spotify, audible)."""
15 for name in ("spotify", "audible"):
16 (tmp_path / "tests" / "providers" / name).mkdir(parents=True)
17 (tmp_path / "tests" / "providers" / name / "test_init.py").touch()
18 return tmp_path
19
20
21def test_provider_name() -> None:
22 """provider_name maps source and test dirs, and ignores shared paths."""
23 assert provider_name("music_assistant/providers/spotify/provider.py") == "spotify"
24 assert provider_name("tests/providers/spotify/test_init.py") == "spotify"
25 assert provider_name("music_assistant/helpers/util.py") is None
26 assert provider_name("tests/providers/__init__.py") is None
27
28
29def test_cov_source() -> None:
30 """cov_source maps a provider test dir to its coverage package."""
31 assert cov_source("tests/providers/plex") == "music_assistant.providers.plex"
32
33
34def test_single_provider(repo: Path) -> None:
35 """A change to one provider runs only its test dir."""
36 assert decide(["music_assistant/providers/spotify/provider.py"], repo) == (
37 "partial",
38 ["tests/providers/spotify"],
39 )
40
41
42def test_multiple_providers_sorted(repo: Path) -> None:
43 """Multiple changed providers are returned sorted by name."""
44 mode, paths = decide(
45 ["music_assistant/providers/spotify/provider.py", "tests/providers/audible/test_init.py"],
46 repo,
47 )
48 assert mode == "partial"
49 assert paths == ["tests/providers/audible", "tests/providers/spotify"]
50
51
52@pytest.mark.parametrize(
53 "path",
54 [
55 "music_assistant/helpers/util.py",
56 "music_assistant/controllers/streams/controller.py",
57 "tests/core/test_genres.py",
58 "tests/providers/__init__.py",
59 "music_assistant/translations/en.json",
60 "pyproject.toml",
61 ".github/workflows/test.yml",
62 "scripts/ci_test_scope.py",
63 ],
64)
65def test_shared_changes_force_full(repo: Path, path: str) -> None:
66 """Shared code, deps, translations and CI changes run the full suite."""
67 assert decide([path], repo) == ("full", [])
68
69
70def test_provider_without_tests_forces_full(repo: Path) -> None:
71 """A changed provider that has no tests falls back to the full suite."""
72 assert decide(["music_assistant/providers/ghost/provider.py"], repo) == ("full", [])
73
74
75def test_docs_only_skips(repo: Path) -> None:
76 """A PR touching only docs / unrelated workflows runs nothing."""
77 assert decide(["README.md", ".github/workflows/release.yml"], repo) == ("skip", [])
78
79
80def test_no_changes_skips(repo: Path) -> None:
81 """An empty change set runs nothing."""
82 assert decide([], repo) == ("skip", [])
83