147 lines
4.6 KiB
Python
147 lines
4.6 KiB
Python
# SPDX-FileCopyrightText: 2025 Alexander Kalinovsky <a@k8y.ru>
|
|
#
|
|
# 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
|