CLI implementation
This commit is contained in:
187
tests/unit/test_cli.py
Normal file
187
tests/unit/test_cli.py
Normal file
@@ -0,0 +1,187 @@
|
||||
"""
|
||||
Tests for CLI module.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, MagicMock
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from src.cli.main import app
|
||||
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
|
||||
# Valid storyboard JSON template
|
||||
VALID_STORYBOARD = """
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"project": {
|
||||
"title": "Test Storyboard",
|
||||
"fps": 24,
|
||||
"target_duration_s": 20,
|
||||
"resolution": {"width": 1280, "height": 720},
|
||||
"aspect_ratio": "16:9"
|
||||
},
|
||||
"shots": [
|
||||
{
|
||||
"id": "shot_001",
|
||||
"duration_s": 4,
|
||||
"prompt": "A test shot description",
|
||||
"camera": {"framing": "wide", "movement": "static"},
|
||||
"generation": {"seed": 42, "steps": 30, "cfg_scale": 6.0}
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"container": "mp4",
|
||||
"codec": "h264",
|
||||
"crf": 18,
|
||||
"preset": "medium"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class TestValidateCommand:
|
||||
"""Test the validate command."""
|
||||
|
||||
def test_validate_nonexistent_file(self):
|
||||
"""Test validation with non-existent file."""
|
||||
result = runner.invoke(app, ["validate", "nonexistent.json"])
|
||||
assert result.exit_code == 1
|
||||
assert "not found" in result.output
|
||||
|
||||
def test_validate_valid_storyboard(self):
|
||||
"""Test validation with valid storyboard."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
storyboard_file = Path(tmpdir) / "test.json"
|
||||
storyboard_file.write_text(VALID_STORYBOARD)
|
||||
|
||||
result = runner.invoke(app, ["validate", str(storyboard_file)])
|
||||
assert result.exit_code == 0
|
||||
assert "valid" in result.output
|
||||
assert "Test Storyboard" in result.output
|
||||
|
||||
def test_validate_verbose(self):
|
||||
"""Test validation with verbose flag."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
storyboard_file = Path(tmpdir) / "test.json"
|
||||
storyboard_file.write_text(VALID_STORYBOARD)
|
||||
|
||||
result = runner.invoke(app, ["validate", str(storyboard_file), "--verbose"])
|
||||
assert result.exit_code == 0
|
||||
assert "Shots" in result.output
|
||||
|
||||
|
||||
class TestListBackendsCommand:
|
||||
"""Test the list-backends command."""
|
||||
|
||||
def test_list_backends(self):
|
||||
"""Test listing available backends."""
|
||||
result = runner.invoke(app, ["list-backends"])
|
||||
assert result.exit_code == 0
|
||||
assert "wan" in result.output
|
||||
assert "Available Backends" in result.output
|
||||
|
||||
|
||||
class TestGenerateCommand:
|
||||
"""Test the generate command."""
|
||||
|
||||
@pytest.fixture
|
||||
def mock_storyboard(self):
|
||||
"""Create a mock storyboard file."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
storyboard_file = Path(tmpdir) / "test.json"
|
||||
storyboard_file.write_text(VALID_STORYBOARD)
|
||||
yield storyboard_file
|
||||
|
||||
def test_generate_dry_run(self, mock_storyboard):
|
||||
"""Test generate command with dry-run flag."""
|
||||
result = runner.invoke(app, [
|
||||
"generate",
|
||||
str(mock_storyboard),
|
||||
"--dry-run"
|
||||
])
|
||||
assert result.exit_code == 0
|
||||
assert "Dry run complete" in result.output
|
||||
|
||||
def test_generate_nonexistent_storyboard(self):
|
||||
"""Test generate with non-existent storyboard."""
|
||||
result = runner.invoke(app, ["generate", "nonexistent.json"])
|
||||
assert result.exit_code == 1
|
||||
assert "not found" in result.output
|
||||
|
||||
|
||||
class TestResumeCommand:
|
||||
"""Test the resume command."""
|
||||
|
||||
def test_resume_nonexistent_project(self):
|
||||
"""Test resume with non-existent project."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
result = runner.invoke(app, [
|
||||
"resume",
|
||||
"nonexistent_project",
|
||||
"--output", tmpdir
|
||||
])
|
||||
assert result.exit_code == 1
|
||||
assert "No checkpoint found" in result.output
|
||||
|
||||
def test_resume_existing_project(self):
|
||||
"""Test resume with existing project checkpoint."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
project_dir = Path(tmpdir) / "test_project"
|
||||
project_dir.mkdir()
|
||||
checkpoint_db = project_dir / "checkpoints.db"
|
||||
checkpoint_db.touch()
|
||||
|
||||
# Create a mock checkpoint
|
||||
with patch('src.cli.main.CheckpointManager') as mock_mgr:
|
||||
mock_checkpoint = MagicMock()
|
||||
mock_checkpoint.storyboard_path = str(Path(tmpdir) / "storyboard.json")
|
||||
mock_mgr.return_value.get_project_checkpoint.return_value = mock_checkpoint
|
||||
|
||||
# Create storyboard file
|
||||
storyboard_file = Path(tmpdir) / "storyboard.json"
|
||||
storyboard_file.write_text(VALID_STORYBOARD)
|
||||
|
||||
result = runner.invoke(app, [
|
||||
"resume",
|
||||
"test_project",
|
||||
"--output", tmpdir
|
||||
])
|
||||
|
||||
# Should attempt to resume (may fail on actual generation)
|
||||
assert "Resuming project" in result.output or result.exit_code != 0
|
||||
|
||||
|
||||
class TestCLIHelp:
|
||||
"""Test CLI help messages."""
|
||||
|
||||
def test_main_help(self):
|
||||
"""Test main help message."""
|
||||
result = runner.invoke(app, ["--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "Storyboard to Video Generation Pipeline" in result.output
|
||||
|
||||
def test_generate_help(self):
|
||||
"""Test generate command help."""
|
||||
result = runner.invoke(app, ["generate", "--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "Generate video from storyboard" in result.output
|
||||
assert "--output" in result.output
|
||||
assert "--backend" in result.output
|
||||
assert "--dry-run" in result.output
|
||||
|
||||
def test_validate_help(self):
|
||||
"""Test validate command help."""
|
||||
result = runner.invoke(app, ["validate", "--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "Validate a storyboard file" in result.output
|
||||
|
||||
def test_resume_help(self):
|
||||
"""Test resume command help."""
|
||||
result = runner.invoke(app, ["resume", "--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "Resume a failed or interrupted project" in result.output
|
||||
Reference in New Issue
Block a user