""" 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("") 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)