Initial upload: ScaffoldForge CLI tool with full codebase, tests, and CI/CD

This commit is contained in:
2026-02-04 05:37:20 +00:00
parent 6243751521
commit dba02f0756

View File

@@ -0,0 +1,185 @@
"""Unit tests for the generators module."""
import pytest
import os
import tempfile
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
from scaffoldforge.generators import StructureGenerator, CodeGenerator
from scaffoldforge.generators.structure import FileSpec
from scaffoldforge.parsers import IssueData, ChecklistItem
from scaffoldforge.templates import TemplateEngine
class TestFileSpec:
"""Tests for FileSpec dataclass."""
def test_file_spec_creation(self):
"""Test creating a file specification."""
spec = FileSpec(
path="src/main.py",
content="# Hello World"
)
assert spec.path == "src/main.py"
assert spec.content == "# Hello World"
assert spec.encoding == "utf-8"
assert spec.executable is False
def test_file_spec_executable(self):
"""Test executable file specification."""
spec = FileSpec(
path="script.sh",
content="#!/bin/bash",
executable=True
)
assert spec.executable is True
class TestStructureGenerator:
"""Tests for StructureGenerator class."""
def test_generator_initialization(self):
"""Test generator initialization."""
gen = StructureGenerator()
assert gen.output_dir == "./generated"
assert gen.preview is False
def test_generator_initialization_with_custom_dir(self):
"""Test generator with custom output directory."""
gen = StructureGenerator(output_dir="/tmp/myproject", preview=True)
assert gen.output_dir == "/tmp/myproject"
assert gen.preview is True
def test_sanitize_name(self):
"""Test name sanitization."""
gen = StructureGenerator()
assert gen._sanitize_name("Hello World!") == "hello-world"
assert gen._sanitize_name("Test/Project") == "testproject"
assert gen._sanitize_name(" Spaces ") == "spaces"
result = gen._sanitize_name("Very long name " * 10)
assert len(result) <= 50
def test_sanitize_name_empty(self):
"""Test sanitizing empty name."""
gen = StructureGenerator()
result = gen._sanitize_name("!!!")
assert result == "project"
@patch('scaffoldforge.generators.code.TemplateEngine')
def test_generate_creates_files(self, mock_template_engine):
"""Test that generate creates files in preview mode."""
issue_data = IssueData(
number=1, title="Test Issue", body="", body_html="",
labels=["python"], state="open", url="", repository="",
author="", created_at="", updated_at="",
checklist=[ChecklistItem(text="Task 1", completed=False)]
)
with tempfile.TemporaryDirectory() as tmpdir:
gen = StructureGenerator(output_dir=tmpdir, preview=True)
mock_engine = Mock(spec=TemplateEngine)
mock_engine.get_template_context.return_value = {
"project_name": "test-project"
}
code_gen = Mock(spec=CodeGenerator)
code_gen.generate_all_files.return_value = [
FileSpec(path="main.py", content="print('hello')")
]
gen.generate("python", issue_data, code_gen)
def test_get_created_files(self):
"""Test getting list of created files."""
gen = StructureGenerator()
gen.created_files = ["file1.py", "file2.py"]
files = gen.get_created_files()
assert len(files) == 2
assert "file1.py" in files
def test_get_created_directories(self):
"""Test getting list of created directories."""
gen = StructureGenerator()
gen.created_dirs = ["src", "tests"]
dirs = gen.get_created_directories()
assert len(dirs) == 2
class TestCodeGenerator:
"""Tests for CodeGenerator class."""
def test_code_generator_initialization(self):
"""Test code generator initialization."""
issue_data = IssueData(
number=1, title="Test", body="", body_html="",
labels=[], state="open", url="", repository="",
author="", created_at="", updated_at=""
)
engine = TemplateEngine()
gen = CodeGenerator(engine, issue_data)
assert gen.issue_data == issue_data
assert gen.template_engine == engine
def test_get_extension(self):
"""Test file extension detection."""
issue_data = IssueData(
number=1, title="Test", body="", body_html="",
labels=[], state="open", url="", repository="",
author="", created_at="", updated_at=""
)
engine = TemplateEngine()
gen = CodeGenerator(engine, issue_data)
assert gen._get_extension("python") == ".py"
assert gen._get_extension("javascript") == ".js"
assert gen._get_extension("go") == ".go"
assert gen._get_extension("rust") == ".rs"
assert gen._get_extension("unknown") == ".txt"
def test_get_source_path(self):
"""Test source path generation."""
issue_data = IssueData(
number=1, title="Test", body="", body_html="",
labels=[], state="open", url="", repository="",
author="", created_at="", updated_at=""
)
engine = TemplateEngine()
gen = CodeGenerator(engine, issue_data)
assert gen._get_source_path("main", "python") == "main.py"
assert gen._get_source_path("utils", "python") == "src/utils.py"
assert gen._get_source_path("lib", "rust") == "src/lib.rs"
def test_generate_todo_content_python(self):
"""Test TODO content generation for Python."""
issue_data = IssueData(
number=42, title="Test", body="", body_html="",
labels=[], state="open", url="", repository="",
author="", created_at="", updated_at="",
checklist=[
ChecklistItem(text="Implement feature", completed=False),
ChecklistItem(text="Add tests", completed=False),
]
)
engine = TemplateEngine()
gen = CodeGenerator(engine, issue_data)
content = gen._generate_todo_content("python", "main", ["Task 1", "Task 2"])
assert '"""' in content
assert "# TODO: Task 1" in content
def test_generate_todo_content_go(self):
"""Test TODO content generation for Go."""
issue_data = IssueData(
number=1, title="Test", body="", body_html="",
labels=[], state="open", url="", repository="",
author="", created_at="", updated_at="",
checklist=[ChecklistItem(text="Task 1", completed=False)]
)
engine = TemplateEngine()
gen = CodeGenerator(engine, issue_data)
content = gen._generate_todo_content("go", "main", ["Task 1"])
assert "// main" in content
assert "# TODO: Task 1" in content