Files
markitect-main/tests/test_issue_7_schema_validation.py
tegwick 1358ca17ec
Some checks failed
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 / code-quality (push) Has been cancelled
Test Suite / security-scan (push) Has been cancelled
Test Suite / test-summary (push) Has been cancelled
refactor: Remove circular test dependencies and meta-testing anti-patterns
Clean up test infrastructure by removing problematic tests that create
circular dependencies and execute the test suite from within tests.

Key removals:
- Delete test_issue_57_test_efficiency_improvements.py entirely (12 tests)
  - Contained tests that ran `make test-tdd`, `make test-status` etc.
  - Created circular dependencies where tests execute the entire test suite
  - Violated separation of concerns between testing and test infrastructure

- Remove self-execution blocks from 11 test files
  - Eliminated `if __name__ == '__main__': pytest.main([__file__, '-v'])` patterns
  - Prevents confusion and potential circular execution paths
  - Test files should be run via pytest, not as standalone scripts

Test Infrastructure Improvements:
- Reduced test count from 701 to 689 tests (removed 12 problematic tests)
- Eliminated subprocess calls to `make test-*` commands from within tests
- Removed `pytest.main()` calls that could cause circular execution
- Maintained clean separation between test infrastructure and actual tests

Impact:
- No more tests testing tests (circular dependency elimination)
- Cleaner test execution without subprocess complexity
- Proper test isolation and independence
- Faster and more reliable test runs

The proper way to test infrastructure is to test the underlying functions
directly, not to execute the entire test suite from within a test.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 21:05:36 +02:00

375 lines
12 KiB
Python

