""" 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, [ 'db-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_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, ['db-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, [ 'db-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() 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, ['db-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_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, ['db-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 TestDbDataFormatting: """Test suite for db-data 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_db_data_table_format(self): """ Test that db-data command produces readable table format. Issue #14: Metadata display functionality (updated for Issue #38) """ 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, ['db-data', '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_db_data_json_format(self): """ Test that db-data command produces valid JSON format. Issue #14: Metadata display functionality (updated for Issue #38) """ 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, ['db-data', '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_db_data_yaml_format(self): """ Test that db-data command produces valid YAML format. Issue #14: Metadata display functionality (updated for Issue #38) """ 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, ['db-data', '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 = [ ['db-query', 'SELECT COUNT(*) FROM markdown_files'], ['db-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 = [ ['db-query', 'SELECT COUNT(*) FROM markdown_files'], ['db-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)