## Database Command Reorganization
- Add new db-prefixed commands: db-query, db-schema, db-delete, db-status
- Maintain backward compatibility with deprecation warnings for query/schema commands
- Implement lazy database initialization to reduce CLI coupling
- Add command-specific --database options for flexibility
## Legacy Compatibility Framework
- Create comprehensive legacy compatibility system in markitect/legacy_compat.py
- Support versioned legacy switches (--legacy-v39-pre) for smooth transitions
- Implement git commit binding for version tracking (Issue #39: v39-pre → 3168de4)
- Add environment-based legacy mode detection for test environments
- Create graduated deprecation warning system (DEPRECATED → LEGACY → SUNSET)
## Legacy Agent System
- Implement intelligent legacy lifecycle management agent
- Add 8 CLI commands for legacy interface management (status, analyze, migrate, cleanup, etc.)
- Create automated maintenance with usage analytics and data-driven decisions
- Provide comprehensive safety features with backup and rollback capabilities
## Test Architecture Enhancement
- Add 18 comprehensive tests for Issue #39 functionality (16 passing, 2 skipped by design)
- Configure pytest.ini with MARKITECT_LEGACY_MODE=39-pre for automatic legacy support
- Update test count to 466 total tests across 7 architectural layers
- Identify 5 legacy interface tests for future recreation without legacy dependencies
## Documentation & Roadmap Updates
- Update NEXT.md with completed Issues #39 and #40
- Document failing tests requiring recreation with pure db- commands
- Add comprehensive legacy agent documentation
- Update development priorities and capability descriptions
## Architecture Achievements
- Simplified CLI architecture with reduced coupling between commands and global state
- Created reusable legacy compatibility framework for future breaking changes
- Established systematic approach to interface deprecation and migration
- Maintained 461/466 tests passing (5 legacy interface tests flagged for recreation)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
454 lines
16 KiB
Python
454 lines
16 KiB
Python
"""
|
|
Test Output Formatting for Database Query CLI - Issue #14
|
|
|
|
This test validates the multiple output format support for database query
|
|
commands, ensuring users can get results in their preferred format.
|
|
|
|
Requirements tested:
|
|
- Table format output (human-readable)
|
|
- JSON format output (machine-readable)
|
|
- YAML format output (configuration-friendly)
|
|
- Format validation and error handling
|
|
- Consistent formatting across all commands
|
|
"""
|
|
|
|
import pytest
|
|
import json
|
|
import yaml
|
|
from click.testing import CliRunner
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
# Import the CLI module (will be extended during implementation)
|
|
from markitect.cli import cli
|
|
|
|
|
|
class TestOutputFormatting:
|
|
"""Test suite for output formatting functionality."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test fixtures."""
|
|
self.runner = CliRunner()
|
|
self.sample_data = [
|
|
{
|
|
'id': 1,
|
|
'filename': 'document1.md',
|
|
'created_at': '2025-09-25 10:00:00',
|
|
'front_matter': '{"title": "First Document", "author": "John Doe"}'
|
|
},
|
|
{
|
|
'id': 2,
|
|
'filename': 'document2.md',
|
|
'created_at': '2025-09-25 11:00:00',
|
|
'front_matter': '{"title": "Second Document", "author": "Jane Smith"}'
|
|
}
|
|
]
|
|
|
|
def test_table_format_output(self):
|
|
"""
|
|
Test that table format produces human-readable output.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.execute_query.return_value = self.sample_data
|
|
|
|
result = self.runner.invoke(cli, [
|
|
'query', 'SELECT * FROM markdown_files',
|
|
'--format', 'table'
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
# Table format should include column headers and data
|
|
assert 'filename' in result.output
|
|
assert 'document1.md' in result.output
|
|
assert 'document2.md' in result.output
|
|
|
|
# Should have some kind of visual structure (lines, spacing, etc.)
|
|
output_lines = result.output.split('\n')
|
|
assert len(output_lines) >= 3 # At least header + 2 data rows
|
|
|
|
def test_json_format_output(self):
|
|
"""
|
|
Test that JSON format produces valid JSON output.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.execute_query.return_value = self.sample_data
|
|
|
|
result = self.runner.invoke(cli, [
|
|
'query', 'SELECT * FROM markdown_files',
|
|
'--format', 'json'
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
# Output should be valid JSON
|
|
try:
|
|
parsed_json = json.loads(result.output.strip())
|
|
assert isinstance(parsed_json, list)
|
|
assert len(parsed_json) == 2
|
|
assert parsed_json[0]['filename'] == 'document1.md'
|
|
assert parsed_json[1]['filename'] == 'document2.md'
|
|
except json.JSONDecodeError:
|
|
print("DEBUG - Raw output:", repr(result.output))
|
|
print("DEBUG - Exit code:", result.exit_code)
|
|
print("DEBUG - Exception:", result.exception)
|
|
pytest.fail("Output should be valid JSON")
|
|
|
|
def test_yaml_format_output(self):
|
|
"""
|
|
Test that YAML format produces valid YAML output.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.execute_query.return_value = self.sample_data
|
|
|
|
result = self.runner.invoke(cli, [
|
|
'query', 'SELECT * FROM markdown_files',
|
|
'--format', 'yaml'
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
# Output should be valid YAML
|
|
try:
|
|
parsed_yaml = yaml.safe_load(result.output)
|
|
assert isinstance(parsed_yaml, list)
|
|
assert len(parsed_yaml) == 2
|
|
assert parsed_yaml[0]['filename'] == 'document1.md'
|
|
assert parsed_yaml[1]['filename'] == 'document2.md'
|
|
except yaml.YAMLError:
|
|
pytest.fail("Output should be valid YAML")
|
|
|
|
def test_default_format_is_table(self):
|
|
"""
|
|
Test that default output format is table when not specified.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.execute_query.return_value = self.sample_data
|
|
|
|
# Without specifying format
|
|
result = self.runner.invoke(cli, ['query', 'SELECT * FROM markdown_files'])
|
|
|
|
if result.exit_code != 0:
|
|
print("Command output:", result.output)
|
|
print("Command exception:", result.exception)
|
|
assert result.exit_code == 0
|
|
# Should look like table format (not JSON or YAML)
|
|
assert not result.output.strip().startswith('[') # Not JSON array
|
|
assert not result.output.strip().startswith('-') # Not YAML array
|
|
|
|
def test_invalid_format_handling(self):
|
|
"""
|
|
Test that invalid format specifications are handled gracefully.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
result = self.runner.invoke(cli, [
|
|
'query', 'SELECT * FROM markdown_files',
|
|
'--format', 'invalid_format'
|
|
])
|
|
|
|
# Should either use default format or show error
|
|
assert result.exit_code != 0 or 'invalid' in result.output.lower()
|
|
|
|
def test_empty_result_formatting(self):
|
|
"""
|
|
Test that empty results are formatted correctly in all formats.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.execute_query.return_value = []
|
|
|
|
# Test JSON format with empty results
|
|
result = self.runner.invoke(cli, [
|
|
'query', 'SELECT * FROM markdown_files WHERE id = -1',
|
|
'--format', 'json'
|
|
])
|
|
assert result.exit_code == 0
|
|
try:
|
|
parsed = json.loads(result.output.strip())
|
|
assert parsed == []
|
|
except json.JSONDecodeError:
|
|
# Might show "No results" message instead
|
|
assert 'no results' in result.output.lower()
|
|
|
|
# Test YAML format with empty results
|
|
result = self.runner.invoke(cli, [
|
|
'query', 'SELECT * FROM markdown_files WHERE id = -1',
|
|
'--format', 'yaml'
|
|
])
|
|
assert result.exit_code == 0
|
|
|
|
# Test table format with empty results
|
|
result = self.runner.invoke(cli, [
|
|
'query', 'SELECT * FROM markdown_files WHERE id = -1',
|
|
'--format', 'table'
|
|
])
|
|
assert result.exit_code == 0
|
|
|
|
|
|
class TestSchemaFormatting:
|
|
"""Test suite for schema command output formatting."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test fixtures."""
|
|
self.runner = CliRunner()
|
|
self.schema_data = {
|
|
'markdown_files': {
|
|
'columns': [
|
|
{'name': 'id', 'type': 'INTEGER', 'primary_key': True, 'nullable': False},
|
|
{'name': 'filename', 'type': 'TEXT', 'primary_key': False, 'nullable': False},
|
|
{'name': 'front_matter', 'type': 'TEXT', 'primary_key': False, 'nullable': True},
|
|
{'name': 'content', 'type': 'TEXT', 'primary_key': False, 'nullable': True},
|
|
{'name': 'created_at', 'type': 'TIMESTAMP', 'primary_key': False, 'nullable': True}
|
|
]
|
|
}
|
|
}
|
|
|
|
def test_schema_table_format(self):
|
|
"""
|
|
Test that schema command produces readable table format.
|
|
|
|
Issue #14: Schema inspection commands
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.get_schema.return_value = self.schema_data
|
|
|
|
result = self.runner.invoke(cli, ['schema', '--format', 'table'])
|
|
|
|
assert result.exit_code == 0
|
|
assert 'markdown_files' in result.output
|
|
assert 'filename' in result.output
|
|
assert 'INTEGER' in result.output
|
|
assert 'TEXT' in result.output
|
|
|
|
def test_schema_json_format(self):
|
|
"""
|
|
Test that schema command produces valid JSON format.
|
|
|
|
Issue #14: Schema inspection commands
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.get_schema.return_value = self.schema_data
|
|
|
|
result = self.runner.invoke(cli, ['schema', '--format', 'json'])
|
|
|
|
assert result.exit_code == 0
|
|
try:
|
|
parsed = json.loads(result.output.strip())
|
|
assert 'markdown_files' in parsed
|
|
assert 'columns' in parsed['markdown_files']
|
|
except json.JSONDecodeError:
|
|
pytest.fail("Schema JSON output should be valid JSON")
|
|
|
|
def test_schema_yaml_format(self):
|
|
"""
|
|
Test that schema command produces valid YAML format.
|
|
|
|
Issue #14: Schema inspection commands
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.get_schema.return_value = self.schema_data
|
|
|
|
result = self.runner.invoke(cli, ['schema', '--format', 'yaml'])
|
|
|
|
assert result.exit_code == 0
|
|
try:
|
|
parsed = yaml.safe_load(result.output)
|
|
assert 'markdown_files' in parsed
|
|
assert 'columns' in parsed['markdown_files']
|
|
except yaml.YAMLError:
|
|
pytest.fail("Schema YAML output should be valid YAML")
|
|
|
|
|
|
class TestMetadataFormatting:
|
|
"""Test suite for metadata command output formatting."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test fixtures."""
|
|
self.runner = CliRunner()
|
|
self.metadata = {
|
|
'id': 1,
|
|
'filename': 'test.md',
|
|
'front_matter': '{"title": "Test Document", "author": "Test Author", "tags": ["test", "demo"]}',
|
|
'content': '# Test Document\n\nThis is test content.',
|
|
'created_at': '2025-09-25 12:00:00'
|
|
}
|
|
|
|
def test_metadata_table_format(self):
|
|
"""
|
|
Test that metadata command produces readable table format.
|
|
|
|
Issue #14: Metadata display functionality
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.get_markdown_file.return_value = self.metadata
|
|
|
|
result = self.runner.invoke(cli, ['metadata', 'test.md', '--format', 'table'])
|
|
|
|
assert result.exit_code == 0
|
|
assert 'test.md' in result.output
|
|
assert 'Test Document' in result.output
|
|
assert 'Test Author' in result.output
|
|
|
|
def test_metadata_json_format(self):
|
|
"""
|
|
Test that metadata command produces valid JSON format.
|
|
|
|
Issue #14: Metadata display functionality
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.get_markdown_file.return_value = self.metadata
|
|
|
|
result = self.runner.invoke(cli, ['metadata', 'test.md', '--format', 'json'])
|
|
|
|
assert result.exit_code == 0
|
|
try:
|
|
parsed = json.loads(result.output.strip())
|
|
assert parsed['filename'] == 'test.md'
|
|
assert 'front_matter' in parsed
|
|
except json.JSONDecodeError:
|
|
pytest.fail("Metadata JSON output should be valid JSON")
|
|
|
|
def test_metadata_yaml_format(self):
|
|
"""
|
|
Test that metadata command produces valid YAML format.
|
|
|
|
Issue #14: Metadata display functionality
|
|
"""
|
|
with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
|
|
mock_db_instance = MagicMock()
|
|
mock_db_mgr.return_value = mock_db_instance
|
|
mock_db_instance.get_markdown_file.return_value = self.metadata
|
|
|
|
result = self.runner.invoke(cli, ['metadata', 'test.md', '--format', 'yaml'])
|
|
|
|
assert result.exit_code == 0
|
|
try:
|
|
parsed = yaml.safe_load(result.output)
|
|
assert parsed['filename'] == 'test.md'
|
|
assert 'front_matter' in parsed
|
|
except yaml.YAMLError:
|
|
pytest.fail("Metadata YAML output should be valid YAML")
|
|
|
|
|
|
class TestFormattingConsistency:
|
|
"""Test suite for formatting consistency across commands."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test fixtures."""
|
|
self.runner = CliRunner()
|
|
|
|
def test_format_option_consistency(self):
|
|
"""
|
|
Test that --format option works consistently across all commands.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
commands = [
|
|
['query', 'SELECT COUNT(*) FROM markdown_files'],
|
|
['schema'],
|
|
['metadata', 'test.md']
|
|
]
|
|
|
|
formats = ['table', 'json', 'yaml']
|
|
|
|
for command in commands:
|
|
for fmt in formats:
|
|
# Test that all commands accept the format option
|
|
result = self.runner.invoke(cli, command + ['--format', fmt, '--help'])
|
|
# Should not error on the format option itself
|
|
assert 'unrecognized arguments' not in result.output.lower()
|
|
|
|
def test_format_error_consistency(self):
|
|
"""
|
|
Test that format errors are handled consistently across commands.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
commands = [
|
|
['query', 'SELECT COUNT(*) FROM markdown_files'],
|
|
['schema'],
|
|
['metadata', 'test.md']
|
|
]
|
|
|
|
for command in commands:
|
|
result = self.runner.invoke(cli, command + ['--format', 'invalid'])
|
|
# Should either reject invalid format or use default
|
|
# Consistent error handling across all commands
|
|
assert result.exit_code == 0 or 'invalid' in result.output.lower()
|
|
|
|
|
|
class TestFormattingUtilities:
|
|
"""Test suite for formatting utility functions."""
|
|
|
|
def test_format_table_utility(self):
|
|
"""
|
|
Test table formatting utility function.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
# This test will validate the internal table formatting function
|
|
# once it's implemented in the CLI module
|
|
|
|
sample_data = [
|
|
{'name': 'file1.md', 'size': 100},
|
|
{'name': 'file2.md', 'size': 200}
|
|
]
|
|
|
|
# Test that we can format data as a table
|
|
# The actual implementation will depend on the formatting utility chosen
|
|
assert isinstance(sample_data, list) # Basic validation for now
|
|
|
|
def test_format_json_utility(self):
|
|
"""
|
|
Test JSON formatting utility function.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
sample_data = [{'name': 'test.md', 'id': 1}]
|
|
|
|
# Should be able to serialize to JSON
|
|
json_output = json.dumps(sample_data, indent=2)
|
|
assert 'test.md' in json_output
|
|
assert isinstance(json.loads(json_output), list)
|
|
|
|
def test_format_yaml_utility(self):
|
|
"""
|
|
Test YAML formatting utility function.
|
|
|
|
Issue #14: Multiple output format support
|
|
"""
|
|
sample_data = [{'name': 'test.md', 'id': 1}]
|
|
|
|
# Should be able to serialize to YAML
|
|
yaml_output = yaml.dump(sample_data, default_flow_style=False)
|
|
assert 'test.md' in yaml_output
|
|
assert isinstance(yaml.safe_load(yaml_output), list) |