Files
markitect-main/tests/test_cli_integration.py
tegwick bcbe78d04f feat: Complete Issue #65 Template Engine Foundation + Fix CLI Regression
## Issue #65 - Template Engine Foundation (COMPLETED)
- Implement complete TDD8 methodology with 30 comprehensive tests (100% passing)
- Add template variable parser with Unicode and dot notation support
- Add template rendering engine with strict/lenient modes
- Add business document generation (invoices, reports)
- Add CLI integration with `markitect template-render` command
- Add performance optimization (1000+ variables in <0.1s)

## Critical CLI Regression Fix
- Fix broken `markitect --help` due to import path issues in markitect/issues/base.py
- Add proper path resolution for domain module accessibility
- Add 12 comprehensive CLI integration tests to prevent future regressions
- Restore full CLI functionality with 35+ working commands

## Template Engine Architecture
- markitect/template/parser.py - Variable parsing with comprehensive validation
- markitect/template/engine.py - Template rendering with business logic
- markitect/template/__init__.py - Structured package exports
- Comprehensive exception hierarchy for robust error handling

## Test Coverage Excellence
- 30 Issue #65 tests: parser (9), substitution (14), integration (7)
- 12 CLI integration tests for regression prevention
- Business scenario validation with real invoice/report generation
- Performance benchmarking and error handling validation

## CLI Professional Enhancement
- Add template-render command with comprehensive options
- Fix import path issues preventing CLI access
- Add validation, data checking, output options
- Support JSON/YAML data formats with auto-detection

## Business Impact
- Transform MarkiTect from document analysis to business automation platform
- Enable professional invoice and report generation
- Provide robust CLI interface for document workflows
- Establish foundation for Epic #64 advanced template features

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-02 15:33:32 +02:00

294 lines
10 KiB
Python

