Files
markitect-main/tests/test_issue_40_cli_integration.py
tegwick 3f2449aea1 fix: Update tests to match schema reference metadata feature
Fix failing tests that expected content to start with heading but now
include schema reference comments. Also fix validate command syntax
in test (positional to --schema flag).

Fixes:
- test_generate_stub_with_explicit_associated_path
- test_generate_stub_interactive_mode_defaults_to_associated_path
- test_generate_stub_validates_generated_draft_against_schema

These tests were failing due to changes from Issue #55 schema reference
metadata feature and validate command syntax updates.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 12:48:48 +02:00

330 lines
12 KiB
Python

"""
CLI Integration Tests for Issue #40: Associated Files Management.
Tests the enhanced CLI commands that work with associated files.
"""
import json
import pytest
from pathlib import Path
from tempfile import TemporaryDirectory
from click.testing import CliRunner
from markitect.cli import cli
class TestIssue40CLIIntegration:
"""Test CLI integration for associated files management."""
@pytest.fixture
def runner(self):
"""Create CLI test runner."""
return CliRunner()
@pytest.fixture
def temp_dir(self):
"""Create a temporary directory for testing."""
with TemporaryDirectory() as temp_dir:
yield Path(temp_dir)
def test_schema_generate_with_explicit_associated_path(self, runner, temp_dir):
"""schema-generate can use explicit associated .json file path."""
md_file = temp_dir / "document.md"
md_file.write_text("# Document\n\n## Introduction\n\nContent here.")
# Explicitly specify associated file path
expected_schema = temp_dir / "document.json"
result = runner.invoke(cli, [
'schema-generate', str(md_file), '--output', str(expected_schema)
])
assert result.exit_code == 0
# Should create associated schema file
assert expected_schema.exists()
# Verify it's valid JSON
schema_content = json.loads(expected_schema.read_text())
assert schema_content['type'] == 'object'
def test_schema_generate_interactive_mode_defaults_to_associated_path(self, runner, temp_dir):
"""schema-generate in interactive mode should default to associated path."""
md_file = temp_dir / "document.md"
md_file.write_text("# Document\n\n## Introduction\n\nContent here.")
# Run schema-generate without --output in interactive mode
result = runner.invoke(cli, [
'schema-generate', str(md_file)
], env={'MARKITECT_MODE': 'interactive'})
assert result.exit_code == 0
# Should create associated schema file
expected_schema = temp_dir / "document.json"
assert expected_schema.exists()
# Verify it's valid JSON
schema_content = json.loads(expected_schema.read_text())
assert schema_content['type'] == 'object'
def test_generate_stub_with_explicit_associated_path(self, runner, temp_dir):
"""generate-stub can use explicit associated .md file path."""
schema_file = temp_dir / "template.json"
schema_content = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Template Schema",
"properties": {
"headings": {
"type": "object",
"properties": {
"level_1": {"type": "array", "minItems": 1, "maxItems": 1}
}
}
}
}
schema_file.write_text(json.dumps(schema_content))
# Explicitly specify associated file path
expected_md = temp_dir / "template.md"
result = runner.invoke(cli, [
'generate-stub', str(schema_file), '--output', str(expected_md)
])
assert result.exit_code == 0
# Should create associated markdown file
assert expected_md.exists()
# Verify it's valid markdown with schema reference
md_content = expected_md.read_text()
# Content should include schema reference metadata and heading
assert '<!-- Generated from schema:' in md_content
assert '# Template Schema' in md_content
def test_generate_stub_interactive_mode_defaults_to_associated_path(self, runner, temp_dir):
"""generate-stub in interactive mode should default to associated path."""
schema_file = temp_dir / "template.json"
schema_content = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Template Schema",
"properties": {
"headings": {
"type": "object",
"properties": {
"level_1": {"type": "array", "minItems": 1, "maxItems": 1}
}
}
}
}
schema_file.write_text(json.dumps(schema_content))
# Run generate-stub without --output in interactive mode
result = runner.invoke(cli, [
'generate-stub', str(schema_file)
], env={'MARKITECT_MODE': 'interactive'})
assert result.exit_code == 0
# Should create associated markdown file
expected_md = temp_dir / "template.md"
assert expected_md.exists()
# Verify it's valid markdown with schema reference
md_content = expected_md.read_text()
# Content should include schema reference metadata and heading
assert '<!-- Generated from schema:' in md_content
assert '# Template Schema' in md_content
def test_validate_auto_discovers_associated_schema(self, runner, temp_dir):
"""validate should auto-discover associated schema when not specified."""
md_file = temp_dir / "article.md"
schema_file = temp_dir / "article.json"
md_file.write_text("# Article\n\n## Introduction\n\nContent.")
schema_file.write_text('{"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "title": "Article Schema"}')
# Run validate with only markdown file (should find associated schema)
result = runner.invoke(cli, [
'validate', str(md_file)
])
assert result.exit_code == 0
# Should indicate successful validation using auto-discovered schema
def test_new_associated_files_list_command(self, runner, temp_dir):
"""Should have new command to list associated file pairs."""
# Create some file pairs
(temp_dir / "doc1.md").write_text("# Doc 1")
(temp_dir / "doc1.json").write_text('{"type": "object"}')
(temp_dir / "doc2.md").write_text("# Doc 2")
(temp_dir / "doc2.json").write_text('{"type": "object"}')
# Create orphaned files
(temp_dir / "orphan.md").write_text("# Orphan")
result = runner.invoke(cli, [
'associated-files', 'list', str(temp_dir)
])
assert result.exit_code == 0
assert 'doc1' in result.output
assert 'doc2' in result.output
# Should show paired status
def test_new_associated_files_info_command(self, runner, temp_dir):
"""Should have command to show info about associated files."""
md_file = temp_dir / "example.md"
schema_file = temp_dir / "example.json"
md_file.write_text("# Example\n\nContent here.")
schema_file.write_text('{"type": "object", "title": "Example"}')
result = runner.invoke(cli, [
'associated-files', 'info', str(md_file)
])
assert result.exit_code == 0
assert 'example' in result.output
assert 'paired' in result.output.lower()
def test_new_associated_files_create_command(self, runner, temp_dir):
"""Should have command to create missing associated files."""
md_file = temp_dir / "lonely.md"
md_file.write_text("# Lonely Document\n\n## Section\n\nContent.")
# Create associated schema
result = runner.invoke(cli, [
'associated-files', 'create-schema', str(md_file)
])
assert result.exit_code == 0
expected_schema = temp_dir / "lonely.json"
assert expected_schema.exists()
# Verify it's a valid schema
schema = json.loads(expected_schema.read_text())
assert schema['type'] == 'object'
def test_new_associated_files_create_stub_command(self, runner, temp_dir):
"""Should have command to create stub from existing schema."""
schema_file = temp_dir / "template.json"
schema_content = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Template",
"properties": {
"headings": {
"type": "object",
"properties": {
"level_1": {"type": "array", "minItems": 1}
}
}
}
}
schema_file.write_text(json.dumps(schema_content))
# Create associated markdown stub
result = runner.invoke(cli, [
'associated-files', 'create-stub', str(schema_file)
])
assert result.exit_code == 0
expected_md = temp_dir / "template.md"
assert expected_md.exists()
# Verify it's valid markdown
md_content = expected_md.read_text()
assert md_content.startswith('# ')
def test_associated_files_status_command(self, runner, temp_dir):
"""Should show status of associated files in directory."""
# Create mixed scenarios
(temp_dir / "paired.md").write_text("# Paired")
(temp_dir / "paired.json").write_text('{"type": "object"}')
(temp_dir / "lonely.md").write_text("# Lonely")
(temp_dir / "orphan.json").write_text('{"type": "object"}')
result = runner.invoke(cli, [
'associated-files', 'status', str(temp_dir)
])
assert result.exit_code == 0
assert 'paired' in result.output.lower() or 'orphaned' in result.output.lower()
def test_enhanced_commands_preserve_explicit_output(self, runner, temp_dir):
"""Enhanced commands should still respect explicit --output options."""
md_file = temp_dir / "source.md"
md_file.write_text("# Source\n\n## Content")
custom_output = temp_dir / "custom_name.json"
# Use explicit output path (should override associated file logic)
result = runner.invoke(cli, [
'schema-generate', str(md_file), '--output', str(custom_output)
])
assert result.exit_code == 0
assert custom_output.exists()
assert not (temp_dir / "source.json").exists()
def test_associated_files_help_commands(self, runner):
"""Associated files commands should provide helpful usage information."""
result = runner.invoke(cli, ['associated-files', '--help'])
assert result.exit_code == 0
assert 'associated' in result.output.lower()
assert 'files' in result.output.lower()
# Test subcommand help
result = runner.invoke(cli, ['associated-files', 'list', '--help'])
assert result.exit_code == 0
def test_error_handling_for_non_existent_files(self, runner, temp_dir):
"""Should handle non-existent files gracefully."""
non_existent = temp_dir / "does_not_exist.md"
result = runner.invoke(cli, [
'associated-files', 'info', str(non_existent)
])
assert result.exit_code != 0
assert 'not found' in result.output.lower() or 'error' in result.output.lower()
def test_workflow_integration_complete_cycle(self, runner, temp_dir):
"""Test complete workflow with associated files."""
original_md = temp_dir / "workflow.md"
original_md.write_text("# Workflow Example\n\n## Introduction\n\nTest content.")
# Step 1: Generate schema explicitly to workflow.json
schema_file = temp_dir / "workflow.json"
result1 = runner.invoke(cli, [
'schema-generate', str(original_md), '--output', str(schema_file)
])
assert result1.exit_code == 0
assert schema_file.exists()
# Step 2: Generate stub with different name to avoid conflict
stub_name = temp_dir / "workflow_template.md"
result2 = runner.invoke(cli, [
'generate-stub', str(schema_file), '--output', str(stub_name)
])
assert result2.exit_code == 0
assert stub_name.exists()
# Step 3: Validate original against its schema
result3 = runner.invoke(cli, [
'validate', str(original_md)
])
assert result3.exit_code == 0
# Step 4: List associated files
result4 = runner.invoke(cli, [
'associated-files', 'status', str(temp_dir)
])
assert result4.exit_code == 0
assert 'paired' in result4.output.lower() or 'orphaned' in result4.output.lower()