Some checks failed
Test Suite / code-quality (push) Has been cancelled
Test Suite / unit-tests (3.11) (push) Has been cancelled
Test Suite / unit-tests (3.12) (push) Has been cancelled
Test Suite / integration-tests (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / performance-tests (push) Has been cancelled
Test Suite / security-scan (push) Has been cancelled
Test Suite / test-summary (push) Has been cancelled
This commit implements comprehensive associated files management and introduces a mode-based architecture that resolves conflicting requirements between interactive user workflows and automation/testing scenarios. ## Key Features ### Associated Files Management - Convention-based file pairing (document.md ↔ document.json) - Automatic path resolution and file discovery - Complete CLI command suite for managing file pairs - Performance optimizations with caching ### Interactive vs Automation Mode System - Automatic mode detection via TTY, CI environment, and pipes - Environment variable override (MARKITECT_MODE) - Interactive mode: Uses associated file paths by default - Automation mode: Optimizes for speed, memory, and stdout output ### Enhanced CLI Commands - schema-generate: Auto-places output next to source in interactive mode - generate-stub: Auto-places output next to schema in interactive mode - validate: Auto-discovers associated schema files - New associated-files command group with list, info, status, create subcommands ### Bug Fixes - Fixed isinstance() errors caused by function shadowing built-in types - Resolved test failures with new mode system integration - Ensured backward compatibility for all existing functionality ## Technical Implementation - Added AssociatedFilesManager class with comprehensive file operations - Implemented mode detection using environment analysis - Enhanced format_output function with proper type checking - Added pytest configuration for automation mode during testing - Complete test coverage for all new functionality All 448 tests passing. Maintains full backward compatibility while adding powerful new interactive features for improved developer experience. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
271 lines
10 KiB
Python
271 lines
10 KiB
Python
"""
|
|
Tests for Issue #40: Associated Files Management.
|
|
|
|
This module tests the functionality for managing associated markdown and schema files
|
|
with convention-based naming and automatic file placement.
|
|
"""
|
|
|
|
import pytest
|
|
from pathlib import Path
|
|
from tempfile import TemporaryDirectory
|
|
|
|
from markitect.associated_files import AssociatedFilesManager
|
|
|
|
|
|
class TestIssue40AssociatedFiles:
|
|
"""Test suite for associated files management."""
|
|
|
|
@pytest.fixture
|
|
def manager(self):
|
|
"""Create an AssociatedFilesManager instance."""
|
|
return AssociatedFilesManager()
|
|
|
|
@pytest.fixture
|
|
def temp_dir(self):
|
|
"""Create a temporary directory for testing."""
|
|
with TemporaryDirectory() as temp_dir:
|
|
yield Path(temp_dir)
|
|
|
|
def test_associated_files_manager_can_be_created(self, manager):
|
|
"""AssociatedFilesManager class should be importable and instantiable."""
|
|
assert manager is not None
|
|
assert isinstance(manager, AssociatedFilesManager)
|
|
|
|
def test_get_associated_schema_path(self, manager, temp_dir):
|
|
"""Should generate correct associated schema path for markdown file."""
|
|
md_file = temp_dir / "document.md"
|
|
md_file.write_text("# Test Document")
|
|
|
|
schema_path = manager.get_associated_schema_path(md_file)
|
|
|
|
assert schema_path == temp_dir / "document.json"
|
|
assert schema_path.parent == md_file.parent
|
|
assert schema_path.stem == md_file.stem
|
|
|
|
def test_get_associated_markdown_path(self, manager, temp_dir):
|
|
"""Should generate correct associated markdown path for schema file."""
|
|
schema_file = temp_dir / "document.json"
|
|
schema_file.write_text('{"type": "object"}')
|
|
|
|
md_path = manager.get_associated_markdown_path(schema_file)
|
|
|
|
assert md_path == temp_dir / "document.md"
|
|
assert md_path.parent == schema_file.parent
|
|
assert md_path.stem == schema_file.stem
|
|
|
|
def test_find_associated_schema(self, manager, temp_dir):
|
|
"""Should find existing associated schema file."""
|
|
md_file = temp_dir / "blog_post.md"
|
|
schema_file = temp_dir / "blog_post.json"
|
|
|
|
md_file.write_text("# Blog Post")
|
|
schema_file.write_text('{"type": "object"}')
|
|
|
|
found_schema = manager.find_associated_schema(md_file)
|
|
|
|
assert found_schema == schema_file
|
|
assert found_schema.exists()
|
|
|
|
def test_find_associated_markdown(self, manager, temp_dir):
|
|
"""Should find existing associated markdown file."""
|
|
md_file = temp_dir / "article.md"
|
|
schema_file = temp_dir / "article.json"
|
|
|
|
md_file.write_text("# Article")
|
|
schema_file.write_text('{"type": "object"}')
|
|
|
|
found_md = manager.find_associated_markdown(schema_file)
|
|
|
|
assert found_md == md_file
|
|
assert found_md.exists()
|
|
|
|
def test_find_associated_files_returns_none_when_not_found(self, manager, temp_dir):
|
|
"""Should return None when associated files don't exist."""
|
|
md_file = temp_dir / "lonely.md"
|
|
md_file.write_text("# Lonely Document")
|
|
|
|
schema_file = temp_dir / "orphan.json"
|
|
schema_file.write_text('{"type": "object"}')
|
|
|
|
assert manager.find_associated_schema(md_file) is None
|
|
assert manager.find_associated_markdown(schema_file) is None
|
|
|
|
def test_has_associated_schema(self, manager, temp_dir):
|
|
"""Should correctly detect if markdown file has associated schema."""
|
|
md_file = temp_dir / "test.md"
|
|
schema_file = temp_dir / "test.json"
|
|
|
|
md_file.write_text("# Test")
|
|
|
|
# No schema initially
|
|
assert not manager.has_associated_schema(md_file)
|
|
|
|
# Create schema
|
|
schema_file.write_text('{"type": "object"}')
|
|
assert manager.has_associated_schema(md_file)
|
|
|
|
def test_has_associated_markdown(self, manager, temp_dir):
|
|
"""Should correctly detect if schema file has associated markdown."""
|
|
md_file = temp_dir / "guide.md"
|
|
schema_file = temp_dir / "guide.json"
|
|
|
|
schema_file.write_text('{"type": "object"}')
|
|
|
|
# No markdown initially
|
|
assert not manager.has_associated_markdown(schema_file)
|
|
|
|
# Create markdown
|
|
md_file.write_text("# Guide")
|
|
assert manager.has_associated_markdown(schema_file)
|
|
|
|
def test_list_file_pairs(self, manager, temp_dir):
|
|
"""Should list all associated file pairs in directory."""
|
|
# Create some paired files
|
|
(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")
|
|
(temp_dir / "lonely.json").write_text('{"type": "object"}')
|
|
|
|
pairs = manager.list_file_pairs(temp_dir)
|
|
|
|
assert len(pairs) == 2
|
|
pair_names = {pair['basename'] for pair in pairs}
|
|
assert 'doc1' in pair_names
|
|
assert 'doc2' in pair_names
|
|
|
|
def test_get_file_pair_info(self, manager, temp_dir):
|
|
"""Should provide detailed information about file pairs."""
|
|
md_file = temp_dir / "example.md"
|
|
schema_file = temp_dir / "example.json"
|
|
|
|
md_file.write_text("# Example Document\n\nContent here.")
|
|
schema_file.write_text('{"type": "object", "title": "Example Schema"}')
|
|
|
|
pair_info = manager.get_file_pair_info(md_file)
|
|
|
|
assert pair_info['basename'] == 'example'
|
|
assert pair_info['markdown_file'] == md_file
|
|
assert pair_info['schema_file'] == schema_file
|
|
assert pair_info['both_exist'] is True
|
|
assert 'markdown_size' in pair_info
|
|
assert 'schema_size' in pair_info
|
|
|
|
def test_supports_nested_directories(self, manager, temp_dir):
|
|
"""Should work correctly with nested directory structures."""
|
|
nested_dir = temp_dir / "docs" / "architecture"
|
|
nested_dir.mkdir(parents=True)
|
|
|
|
md_file = nested_dir / "system.md"
|
|
schema_file = nested_dir / "system.json"
|
|
|
|
md_file.write_text("# System Architecture")
|
|
|
|
schema_path = manager.get_associated_schema_path(md_file)
|
|
assert schema_path == schema_file
|
|
assert not manager.has_associated_schema(md_file)
|
|
|
|
schema_file.write_text('{"type": "object"}')
|
|
assert manager.has_associated_schema(md_file)
|
|
|
|
def test_handles_complex_filenames(self, manager, temp_dir):
|
|
"""Should handle complex filenames with special characters."""
|
|
complex_name = "my-complex_file.name-v2"
|
|
md_file = temp_dir / f"{complex_name}.md"
|
|
|
|
md_file.write_text("# Complex File")
|
|
|
|
schema_path = manager.get_associated_schema_path(md_file)
|
|
expected_schema = temp_dir / f"{complex_name}.json"
|
|
|
|
assert schema_path == expected_schema
|
|
assert schema_path.stem == complex_name
|
|
|
|
def test_validate_file_extensions(self, manager, temp_dir):
|
|
"""Should validate that files have correct extensions."""
|
|
txt_file = temp_dir / "document.txt"
|
|
txt_file.write_text("Not markdown")
|
|
|
|
from markitect.associated_files import InvalidFileTypeError
|
|
|
|
with pytest.raises(InvalidFileTypeError, match="Expected markdown file"):
|
|
manager.get_associated_schema_path(txt_file)
|
|
|
|
xml_file = temp_dir / "schema.xml"
|
|
xml_file.write_text("<schema/>")
|
|
|
|
with pytest.raises(InvalidFileTypeError, match="Expected schema file"):
|
|
manager.get_associated_markdown_path(xml_file)
|
|
|
|
|
|
class TestAssociatedFilesIntegration:
|
|
"""Test integration of associated files with existing commands."""
|
|
|
|
@pytest.fixture
|
|
def manager(self):
|
|
return AssociatedFilesManager()
|
|
|
|
@pytest.fixture
|
|
def temp_dir(self):
|
|
with TemporaryDirectory() as temp_dir:
|
|
yield Path(temp_dir)
|
|
|
|
def test_schema_generate_default_output_placement(self, manager, temp_dir):
|
|
"""Schema generation should default to placing output next to source."""
|
|
md_file = temp_dir / "article.md"
|
|
md_file.write_text("# Article\n\n## Introduction\n\nContent here.")
|
|
|
|
expected_schema_path = manager.get_associated_schema_path(md_file)
|
|
|
|
# This would be the expected behavior for schema-generate command
|
|
assert expected_schema_path == temp_dir / "article.json"
|
|
|
|
def test_stub_generate_default_output_placement(self, manager, temp_dir):
|
|
"""Stub generation should default to placing output next to schema."""
|
|
schema_file = temp_dir / "template.json"
|
|
schema_file.write_text('''{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"type": "object",
|
|
"title": "Template Schema"
|
|
}''')
|
|
|
|
expected_md_path = manager.get_associated_markdown_path(schema_file)
|
|
|
|
# This would be the expected behavior for generate-stub command
|
|
assert expected_md_path == temp_dir / "template.md"
|
|
|
|
def test_validation_auto_discovery(self, manager, temp_dir):
|
|
"""Validation should auto-discover associated schema files."""
|
|
md_file = temp_dir / "document.md"
|
|
schema_file = temp_dir / "document.json"
|
|
|
|
md_file.write_text("# Document")
|
|
schema_file.write_text('{"type": "object"}')
|
|
|
|
# Validation command should find schema automatically
|
|
found_schema = manager.find_associated_schema(md_file)
|
|
assert found_schema == schema_file
|
|
|
|
def test_workflow_roundtrip(self, manager, temp_dir):
|
|
"""Test complete workflow: markdown → schema → stub."""
|
|
# Start with markdown
|
|
original_md = temp_dir / "workflow_test.md"
|
|
original_md.write_text("# Workflow Test\n\n## Section 1\n\nContent.")
|
|
|
|
# Generate schema (should place next to original)
|
|
schema_path = manager.get_associated_schema_path(original_md)
|
|
assert schema_path == temp_dir / "workflow_test.json"
|
|
|
|
# Create the schema (simulating schema-generate command)
|
|
schema_path.write_text('{"type": "object", "title": "Workflow Test"}')
|
|
|
|
# Generate stub from schema (should use different name to avoid conflict)
|
|
stub_path = temp_dir / "workflow_test_stub.md" # Avoiding conflict with original
|
|
|
|
# Verify the association logic works
|
|
assert manager.has_associated_schema(original_md)
|
|
assert manager.has_associated_markdown(schema_path) |