"""
CLI Integration Tests - Prevent CLI Entry Point Regressions
This test module validates that the CLI entry point is properly accessible
and core commands work as expected. It prevents regressions like broken
imports or missing entry points that would break user accessibility.
Tests focus on:
- CLI entry point accessibility (markitect --help)
- Core command availability and help text
- Template rendering CLI functionality
- Error handling in CLI commands
"""
import subprocess
import tempfile
import json
import os
import pytest
from pathlib import Path
class TestCLIEntryPoint:
"""Test CLI entry point accessibility."""
def test_markitect_help_accessible(self):
"""Test that markitect --help works and shows expected content.
This prevents regressions where import errors break CLI accessibility.
"""
# Run markitect --help
result = subprocess.run(
['markitect', '--help'],
capture_output=True,
text=True
)
# Should exit successfully
assert result.returncode == 0, f"CLI help failed with error: {result.stderr}"
# Should contain core CLI information
output = result.stdout
assert "MarkiTect - Advanced Markdown engine" in output
assert "Commands:" in output
assert "--help" in output
# Should not have import errors
assert "ModuleNotFoundError" not in result.stderr
assert "ImportError" not in result.stderr
def test_core_commands_available(self):
"""Test that core commands are listed in help output."""
result = subprocess.run(
['markitect', '--help'],
capture_output=True,
text=True
)
output = result.stdout
# Core functionality commands
assert "ingest" in output
assert "list" in output
assert "status" in output or "stats" in output
# Template engine command (Issue #65)
assert "template-render" in output
# Schema commands
assert "schema-generate" in output
assert "validate" in output
def test_template_render_command_help(self):
"""Test that template-render command help is accessible."""
result = subprocess.run(
['markitect', 'template-render', '--help'],
capture_output=True,
text=True
)
assert result.returncode == 0
output = result.stdout
assert "Render a template with data" in output
assert "TEMPLATE_FILE" in output
assert "DATA_FILE" in output
assert "--output" in output
assert "--strict" in output
assert "--lenient" in output
class TestTemplateRenderCLI:
"""Test template-render CLI functionality end-to-end."""
def test_template_render_basic_functionality(self):
"""Test basic template rendering via CLI."""
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# Create test template
template_file = temp_path / "test.md"
template_file.write_text("# {{title}}\n\nHello {{name}}!")
# Create test data
data_file = temp_path / "data.json"
data = {"title": "Test Document", "name": "World"}
data_file.write_text(json.dumps(data))
# Run template rendering
result = subprocess.run(
['markitect', 'template-render', str(template_file), str(data_file)],
capture_output=True,
text=True
)
assert result.returncode == 0, f"Template rendering failed: {result.stderr}"
output = result.stdout
assert "# Test Document" in output
assert "Hello World!" in output
def test_template_render_with_output_file(self):
"""Test template rendering with output file option."""
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# Create test files
template_file = temp_path / "template.md"
template_file.write_text("Result: {{value}}")
data_file = temp_path / "data.json"
data_file.write_text(json.dumps({"value": "SUCCESS"}))
output_file = temp_path / "output.md"
# Run with output option
result = subprocess.run(
['markitect', 'template-render',
str(template_file), str(data_file),
'--output', str(output_file)],
capture_output=True,
text=True
)
assert result.returncode == 0
assert "Template rendered successfully" in result.stdout
# Check output file was created
assert output_file.exists()
content = output_file.read_text()
assert "Result: SUCCESS" in content
def test_template_render_validation_mode(self):
"""Test template rendering with validation options."""
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# Create valid template
template_file = temp_path / "valid.md"
template_file.write_text("Valid: {{name}}")
data_file = temp_path / "data.json"
data_file.write_text(json.dumps({"name": "test"}))
# Run with validation
result = subprocess.run(
['markitect', 'template-render',
str(template_file), str(data_file),
'--validate', '--check-data'],
capture_output=True,
text=True
)
assert result.returncode == 0
assert "Valid: test" in result.stdout
def test_template_render_error_handling(self):
"""Test CLI error handling for invalid inputs."""
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# Test with non-existent template file
result = subprocess.run(
['markitect', 'template-render', 'nonexistent.md', 'data.json'],
capture_output=True,
text=True
)
assert result.returncode != 0
assert "does not exist" in result.stderr.lower() or "not found" in result.stderr.lower()
def test_template_render_strict_vs_lenient_mode(self):
"""Test strict vs lenient mode behavior."""
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# Template with missing variable
template_file = temp_path / "template.md"
template_file.write_text("Hello {{name}}, missing: {{missing}}")
# Data missing the 'missing' variable
data_file = temp_path / "data.json"
data_file.write_text(json.dumps({"name": "Alice"}))
# Test strict mode (should fail)
result_strict = subprocess.run(
['markitect', 'template-render', str(template_file), str(data_file), '--strict'],
capture_output=True,
text=True
)
assert result_strict.returncode != 0
# Test lenient mode (should succeed)
result_lenient = subprocess.run(
['markitect', 'template-render', str(template_file), str(data_file), '--lenient'],
capture_output=True,
text=True
)
assert result_lenient.returncode == 0
output = result_lenient.stdout
assert "Hello Alice" in output
assert "{{missing}}" in output # Placeholder preserved
class TestCLIRegressionPrevention:
"""Tests specifically designed to catch common CLI regression patterns."""
def test_import_paths_valid(self):
"""Test that all CLI module imports work correctly.
This catches issues like the domain module import that broke CLI access.
"""
# Try to import the CLI module directly
try:
import markitect.cli
# Should not raise ImportError or ModuleNotFoundError
except (ImportError, ModuleNotFoundError) as e:
pytest.fail(f"CLI module import failed: {e}")
def test_cli_entry_point_configuration(self):
"""Test that the CLI entry point is properly configured."""
# Check that the entry point script exists and is executable
import shutil
markitect_path = shutil.which('markitect')
assert markitect_path is not None, "markitect command not found in PATH"
assert os.access(markitect_path, os.X_OK), "markitect command is not executable"
def test_no_runtime_import_errors(self):
"""Test that basic CLI commands don't have runtime import errors."""
# Test a few key commands to ensure no import errors at runtime
commands_to_test = [
['markitect', '--version'], # Should show version or error gracefully
['markitect', 'list', '--help'], # Core command help
['markitect', 'template-render', '--help'], # New template command help
]
for cmd in commands_to_test:
result = subprocess.run(cmd, capture_output=True, text=True)
# Even if command fails, it shouldn't be due to import errors
assert "ModuleNotFoundError" not in result.stderr
assert "ImportError" not in result.stderr
assert "No module named" not in result.stderr
def test_template_engine_availability(self):
"""Test that template engine is properly available to CLI."""
# Create minimal test to ensure template engine can be imported by CLI
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
template_file = temp_path / "minimal.md"
template_file.write_text("test")
data_file = temp_path / "minimal.json"
data_file.write_text("{}")
# This should not fail with import errors
result = subprocess.run(
['markitect', 'template-render', str(template_file), str(data_file)],
capture_output=True,
text=True
)
# Should succeed or fail gracefully, but not with import errors
assert "ImportError" not in result.stderr
assert "ModuleNotFoundError" not in result.stderr
assert "Template engine not available" not in result.stderr
if __name__ == '__main__':
pytest.main([__file__, '-v'])