# SPDX-FileCopyrightText: 2025 Alexander Kalinovsky # # SPDX-License-Identifier: MIT """Pytest configuration and fixtures for CLI tests.""" import shutil import sys import tempfile from collections.abc import Generator from pathlib import Path from unittest.mock import MagicMock, patch import pytest from typer.testing import CliRunner # Add src to path for imports sys.path.insert(0, str(Path(__file__).parent.parent / "src")) @pytest.fixture def cli_runner() -> CliRunner: """Provide a CLI runner for testing commands.""" return CliRunner() @pytest.fixture def temp_dir() -> Generator[Path]: """Provide a temporary directory for testing.""" with tempfile.TemporaryDirectory() as tmp_dir: yield Path(tmp_dir) @pytest.fixture def mock_template_dir() -> Generator[Path]: """Provide a mock template directory structure.""" template_dir = Path(__file__).parent / "fixtures" / "mock_template" template_dir.mkdir(parents=True, exist_ok=True) # Create template spec spec_file = template_dir / "__template__.yaml" spec_content = """ variables: project_name: prompt: "Project name" default: "test_project" description: prompt: "Description" default: "Test description" author: prompt: "Author" default: "Test Author" license: prompt: "License" default: "MIT" include_alembic: prompt: "Include Alembic?" choices: ["yes", "no"] default: "yes" include_i18n: prompt: "Include i18n?" choices: [true, false] default: true post_tasks: - when: "{{ include_alembic == 'yes' }}" run: ["echo", "alembic_init"] - when: "{{ include_i18n == true }}" run: ["echo", "babel_init"] """ spec_file.write_text(spec_content) # Create some template files (template_dir / "app").mkdir() (template_dir / "app" / "main.py.j2").write_text( "from fastapi import FastAPI\n\napp = FastAPI(title='{{ project_name }}')\n" ) (template_dir / "app" / "config.py.j2").write_text( "PROJECT_NAME = '{{ project_name }}'\nDESCRIPTION = '{{ description }}'\n" ) (template_dir / "README.md.j2").write_text( "# {{ project_name }}\n\n{{ description }}\n\nAuthor: {{ author }}\nLicense: {{ license }}" ) (template_dir / "pyproject.toml.j2").write_text( "[project]\nname = '{{ project_name }}'\ndescription = '{{ description }}'" ) # Create optional modules (template_dir / "alembic").mkdir() (template_dir / "alembic" / "alembic.ini.j2").write_text("alembic config for {{ project_name }}") (template_dir / "locales").mkdir() (template_dir / "locales" / "en").mkdir() (template_dir / "locales" / "en" / "LC_MESSAGES").mkdir() # Create scripts (template_dir / "scripts").mkdir() (template_dir / "scripts" / "migrations_generate.sh.j2").write_text( "#!/bin/bash\necho 'Generate migrations for {{ project_name }}'" ) (template_dir / "scripts" / "migrations_apply.sh.j2").write_text( "#!/bin/bash\necho 'Apply migrations for {{ project_name }}'" ) (template_dir / "scripts" / "babel_init.sh.j2").write_text("#!/bin/bash\necho 'Init Babel for {{ project_name }}'") (template_dir / "scripts" / "babel_extract.sh.j2").write_text( "#!/bin/bash\necho 'Extract Babel for {{ project_name }}'" ) (template_dir / "scripts" / "babel_update.sh.j2").write_text( "#!/bin/bash\necho 'Update Babel for {{ project_name }}'" ) (template_dir / "scripts" / "babel_compile.sh.j2").write_text( "#!/bin/bash\necho 'Compile Babel for {{ project_name }}'" ) yield template_dir # Cleanup shutil.rmtree(template_dir) @pytest.fixture def mock_typer_prompt() -> Generator[MagicMock]: """Mock typer.prompt to avoid interactive input during tests.""" with patch("quickbot_cli.cli.typer.prompt") as mock_prompt: mock_prompt.return_value = "test_value" yield mock_prompt @pytest.fixture def mock_typer_secho() -> Generator[MagicMock]: """Mock typer.secho to capture output during tests.""" with patch("quickbot_cli.cli.typer.secho") as mock_secho: yield mock_secho @pytest.fixture def mock_typer_echo() -> Generator[MagicMock]: """Mock typer.echo to capture output during tests.""" with patch("quickbot_cli.cli.typer.echo") as mock_echo: yield mock_echo @pytest.fixture def mock_subprocess_run() -> Generator[MagicMock]: """Mock subprocess.run to avoid actual command execution during tests.""" with patch("quickbot_cli.cli.subprocess.run") as mock_run: mock_run.return_value = MagicMock(returncode=0) yield mock_run