from __future__ import annotations from pathlib import Path import sys import tempfile import unittest from unittest.mock import patch import click SRC_ROOT = Path(__file__).resolve().parents[2] / "src" if str(SRC_ROOT) not in sys.path: sys.path.insert(0, str(SRC_ROOT)) from ffx import cli # noqa: E402 class StaticConfig: def __init__(self, subtitles_directory: str = ""): self._subtitles_directory = subtitles_directory def getSubtitlesDirectoryPath(self): return self._subtitles_directory class UnmuxOutputDirectoryTests(unittest.TestCase): def test_subtitles_only_with_label_uses_configured_subtitles_base_directory(self): with tempfile.TemporaryDirectory() as tempdir: context = { "config": StaticConfig(str(Path(tempdir) / "subtitles")), } resolved_output_directory, should_create = cli.resolveUnmuxOutputDirectory( context, "", True, "dball", ) self.assertEqual(str(Path(tempdir) / "subtitles" / "dball"), resolved_output_directory) self.assertTrue(should_create) def test_explicit_output_directory_requires_directory(self): with tempfile.TemporaryDirectory() as tempdir: context = { "config": StaticConfig(str(Path(tempdir) / "subtitles")), } explicit_output_directory = str(Path(tempdir) / "manual") resolved_output_directory, should_create = cli.resolveUnmuxOutputDirectory( context, explicit_output_directory, True, "dball", ) self.assertEqual(explicit_output_directory, resolved_output_directory) self.assertTrue(should_create) def test_subtitles_only_without_label_keeps_existing_behavior(self): context = { "config": StaticConfig("/tmp/subtitles"), } resolved_output_directory, should_create = cli.resolveUnmuxOutputDirectory( context, "", True, "", ) self.assertEqual("", resolved_output_directory) self.assertFalse(should_create) def test_subtitles_only_with_label_requires_configured_default_when_output_directory_is_missing(self): context = { "config": StaticConfig(""), } with self.assertRaises(click.ClickException) as caught: cli.resolveUnmuxOutputDirectory( context, "", True, "dball", ) self.assertIn("subtitlesDirectory default", str(caught.exception)) def test_missing_output_directory_can_be_confirmed_and_created_with_parents(self): with tempfile.TemporaryDirectory() as tempdir: output_directory = Path(tempdir) / "missing" / "parents" / "manual" with patch("ffx.cli.click.confirm", return_value=True) as mocked_confirm: created = cli.ensureUnmuxOutputDirectory( {"dry_run": False}, str(output_directory), ) self.assertTrue(created) self.assertTrue(output_directory.is_dir()) mocked_confirm.assert_called_once() def test_tty_carriage_return_accepts_default_directory_creation(self): with tempfile.TemporaryDirectory() as tempdir: output_directory = Path(tempdir) / "missing" / "manual" with patch("ffx.cli.sys.stdin.isatty", return_value=True), patch( "ffx.cli.click.getchar", return_value="\r", ) as mocked_getchar, patch("ffx.cli.click.confirm") as mocked_confirm: created = cli.ensureUnmuxOutputDirectory( {"dry_run": False}, str(output_directory), ) self.assertTrue(created) self.assertTrue(output_directory.is_dir()) mocked_getchar.assert_called_once() mocked_confirm.assert_not_called() def test_missing_output_directory_can_be_rejected(self): with tempfile.TemporaryDirectory() as tempdir: output_directory = Path(tempdir) / "missing" / "manual" with patch("ffx.cli.click.confirm", return_value=False) as mocked_confirm: with self.assertRaises(click.ClickException) as caught: cli.ensureUnmuxOutputDirectory( {"dry_run": False}, str(output_directory), ) self.assertFalse(output_directory.exists()) self.assertIn("aborted by user", str(caught.exception)) mocked_confirm.assert_called_once() def test_existing_output_directory_does_not_prompt(self): with tempfile.TemporaryDirectory() as tempdir: output_directory = Path(tempdir) / "manual" output_directory.mkdir() with patch("ffx.cli.click.confirm") as mocked_confirm: created = cli.ensureUnmuxOutputDirectory( {"dry_run": False}, str(output_directory), ) self.assertFalse(created) mocked_confirm.assert_not_called() def test_existing_non_directory_output_path_fails_without_prompt(self): with tempfile.TemporaryDirectory() as tempdir: output_path = Path(tempdir) / "manual" output_path.write_text("not a directory", encoding="utf-8") with patch("ffx.cli.click.confirm") as mocked_confirm: with self.assertRaises(click.ClickException) as caught: cli.ensureUnmuxOutputDirectory( {"dry_run": False}, str(output_path), ) self.assertIn("not a directory", str(caught.exception)) mocked_confirm.assert_not_called() def test_dry_run_does_not_prompt_or_create_missing_output_directory(self): with tempfile.TemporaryDirectory() as tempdir: output_directory = Path(tempdir) / "missing" / "manual" with patch("ffx.cli.click.confirm") as mocked_confirm: created = cli.ensureUnmuxOutputDirectory( {"dry_run": True}, str(output_directory), ) self.assertFalse(created) self.assertFalse(output_directory.exists()) mocked_confirm.assert_not_called() if __name__ == "__main__": unittest.main()