Files
scaffoldforge/tests/unit/test_cli.py

182 lines
6.1 KiB
Python

"""Unit tests for the CLI module."""
import pytest
from click.testing import CliRunner
from unittest.mock import Mock, patch, MagicMock
from scaffoldforge.cli import cli
from scaffoldforge.cli.commands import parse_github_url
class TestParseGitHubUrl:
"""Tests for GitHub URL parsing."""
def test_parse_valid_url(self):
"""Test parsing a valid GitHub issue URL."""
owner, repo, issue_number = parse_github_url(
"https://github.com/owner/repo/issues/123"
)
assert owner == "owner"
assert repo == "repo"
assert issue_number == 123
def test_parse_url_with_www(self):
"""Test parsing URL with www prefix."""
owner, repo, issue_number = parse_github_url(
"https://www.github.com/owner/repo/issues/456"
)
assert owner == "owner"
assert repo == "repo"
assert issue_number == 456
def test_parse_url_with_trailing_slash(self):
"""Test parsing URL with trailing slash."""
owner, repo, issue_number = parse_github_url(
"https://github.com/owner/repo/issues/789/"
)
assert owner == "owner"
assert repo == "repo"
def test_parse_invalid_url(self):
"""Test parsing invalid URL raises exception."""
from click import ClickException
with pytest.raises(ClickException):
parse_github_url("https://invalid.com/owner/repo/issues/123")
def test_parse_url_without_issue_number(self):
"""Test parsing URL without issue number."""
from click import ClickException
with pytest.raises(ClickException):
parse_github_url("https://github.com/owner/repo")
class TestCLI:
"""Tests for CLI commands."""
@patch('scaffoldforge.cli.commands.IssueParser')
@patch('scaffoldforge.cli.commands.TemplateEngine')
@patch('scaffoldforge.cli.commands.StructureGenerator')
@patch('scaffoldforge.cli.commands.CodeGenerator')
def test_generate_command_preview_mode(
self, mock_code_gen, mock_struct_gen, mock_tpl_engine, mock_parser
):
"""Test generate command in preview mode."""
runner = CliRunner()
mock_issue_data = Mock()
mock_issue_data.number = 1
mock_issue_data.title = "Test Issue"
mock_issue_data.labels = ["python"]
mock_issue_data.checklist = []
mock_issue_data.get_todo_items.return_value = []
mock_issue_data.requirements = []
mock_issue_data.body = ""
mock_parser_instance = Mock()
mock_parser_instance.parse_issue.return_value = mock_issue_data
mock_parser_instance.detect_language.return_value = "python"
mock_parser.return_value = mock_parser_instance
mock_engine = Mock()
mock_engine.load_templates.return_value = {}
mock_engine.get_template_context.return_value = {}
mock_tpl_engine.return_value = mock_engine
result = runner.invoke(
cli,
["generate", "https://github.com/owner/repo/issues/1", "--preview"]
)
assert result.exit_code == 0
assert "PREVIEW" in result.output or "preview" in result.output.lower()
@patch('scaffoldforge.cli.commands.TemplateEngine')
def test_list_templates_command(self, mock_tpl_engine):
"""Test list-templates command."""
runner = CliRunner()
mock_engine = Mock()
mock_engine.list_available_templates.return_value = ["default", "cli"]
mock_tpl_engine.return_value = mock_engine
result = runner.invoke(cli, ["list-templates", "--language", "python"])
assert result.exit_code == 0
assert "python" in result.output.lower()
@patch('scaffoldforge.cli.commands.TemplateEngine')
def test_list_templates_all_languages(self, mock_tpl_engine):
"""Test list-templates without language filter."""
runner = CliRunner()
mock_engine = Mock()
mock_engine.list_available_templates.side_effect = [
["default"], ["default"], ["default"], ["default"]
]
mock_tpl_engine.return_value = mock_engine
result = runner.invoke(cli, ["list-templates"])
assert result.exit_code == 0
def test_cli_help(self):
"""Test CLI help output."""
runner = CliRunner()
result = runner.invoke(cli, ["--help"])
assert result.exit_code == 0
assert "ScaffoldForge" in result.output
def test_generate_help(self):
"""Test generate command help."""
runner = CliRunner()
result = runner.invoke(cli, ["generate", "--help"])
assert result.exit_code == 0
assert "--output" in result.output or "-o" in result.output
assert "--language" in result.output or "-l" in result.output
assert "--preview" in result.output or "-p" in result.output
class TestCLIErrorHandling:
"""Tests for CLI error handling."""
def test_generate_invalid_url(self):
"""Test generate with invalid URL."""
runner = CliRunner()
result = runner.invoke(
cli,
["generate", "https://invalid.com/issue/123"]
)
assert result.exit_code != 0
assert "Invalid" in result.output or "error" in result.output.lower()
@patch('scaffoldforge.cli.commands.IssueParser')
def test_generate_missing_language(
self, mock_parser
):
"""Test generate without specifying language when it can't be detected."""
runner = CliRunner()
mock_issue_data = Mock()
mock_issue_data.number = 1
mock_issue_data.title = "Test Issue"
mock_issue_data.labels = []
mock_issue_data.checklist = []
mock_issue_data.get_todo_items.return_value = []
mock_issue_data.requirements = []
mock_issue_data.body = ""
mock_parser_instance = Mock()
mock_parser_instance.parse_issue.return_value = mock_issue_data
mock_parser_instance.detect_language.return_value = None
mock_parser.return_value = mock_parser_instance
result = runner.invoke(
cli,
["generate", "https://github.com/owner/repo/issues/1"]
)
assert result.exit_code != 0