markitect-main/tests/test_issue_140_roundtrip_simplified.py

371 lines
12 KiB
Python
Raw Normal View History

feat: complete Issue #140 roundtrip compatibility analysis Comprehensive testing and analysis of md-explode ↔ md-implode roundtrip functionality: ## Test Infrastructure Created - 77 comprehensive tests covering all roundtrip scenarios - 4 simplified tests for behavior analysis and documentation - Automated content preservation analysis and reporting - Error handling and edge case validation ## Key Findings - ✅ Both commands execute successfully as individual tools - ✅ Complete functionality for unidirectional use cases - ⚠️ Content duplication prevents lossless bidirectional roundtrips - 📊 0% perfect match rate due to overlapping file architecture ## Analysis Results - md-explode creates overlapping content in hierarchical files - md-implode processes all files independently, causing duplication - Content growth factor: 1.5-2.7x in typical roundtrip scenarios - Root cause: Architectural incompatibility between commands ## Deliverables - Comprehensive roundtrip test suite (test_issue_140_roundtrip.py) - Simplified behavior analysis tests (test_issue_140_roundtrip_simplified.py) - Detailed analysis report (ISSUE_140_ROUNDTRIP_ANALYSIS.md) - Usage guidelines and recommendations for users ## Recommendations - Document limitations in command help text - Provide clear usage guidelines for unidirectional workflows - Consider architectural improvements for future versions Commands work excellently individually but require careful usage for roundtrip scenarios. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-07 23:11:33 +02:00
"""
Simplified roundtrip tests for Issue #140: md-explode and md-implode compatibility.
Tests the actual behavior of explodeimplode and implodeexplode roundtrips
to document current functionality and identify any issues.
"""
import pytest
import tempfile
import shutil
import subprocess
from pathlib import Path
from textwrap import dedent
class TestActualRoundtripBehavior:
"""Test actual roundtrip behavior to document current functionality."""
def setup_method(self):
"""Set up temporary directory for each test."""
self.temp_dir = Path(tempfile.mkdtemp())
def teardown_method(self):
"""Clean up temporary directory after each test."""
if self.temp_dir.exists():
shutil.rmtree(self.temp_dir)
def run_markitect_command(self, args, check=True):
"""Helper to run markitect commands."""
cmd = ["python", "-m", "markitect.cli"] + args
result = subprocess.run(
cmd,
cwd="/home/worsch/markitect-main",
feat: complete Issue #140 roundtrip compatibility analysis Comprehensive testing and analysis of md-explode ↔ md-implode roundtrip functionality: ## Test Infrastructure Created - 77 comprehensive tests covering all roundtrip scenarios - 4 simplified tests for behavior analysis and documentation - Automated content preservation analysis and reporting - Error handling and edge case validation ## Key Findings - ✅ Both commands execute successfully as individual tools - ✅ Complete functionality for unidirectional use cases - ⚠️ Content duplication prevents lossless bidirectional roundtrips - 📊 0% perfect match rate due to overlapping file architecture ## Analysis Results - md-explode creates overlapping content in hierarchical files - md-implode processes all files independently, causing duplication - Content growth factor: 1.5-2.7x in typical roundtrip scenarios - Root cause: Architectural incompatibility between commands ## Deliverables - Comprehensive roundtrip test suite (test_issue_140_roundtrip.py) - Simplified behavior analysis tests (test_issue_140_roundtrip_simplified.py) - Detailed analysis report (ISSUE_140_ROUNDTRIP_ANALYSIS.md) - Usage guidelines and recommendations for users ## Recommendations - Document limitations in command help text - Provide clear usage guidelines for unidirectional workflows - Consider architectural improvements for future versions Commands work excellently individually but require careful usage for roundtrip scenarios. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-07 23:11:33 +02:00
capture_output=True,
text=True
)
if check and result.returncode != 0:
pytest.fail(f"Command failed: {' '.join(args)}\nStdout: {result.stdout}\nStderr: {result.stderr}")
return result
def test_explode_then_implode_basic(self):
"""Test basic explode→implode sequence and document behavior."""
# Create a simple markdown file
original_content = dedent("""
# Test Document
Introduction content.
## Chapter 1
Chapter 1 content.
### Section 1.1
Section 1.1 content.
## Chapter 2
Chapter 2 content.
""").strip()
original_file = self.temp_dir / "test.md"
original_file.write_text(original_content)
# Step 1: Explode to directory
exploded_dir = self.temp_dir / "test_exploded"
result = self.run_markitect_command([
"md-explode", str(original_file),
"--output-dir", str(exploded_dir),
"--verbose"
])
assert result.returncode == 0
assert exploded_dir.exists()
# Document what explode actually creates
files_created = []
for md_file in exploded_dir.rglob("*.md"):
files_created.append(str(md_file.relative_to(exploded_dir)))
print(f"Files created by md-explode: {files_created}")
# Step 2: Implode back to markdown
imploded_file = self.temp_dir / "imploded.md"
result = self.run_markitect_command([
"md-implode", str(exploded_dir),
"--output", str(imploded_file),
"--verbose"
])
assert result.returncode == 0
assert imploded_file.exists()
# Document the result
imploded_content = imploded_file.read_text()
print(f"Original content length: {len(original_content)}")
print(f"Imploded content length: {len(imploded_content)}")
# Basic verification - key headings should be present
assert "# Test Document" in imploded_content
assert "## Chapter 1" in imploded_content
assert "### Section 1.1" in imploded_content
assert "## Chapter 2" in imploded_content
# Save both for comparison
comparison_file = self.temp_dir / "comparison.txt"
comparison_content = f"""
ORIGINAL CONTENT:
{'-' * 50}
{original_content}
IMPLODED CONTENT:
{'-' * 50}
{imploded_content}
CONTENT MATCH: {original_content.strip() == imploded_content.strip()}
"""
comparison_file.write_text(comparison_content)
print(f"Comparison saved to: {comparison_file}")
def test_directory_implode_then_explode(self):
"""Test directory→markdown→directory sequence."""
# Create a directory structure manually
base_dir = self.temp_dir / "manual_structure"
base_dir.mkdir()
# Create files
(base_dir / "intro.md").write_text("# Manual Structure\n\nIntroduction content.")
chapter_dir = base_dir / "chapter_1"
chapter_dir.mkdir()
(chapter_dir / "index.md").write_text("## Chapter 1\n\nChapter content.")
(chapter_dir / "section_1.md").write_text("### Section 1\n\nSection content.")
# Step 1: Implode directory to markdown
imploded_file = self.temp_dir / "manual_imploded.md"
result = self.run_markitect_command([
"md-implode", str(base_dir),
"--output", str(imploded_file),
"--verbose"
])
assert result.returncode == 0
imploded_content = imploded_file.read_text()
print(f"Directory imploded to {len(imploded_content)} characters")
# Step 2: Explode back to directory
re_exploded_dir = self.temp_dir / "re_exploded"
result = self.run_markitect_command([
"md-explode", str(imploded_file),
"--output-dir", str(re_exploded_dir),
"--verbose"
])
assert result.returncode == 0
# Document the results
original_files = list(base_dir.rglob("*.md"))
re_exploded_files = list(re_exploded_dir.rglob("*.md"))
print(f"Original files: {len(original_files)}")
print(f"Re-exploded files: {len(re_exploded_files)}")
# Basic verification
assert len(re_exploded_files) > 0
# Check that key content is preserved
all_re_exploded_content = ""
for file in re_exploded_files:
all_re_exploded_content += file.read_text() + "\n"
assert "# Manual Structure" in all_re_exploded_content
assert "## Chapter 1" in all_re_exploded_content
assert "### Section 1" in all_re_exploded_content
def test_content_preservation_analysis(self):
"""Analyze what content is preserved and what changes in roundtrips."""
# Test various content types
test_cases = [
{
"name": "simple_hierarchy",
"content": dedent("""
# Main Title
Introduction.
## Section
Section content.
""").strip()
},
{
"name": "deep_hierarchy",
"content": dedent("""
# Level 1
Content 1.
## Level 2
Content 2.
### Level 3
Content 3.
#### Level 4
Content 4.
""").strip()
},
{
"name": "multiple_sections",
"content": dedent("""
# Document
Intro.
## Part 1
Part 1 content.
## Part 2
Part 2 content.
## Part 3
Part 3 content.
""").strip()
}
]
results = []
for test_case in test_cases:
# Create original file
original_file = self.temp_dir / f"{test_case['name']}.md"
original_file.write_text(test_case['content'])
# Explode → Implode
exploded_dir = self.temp_dir / f"{test_case['name']}_exploded"
self.run_markitect_command([
"md-explode", str(original_file),
"--output-dir", str(exploded_dir)
])
imploded_file = self.temp_dir / f"{test_case['name']}_imploded.md"
self.run_markitect_command([
"md-implode", str(exploded_dir),
"--output", str(imploded_file)
])
imploded_content = imploded_file.read_text()
# Analyze results
result = {
"test_case": test_case['name'],
"original_length": len(test_case['content']),
"imploded_length": len(imploded_content),
"content_match": test_case['content'].strip() == imploded_content.strip(),
"files_created": len(list(exploded_dir.rglob("*.md")))
}
results.append(result)
print(f"Test case '{test_case['name']}': {result}")
# Summary
total_tests = len(results)
perfect_matches = sum(1 for r in results if r['content_match'])
print(f"\nSUMMARY:")
print(f"Total tests: {total_tests}")
print(f"Perfect matches: {perfect_matches}")
print(f"Success rate: {perfect_matches/total_tests:.1%}")
# At least some basic functionality should work
assert total_tests > 0
assert any(len(list((self.temp_dir / f"{r['test_case']}_exploded").rglob("*.md"))) > 0 for r in results)
def test_roundtrip_functionality_status(self):
"""Document the current status of roundtrip functionality."""
# Test a representative case
content = dedent("""
# Test Document
Introduction paragraph.
## Chapter One
First chapter content.
### Section A
Section A details.
### Section B
Section B details.
## Chapter Two
Second chapter content.
""").strip()
original_file = self.temp_dir / "status_test.md"
original_file.write_text(content)
# Test explode
exploded_dir = self.temp_dir / "status_exploded"
explode_result = self.run_markitect_command([
"md-explode", str(original_file),
"--output-dir", str(exploded_dir),
"--verbose"
], check=False)
explode_success = explode_result.returncode == 0
files_created = len(list(exploded_dir.rglob("*.md"))) if exploded_dir.exists() else 0
# Test implode if explode succeeded
implode_success = False
content_match = False
if explode_success:
imploded_file = self.temp_dir / "status_imploded.md"
implode_result = self.run_markitect_command([
"md-implode", str(exploded_dir),
"--output", str(imploded_file),
"--verbose"
], check=False)
implode_success = implode_result.returncode == 0
if implode_success:
imploded_content = imploded_file.read_text().strip()
content_match = content == imploded_content
# Create status report
status_report = f"""
ROUNDTRIP FUNCTIONALITY STATUS REPORT
=====================================
Original content: {len(content)} characters
Explode success: {explode_success}
Files created: {files_created}
Implode success: {implode_success}
Perfect content match: {content_match}
OVERALL STATUS: {'✅ WORKING' if explode_success and implode_success else '⚠️ ISSUES DETECTED'}
RECOMMENDATIONS:
{'- Roundtrip functionality is operational' if content_match else '- Content duplication or loss detected in roundtrip'}
{'- Both commands execute successfully' if explode_success and implode_success else '- Command execution issues detected'}
- Further testing recommended for production use
- Document any known limitations for users
"""
print(status_report)
status_file = self.temp_dir / "roundtrip_status_report.txt"
status_file.write_text(status_report)
# Basic assertions for functionality
assert explode_success, "md-explode should execute successfully"
assert implode_success, "md-implode should execute successfully"
assert files_created > 0, "md-explode should create files"
if __name__ == "__main__":
pytest.main([__file__, "-v", "-s"]) # -s to show print statements