"""
Test for Issue #7: Validate a Markdown File Against a Schema.
Tests the ability to validate markdown documents against JSON schemas for
arc42 architecture documentation compliance checking - critical for intelligent
document analysis and plan-actual comparison capabilities.
"""
import json
import pytest
from pathlib import Path
from tempfile import NamedTemporaryFile
from markitect.schema_validator import SchemaValidator
from markitect.schema_generator import SchemaGenerator
from markitect.exceptions import FileNotFoundError, SchemaValidationError, InvalidSchemaError
class TestIssue7SchemaValidation:
"""Test suite for schema validation of markdown files."""
def setup_method(self):
"""Set up test environment."""
self.schema_validator = SchemaValidator()
self.schema_generator = SchemaGenerator()
def teardown_method(self):
"""Clean up after tests."""
pass
def test_validate_markdown_against_matching_schema_returns_true(self):
"""
ISSUE #7: Test markdown validation against matching schema returns True.
Verifies that a markdown document that matches its generated schema
returns True for compliance - essential for arc42 document validation.
"""
# Arrange - Create markdown with known structure
markdown_content = """# Architecture Document
This document describes the system architecture.
## Overview
The system consists of several components:
- Component A
- Component B
## Details
More detailed information here.
"""
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write(markdown_content)
temp_file = Path(f.name)
try:
# Generate schema from the same content
schema = self.schema_generator.generate_schema_from_file(temp_file)
# Act - Validate the document against its own schema
is_valid = self.schema_validator.validate_file_against_schema(temp_file, schema)
# Assert - Document should match its own schema
assert is_valid is True
finally:
temp_file.unlink()
def test_validate_markdown_against_non_matching_schema_returns_false(self):
"""
ISSUE #7: Test markdown validation against non-matching schema returns False.
Verifies that a markdown document that doesn't match the schema structure
returns False - critical for detecting arc42 compliance violations.
"""
# Arrange - Create markdown document
markdown_content = """# Single Heading
Just one paragraph of content.
"""
# Create schema that expects different structure (multiple headings)
expected_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"headings": {
"type": "object",
"properties": {
"level_1": {
"type": "array",
"minItems": 2, # Expect at least 2 level-1 headings
"maxItems": 2
},
"level_2": {
"type": "array",
"minItems": 1 # Expect at least 1 level-2 heading
}
},
"required": ["level_1", "level_2"]
}
},
"required": ["headings"]
}
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write(markdown_content)
temp_file = Path(f.name)
try:
# Act - Validate against non-matching schema
is_valid = self.schema_validator.validate_file_against_schema(temp_file, expected_schema)
# Assert - Document should not match the schema
assert is_valid is False
finally:
temp_file.unlink()
def test_validate_markdown_with_depth_limited_schema(self):
"""
ISSUE #7: Test validation with depth-limited schemas for arc42 sections.
Ensures validation works correctly with depth-limited schemas,
essential for arc42 section-specific compliance checking.
"""
# Arrange - Markdown with multiple heading levels
markdown_content = """# Main Architecture
## System Overview
Content here.
### Implementation Details
Deep content.
#### Technical Notes
Very deep content.
"""
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write(markdown_content)
temp_file = Path(f.name)
try:
# Generate schema with depth limit of 2
schema_depth_2 = self.schema_generator.generate_schema_from_file(temp_file, max_depth=2)
# Act - Validate against depth-limited schema
is_valid = self.schema_validator.validate_file_against_schema(temp_file, schema_depth_2)
# Assert - Document should match depth-limited schema
assert is_valid is True
finally:
temp_file.unlink()
def test_validate_file_not_found_raises_exception(self):
"""
ISSUE #7: Test error handling when markdown file doesn't exist.
"""
# Arrange - Non-existent file and valid schema
non_existent_file = Path("/tmp/non_existent_file.md")
valid_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object"
}
# Act & Assert - Should raise FileNotFoundError
with pytest.raises(FileNotFoundError):
self.schema_validator.validate_file_against_schema(non_existent_file, valid_schema)
def test_validate_with_invalid_schema_raises_exception(self):
"""
ISSUE #7: Test error handling for invalid JSON schema.
"""
# Arrange - Valid markdown file and invalid schema
markdown_content = "# Test\n\nContent."
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write(markdown_content)
temp_file = Path(f.name)
invalid_schema = {
# Missing required $schema and type fields
"properties": {}
}
try:
# Act & Assert - Should raise InvalidSchemaError
with pytest.raises(InvalidSchemaError):
self.schema_validator.validate_file_against_schema(temp_file, invalid_schema)
finally:
temp_file.unlink()
def test_validate_markdown_with_complex_schema_requirements(self):
"""
ISSUE #7: Test validation against complex schema requirements.
Validates comprehensive schema rules including specific content
requirements, essential for arc42 template compliance.
"""
# Arrange - Create markdown that should match complex requirements
markdown_content = """# Architecture Decision Record
## Status
Accepted
## Context
This document describes architectural decisions.
## Decision
We decided to use microservices architecture.
## Consequences
- Benefit: Better scalability
- Cost: Increased complexity
"""
# Create schema with specific structural requirements
adr_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Architecture Decision Record Schema",
"properties": {
"headings": {
"type": "object",
"properties": {
"level_1": {
"type": "array",
"minItems": 1,
"maxItems": 1 # Exactly one main title
},
"level_2": {
"type": "array",
"minItems": 4, # Expect Status, Context, Decision, Consequences
"maxItems": 4
}
},
"required": ["level_1", "level_2"]
},
"paragraphs": {
"type": "array",
"minItems": 4 # Expect content under each section
},
"lists": {
"type": "array",
"minItems": 1 # Expect consequences list
}
},
"required": ["headings", "paragraphs", "lists"]
}
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write(markdown_content)
temp_file = Path(f.name)
try:
# Act - Validate against ADR schema
is_valid = self.schema_validator.validate_file_against_schema(temp_file, adr_schema)
# Assert - Document should match ADR schema requirements
assert is_valid is True
finally:
temp_file.unlink()
def test_validate_returns_false_for_missing_required_elements(self):
"""
ISSUE #7: Test validation returns False when required elements are missing.
Ensures strict compliance checking for arc42 architectural templates.
"""
# Arrange - Incomplete markdown missing required elements
incomplete_markdown = """# Incomplete Document
This document is missing required sections.
"""
# Schema requiring multiple sections
strict_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"headings": {
"type": "object",
"properties": {
"level_1": {
"type": "array",
"minItems": 1
},
"level_2": {
"type": "array",
"minItems": 3 # Require at least 3 level-2 headings
}
},
"required": ["level_1", "level_2"]
},
"lists": {
"type": "array",
"minItems": 2 # Require at least 2 lists
}
},
"required": ["headings", "lists"]
}
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write(incomplete_markdown)
temp_file = Path(f.name)
try:
# Act - Validate incomplete document
is_valid = self.schema_validator.validate_file_against_schema(temp_file, strict_schema)
# Assert - Should return False due to missing required elements
assert is_valid is False
finally:
temp_file.unlink()
def test_validate_with_schema_from_json_string(self):
"""
ISSUE #7: Test validation using schema provided as JSON string.
Supports flexible schema input for CLI and API integration.
"""
# Arrange - Simple markdown and schema as JSON string
markdown_content = """# Test Document
Simple test content.
"""
schema_json = """{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"headings": {
"type": "object",
"properties": {
"level_1": {
"type": "array",
"minItems": 1,
"maxItems": 1
}
}
}
}
}"""
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write(markdown_content)
temp_file = Path(f.name)
try:
# Act - Validate using JSON string schema
is_valid = self.schema_validator.validate_file_against_schema_string(temp_file, schema_json)
# Assert - Should successfully validate
assert is_valid is True
finally:
temp_file.unlink()