cgcardona / muse public
test_play.py python
133 lines 4.7 KB
12901c5a Initial extraction from tellurstori/maestro cgcardona <gabriel@tellurstori.com> 4d ago
1 """Tests for ``muse play`` command.
2
3 Tests:
4 - ``test_play_calls_afplay`` — happy path: subprocess.run(['afplay', path]) called.
5 - ``test_play_mid_falls_back_to_open`` — MIDI files fall back to ``open``.
6 - ``test_play_file_not_found_exits_1`` — exit code 1 when file does not exist.
7 - ``test_play_requires_macos`` — exit code 1 on non-macOS platforms.
8 """
9 from __future__ import annotations
10
11 import json
12 import pathlib
13 import uuid
14 from unittest.mock import MagicMock, patch
15
16 import pytest
17 from typer.testing import CliRunner
18
19 from maestro.muse_cli.app import cli
20 from maestro.muse_cli.commands.play import _play_path
21
22 runner = CliRunner()
23
24
25 def _init_muse_repo(root: pathlib.Path, repo_id: str | None = None) -> str:
26 rid = repo_id or str(uuid.uuid4())
27 muse = root / ".muse"
28 (muse / "refs" / "heads").mkdir(parents=True)
29 (muse / "repo.json").write_text(
30 json.dumps({"repo_id": rid, "schema_version": "1"})
31 )
32 (muse / "HEAD").write_text("refs/heads/main")
33 (muse / "refs" / "heads" / "main").write_text("")
34 return rid
35
36
37 def test_play_calls_afplay(tmp_path: pathlib.Path) -> None:
38 """``muse play <mp3>`` calls subprocess.run(['afplay', <path>]) and exits 0."""
39 _init_muse_repo(tmp_path)
40 artifact = tmp_path / "muse-work" / "jazz_4b_run1.mp3"
41 artifact.parent.mkdir(parents=True)
42 artifact.write_bytes(b"MP3DATA")
43
44 with (
45 patch("maestro.muse_cli.commands.play.platform.system", return_value="Darwin"),
46 patch("maestro.muse_cli.commands.play.subprocess.run") as mock_run,
47 patch.dict("os.environ", {"MUSE_REPO_ROOT": str(tmp_path)}),
48 ):
49 mock_run.return_value = MagicMock(returncode=0)
50 result = runner.invoke(cli, ["play", str(artifact)])
51
52 assert result.exit_code == 0, result.output
53 mock_run.assert_called_once()
54 call_args = mock_run.call_args[0][0]
55 assert call_args[0] == "afplay"
56 assert str(artifact.resolve()) in call_args[1]
57
58
59 def test_play_mid_falls_back_to_open(tmp_path: pathlib.Path) -> None:
60 """``muse play <mid>`` falls back to ``open`` and shows a warning."""
61 _init_muse_repo(tmp_path)
62 artifact = tmp_path / "muse-work" / "track.mid"
63 artifact.parent.mkdir(parents=True)
64 artifact.write_bytes(b"MIDI")
65
66 with (
67 patch("maestro.muse_cli.commands.play.platform.system", return_value="Darwin"),
68 patch("maestro.muse_cli.commands.play.subprocess.run") as mock_run,
69 patch.dict("os.environ", {"MUSE_REPO_ROOT": str(tmp_path)}),
70 ):
71 mock_run.return_value = MagicMock(returncode=0)
72 result = runner.invoke(cli, ["play", str(artifact)])
73
74 assert result.exit_code == 0, result.output
75 call_args = mock_run.call_args[0][0]
76 assert call_args[0] == "open"
77 assert "MIDI" in result.output or "afplay" in result.output or "system default" in result.output
78
79
80 def test_play_file_not_found_exits_1(tmp_path: pathlib.Path) -> None:
81 """``muse play <missing>`` exits 1 with a clear error message."""
82 _init_muse_repo(tmp_path)
83
84 with (
85 patch("maestro.muse_cli.commands.play.platform.system", return_value="Darwin"),
86 patch.dict("os.environ", {"MUSE_REPO_ROOT": str(tmp_path)}),
87 ):
88 result = runner.invoke(cli, ["play", "no_such_file.mp3"])
89
90 assert result.exit_code == 1
91
92
93 def test_play_requires_macos(tmp_path: pathlib.Path) -> None:
94 """``muse play`` exits 1 with a clear message on non-macOS platforms."""
95 _init_muse_repo(tmp_path)
96 artifact = tmp_path / "muse-work" / "beat.mp3"
97 artifact.parent.mkdir(parents=True)
98 artifact.write_bytes(b"MP3DATA")
99
100 with (
101 patch("maestro.muse_cli.commands.play.platform.system", return_value="Linux"),
102 patch.dict("os.environ", {"MUSE_REPO_ROOT": str(tmp_path)}),
103 ):
104 result = runner.invoke(cli, ["play", str(artifact)])
105
106 assert result.exit_code == 1
107 assert "macOS" in result.output
108
109
110 def test_play_path_calls_afplay_directly(tmp_path: pathlib.Path) -> None:
111 """``_play_path`` helper calls afplay for mp3 files."""
112 mp3 = tmp_path / "track.mp3"
113 mp3.write_bytes(b"MP3")
114
115 with patch("maestro.muse_cli.commands.play.subprocess.run") as mock_run:
116 mock_run.return_value = MagicMock(returncode=0)
117 _play_path(mp3)
118
119 mock_run.assert_called_once()
120 assert mock_run.call_args[0][0][0] == "afplay"
121
122
123 def test_play_path_midi_falls_back_to_open(tmp_path: pathlib.Path) -> None:
124 """``_play_path`` helper falls back to open for .mid files."""
125 mid = tmp_path / "track.mid"
126 mid.write_bytes(b"MIDI")
127
128 with patch("maestro.muse_cli.commands.play.subprocess.run") as mock_run:
129 mock_run.return_value = MagicMock(returncode=0)
130 _play_path(mid)
131
132 mock_run.assert_called_once()
133 assert mock_run.call_args[0][0][0] == "open"