iteration1
This commit is contained in:
@@ -229,6 +229,51 @@ class CliLazyImportTests(unittest.TestCase):
|
||||
result["modules"],
|
||||
)
|
||||
|
||||
def test_edit_command_avoids_database_bootstrap(self):
|
||||
result = self.run_python(
|
||||
textwrap.dedent(
|
||||
f"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from click.testing import CliRunner
|
||||
|
||||
sys.path.insert(0, {str(SRC_ROOT)!r})
|
||||
|
||||
import ffx.cli
|
||||
import ffx.ffx_app
|
||||
import ffx.logging_utils
|
||||
|
||||
ffx.ffx_app.FfxApp.run = lambda self: None
|
||||
ffx.logging_utils.configure_ffx_logger = lambda *args, **kwargs: None
|
||||
|
||||
runner = CliRunner()
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
sample_path = os.path.join(tmpdir, "sample.mkv")
|
||||
with open(sample_path, "w", encoding="utf-8"):
|
||||
pass
|
||||
|
||||
invoke_result = runner.invoke(
|
||||
ffx.cli.ffx,
|
||||
["--dry-run", "edit", sample_path],
|
||||
)
|
||||
|
||||
print(json.dumps({{
|
||||
"exit_code": invoke_result.exit_code,
|
||||
"output": invoke_result.output,
|
||||
"modules": {{
|
||||
module_name: module_name in sys.modules
|
||||
for module_name in {HEAVY_MODULES!r}
|
||||
}},
|
||||
}}))
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(0, result["exit_code"], result["output"])
|
||||
self.assertFalse(result["modules"]["ffx.database"], result["modules"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -107,6 +107,22 @@ class FilePropertiesProbeTests(unittest.TestCase):
|
||||
+ ["/tmp/example_s01e01.mkv"]
|
||||
)
|
||||
|
||||
def test_use_pattern_false_skips_pattern_controller_construction(self):
|
||||
file_properties_module = self.import_module()
|
||||
|
||||
with patch.object(
|
||||
file_properties_module,
|
||||
"PatternController",
|
||||
side_effect=AssertionError("PatternController should not be created"),
|
||||
):
|
||||
file_properties = file_properties_module.FileProperties(
|
||||
self.make_context(),
|
||||
"/tmp/example_s01e01.mkv",
|
||||
)
|
||||
|
||||
self.assertEqual(-1, file_properties.getShowId())
|
||||
self.assertIsNone(file_properties.getPattern())
|
||||
|
||||
def test_cropdetect_uses_configured_window_and_caches_results(self):
|
||||
file_properties_module = self.import_module()
|
||||
file_properties_module.FileProperties._clear_cropdetect_cache()
|
||||
|
||||
@@ -212,6 +212,53 @@ class MediaDescriptorChangeSetTests(unittest.TestCase):
|
||||
self.assertIn("BPS=", metadata_tokens)
|
||||
self.assertIn("KEEP_ME=keep-me", metadata_tokens)
|
||||
|
||||
def test_cleanup_can_be_disabled_per_context(self):
|
||||
context = {
|
||||
"logger": get_ffx_logger(),
|
||||
"config": StaticConfig(
|
||||
{
|
||||
"metadata": {
|
||||
"remove": ["creation_time"],
|
||||
"streams": {
|
||||
"remove": ["BPS"],
|
||||
},
|
||||
}
|
||||
}
|
||||
),
|
||||
"apply_metadata_cleanup": False,
|
||||
}
|
||||
|
||||
source_track = TrackDescriptor(
|
||||
index=0,
|
||||
source_index=0,
|
||||
sub_index=0,
|
||||
track_type=TrackType.AUDIO,
|
||||
tags={"BPS": "keep-me"},
|
||||
)
|
||||
target_track = TrackDescriptor(
|
||||
index=0,
|
||||
source_index=0,
|
||||
sub_index=0,
|
||||
track_type=TrackType.AUDIO,
|
||||
tags={"BPS": "keep-me"},
|
||||
)
|
||||
|
||||
change_set = MediaDescriptorChangeSet(
|
||||
context,
|
||||
MediaDescriptor(
|
||||
tags={"creation_time": "keep-me"},
|
||||
track_descriptors=[target_track],
|
||||
),
|
||||
MediaDescriptor(
|
||||
tags={"creation_time": "keep-me"},
|
||||
track_descriptors=[source_track],
|
||||
),
|
||||
)
|
||||
|
||||
metadata_tokens = change_set.generateMetadataTokens()
|
||||
self.assertNotIn("creation_time=", metadata_tokens)
|
||||
self.assertNotIn("BPS=", metadata_tokens)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
144
tests/unit/test_metadata_editor.py
Normal file
144
tests/unit/test_metadata_editor.py
Normal file
@@ -0,0 +1,144 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
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.logging_utils import get_ffx_logger # noqa: E402
|
||||
from ffx.media_descriptor import MediaDescriptor # noqa: E402
|
||||
from ffx.metadata_editor import ( # noqa: E402
|
||||
apply_metadata_edits,
|
||||
build_metadata_edit_context,
|
||||
create_temporary_output_path,
|
||||
)
|
||||
from ffx.track_codec import TrackCodec # noqa: E402
|
||||
from ffx.track_descriptor import TrackDescriptor # noqa: E402
|
||||
from ffx.track_type import TrackType # noqa: E402
|
||||
from ffx.video_encoder import VideoEncoder # noqa: E402
|
||||
|
||||
|
||||
class StaticConfig:
|
||||
def getData(self):
|
||||
return {}
|
||||
|
||||
|
||||
def make_context(*, dry_run: bool = False) -> dict:
|
||||
return {
|
||||
"logger": get_ffx_logger(),
|
||||
"config": StaticConfig(),
|
||||
"dry_run": dry_run,
|
||||
"apply_metadata_cleanup": True,
|
||||
}
|
||||
|
||||
|
||||
def make_descriptor() -> MediaDescriptor:
|
||||
return MediaDescriptor(
|
||||
track_descriptors=[
|
||||
TrackDescriptor(
|
||||
index=0,
|
||||
source_index=0,
|
||||
sub_index=0,
|
||||
track_type=TrackType.VIDEO,
|
||||
codec_name=TrackCodec.H264,
|
||||
tags={"title": "Main"},
|
||||
)
|
||||
],
|
||||
tags={"TITLE": "Demo"},
|
||||
)
|
||||
|
||||
|
||||
class MetadataEditorTests(unittest.TestCase):
|
||||
def test_build_metadata_edit_context_forces_copy_without_signature(self):
|
||||
context = build_metadata_edit_context(make_context())
|
||||
|
||||
self.assertEqual(VideoEncoder.COPY, context["video_encoder"])
|
||||
self.assertFalse(context["perform_cut"])
|
||||
self.assertTrue(context["no_signature"])
|
||||
self.assertEqual({}, context["encoding_metadata_tags"])
|
||||
|
||||
def test_create_temporary_output_path_uses_same_directory_and_extension(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
source_path = os.path.join(tmpdir, "episode.mkv")
|
||||
temporary_path = create_temporary_output_path(source_path)
|
||||
|
||||
self.assertEqual(".mkv", Path(temporary_path).suffix)
|
||||
self.assertEqual(Path(source_path).parent, Path(temporary_path).parent)
|
||||
|
||||
def test_apply_metadata_edits_rewrites_via_temporary_file_then_replaces_source(self):
|
||||
context = make_context()
|
||||
baseline_descriptor = make_descriptor()
|
||||
draft_descriptor = baseline_descriptor.clone(context=context)
|
||||
source_path = "/tmp/example.mkv"
|
||||
|
||||
with (
|
||||
patch("ffx.metadata_editor.create_temporary_output_path", return_value="/tmp/.edit.mkv"),
|
||||
patch("ffx.metadata_editor.FfxController.runJob") as mocked_run_job,
|
||||
patch("ffx.metadata_editor.os.replace") as mocked_replace,
|
||||
):
|
||||
result = apply_metadata_edits(
|
||||
context,
|
||||
source_path,
|
||||
baseline_descriptor,
|
||||
draft_descriptor,
|
||||
)
|
||||
|
||||
mocked_run_job.assert_called_once_with(
|
||||
source_path,
|
||||
"/tmp/.edit.mkv",
|
||||
targetFormat="",
|
||||
chainIteration=[],
|
||||
)
|
||||
mocked_replace.assert_called_once_with("/tmp/.edit.mkv", source_path)
|
||||
self.assertEqual(
|
||||
{
|
||||
"applied": True,
|
||||
"dry_run": False,
|
||||
"target_path": source_path,
|
||||
},
|
||||
result,
|
||||
)
|
||||
|
||||
def test_apply_metadata_edits_dry_run_skips_replace_and_cleans_temp_path(self):
|
||||
context = make_context(dry_run=True)
|
||||
baseline_descriptor = make_descriptor()
|
||||
draft_descriptor = baseline_descriptor.clone(context=context)
|
||||
|
||||
with (
|
||||
patch("ffx.metadata_editor.create_temporary_output_path", return_value="/tmp/.edit.mkv"),
|
||||
patch("ffx.metadata_editor.FfxController.runJob") as mocked_run_job,
|
||||
patch("ffx.metadata_editor.os.path.exists", return_value=True),
|
||||
patch("ffx.metadata_editor.os.remove") as mocked_remove,
|
||||
patch("ffx.metadata_editor.os.replace") as mocked_replace,
|
||||
):
|
||||
result = apply_metadata_edits(
|
||||
context,
|
||||
"/tmp/example.mkv",
|
||||
baseline_descriptor,
|
||||
draft_descriptor,
|
||||
)
|
||||
|
||||
mocked_run_job.assert_called_once()
|
||||
mocked_replace.assert_not_called()
|
||||
mocked_remove.assert_called_once_with("/tmp/.edit.mkv")
|
||||
self.assertEqual(
|
||||
{
|
||||
"applied": False,
|
||||
"dry_run": True,
|
||||
"target_path": "/tmp/.edit.mkv",
|
||||
},
|
||||
result,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user