feat: Implement comprehensive Testing Architecture Enhancement
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
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
Establishes robust testing framework with clean architecture patterns: ## Phase 1: Test Infrastructure Foundation - Global test configuration with pytest.ini and conftest.py - Isolated test workspaces and environment management - Comprehensive fixture library for all test types - Test requirements and dependency management ## Phase 2: Advanced Testing Patterns - Test builders using builder pattern for domain objects - Mock factories for repositories, services, and configs - API response builders for external system simulation - Enhanced unit tests with proper mocking and isolation ## Phase 3: Test Performance and Quality - Performance testing framework with benchmarks - Memory usage monitoring and leak detection - Custom assertions for domain-specific validation - Parametrized testing for comprehensive coverage ## Phase 4: CI/CD Integration - GitHub Actions workflow for automated testing - Multi-stage testing: unit → integration → e2e → performance - Code quality checks with flake8, mypy, black, isort - Security scanning with safety and bandit ## Testing Architecture Benefits ✅ 100+ new test infrastructure components ✅ Standardized test organization (unit/integration/e2e) ✅ Mock-based testing with no external dependencies ✅ Performance regression detection ✅ Comprehensive fixture library ✅ CI/CD pipeline with quality gates The testing framework supports the domain logic separation and provides a solid foundation for maintaining high code quality as the system evolves. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
302
tests/fixtures/markdown_samples.py
vendored
Normal file
302
tests/fixtures/markdown_samples.py
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
"""
|
||||
Markdown document builders and sample generators for testing.
|
||||
"""
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
import random
|
||||
import string
|
||||
|
||||
|
||||
class MarkdownDocumentBuilder:
|
||||
"""Builder pattern for creating test markdown documents."""
|
||||
|
||||
def __init__(self):
|
||||
self.content_parts: List[str] = []
|
||||
self.metadata: Dict[str, str] = {}
|
||||
|
||||
def with_heading(self, text: str, level: int = 1) -> "MarkdownDocumentBuilder":
|
||||
"""Add a heading to the document."""
|
||||
if level < 1 or level > 6:
|
||||
raise ValueError("Heading level must be between 1 and 6")
|
||||
|
||||
heading_marker = "#" * level
|
||||
self.content_parts.append(f"{heading_marker} {text}")
|
||||
return self
|
||||
|
||||
def with_paragraph(self, text: str) -> "MarkdownDocumentBuilder":
|
||||
"""Add a paragraph to the document."""
|
||||
self.content_parts.append(text)
|
||||
return self
|
||||
|
||||
def with_list(self, items: List[str], ordered: bool = False) -> "MarkdownDocumentBuilder":
|
||||
"""Add a list to the document."""
|
||||
if ordered:
|
||||
list_items = [f"{i+1}. {item}" for i, item in enumerate(items)]
|
||||
else:
|
||||
list_items = [f"- {item}" for item in items]
|
||||
|
||||
self.content_parts.append("\n".join(list_items))
|
||||
return self
|
||||
|
||||
def with_code_block(self, code: str, language: str = "python") -> "MarkdownDocumentBuilder":
|
||||
"""Add a code block to the document."""
|
||||
self.content_parts.append(f"```{language}\n{code}\n```")
|
||||
return self
|
||||
|
||||
def with_link(self, text: str, url: str) -> "MarkdownDocumentBuilder":
|
||||
"""Add a link to the document."""
|
||||
self.content_parts.append(f"[{text}]({url})")
|
||||
return self
|
||||
|
||||
def with_metadata(self, key: str, value: str) -> "MarkdownDocumentBuilder":
|
||||
"""Add metadata (front matter) to the document."""
|
||||
self.metadata[key] = value
|
||||
return self
|
||||
|
||||
def with_table(self, headers: List[str], rows: List[List[str]]) -> "MarkdownDocumentBuilder":
|
||||
"""Add a table to the document."""
|
||||
table_lines = []
|
||||
|
||||
# Header row
|
||||
table_lines.append("| " + " | ".join(headers) + " |")
|
||||
|
||||
# Separator row
|
||||
table_lines.append("| " + " | ".join(["-" * len(header) for header in headers]) + " |")
|
||||
|
||||
# Data rows
|
||||
for row in rows:
|
||||
table_lines.append("| " + " | ".join(row) + " |")
|
||||
|
||||
self.content_parts.append("\n".join(table_lines))
|
||||
return self
|
||||
|
||||
def with_blockquote(self, text: str) -> "MarkdownDocumentBuilder":
|
||||
"""Add a blockquote to the document."""
|
||||
quote_lines = [f"> {line}" for line in text.split("\n")]
|
||||
self.content_parts.append("\n".join(quote_lines))
|
||||
return self
|
||||
|
||||
def build(self) -> str:
|
||||
"""Build the final markdown document."""
|
||||
content = "\n\n".join(self.content_parts)
|
||||
|
||||
if self.metadata:
|
||||
metadata_lines = [f"{k}: {v}" for k, v in self.metadata.items()]
|
||||
content = "---\n" + "\n".join(metadata_lines) + "\n---\n\n" + content
|
||||
|
||||
return content
|
||||
|
||||
|
||||
class LargeMarkdownGenerator:
|
||||
"""Generator for creating large markdown documents for performance testing."""
|
||||
|
||||
def __init__(self, seed: Optional[int] = None):
|
||||
self.random = random.Random(seed)
|
||||
|
||||
def generate_document(self, size: str = "1mb") -> str:
|
||||
"""Generate a large markdown document of specified size."""
|
||||
size_bytes = self._parse_size(size)
|
||||
builder = MarkdownDocumentBuilder()
|
||||
|
||||
# Add metadata
|
||||
builder.with_metadata("title", "Large Test Document")
|
||||
builder.with_metadata("author", "Test Generator")
|
||||
builder.with_metadata("size", size)
|
||||
|
||||
# Add content until we reach target size
|
||||
current_size = 0
|
||||
section_count = 0
|
||||
|
||||
while current_size < size_bytes:
|
||||
section_count += 1
|
||||
section_title = f"Section {section_count}"
|
||||
builder.with_heading(section_title, level=2)
|
||||
|
||||
# Add paragraphs
|
||||
for _ in range(self.random.randint(3, 8)):
|
||||
paragraph = self._generate_paragraph()
|
||||
builder.with_paragraph(paragraph)
|
||||
current_size += len(paragraph) + 2 # +2 for newlines
|
||||
|
||||
if current_size >= size_bytes:
|
||||
break
|
||||
|
||||
# Add a list occasionally
|
||||
if self.random.random() < 0.3:
|
||||
items = [self._generate_sentence() for _ in range(self.random.randint(3, 7))]
|
||||
builder.with_list(items)
|
||||
current_size += sum(len(item) for item in items) + len(items) * 3 # Approximate
|
||||
|
||||
# Add a code block occasionally
|
||||
if self.random.random() < 0.2:
|
||||
code = self._generate_code_block()
|
||||
builder.with_code_block(code)
|
||||
current_size += len(code) + 10 # +10 for code block markers
|
||||
|
||||
return builder.build()
|
||||
|
||||
def _parse_size(self, size: str) -> int:
|
||||
"""Parse size string (e.g., '1mb', '500kb') to bytes."""
|
||||
size = size.lower()
|
||||
if size.endswith("kb"):
|
||||
return int(size[:-2]) * 1024
|
||||
elif size.endswith("mb"):
|
||||
return int(size[:-2]) * 1024 * 1024
|
||||
elif size.endswith("gb"):
|
||||
return int(size[:-2]) * 1024 * 1024 * 1024
|
||||
else:
|
||||
return int(size)
|
||||
|
||||
def _generate_paragraph(self) -> str:
|
||||
"""Generate a paragraph of random text."""
|
||||
sentences = []
|
||||
for _ in range(self.random.randint(3, 8)):
|
||||
sentences.append(self._generate_sentence())
|
||||
return " ".join(sentences)
|
||||
|
||||
def _generate_sentence(self) -> str:
|
||||
"""Generate a random sentence."""
|
||||
words = []
|
||||
for _ in range(self.random.randint(5, 15)):
|
||||
words.append(self._generate_word())
|
||||
|
||||
sentence = " ".join(words).capitalize()
|
||||
return sentence + "."
|
||||
|
||||
def _generate_word(self) -> str:
|
||||
"""Generate a random word."""
|
||||
length = self.random.randint(3, 12)
|
||||
return "".join(self.random.choices(string.ascii_lowercase, k=length))
|
||||
|
||||
def _generate_code_block(self) -> str:
|
||||
"""Generate a random code block."""
|
||||
lines = []
|
||||
for _ in range(self.random.randint(5, 15)):
|
||||
line = self._generate_code_line()
|
||||
lines.append(line)
|
||||
return "\n".join(lines)
|
||||
|
||||
def _generate_code_line(self) -> str:
|
||||
"""Generate a line of code-like text."""
|
||||
templates = [
|
||||
"def {func_name}({params}):",
|
||||
" return {expression}",
|
||||
"if {condition}:",
|
||||
" {statement}",
|
||||
"# {comment}",
|
||||
"class {class_name}:",
|
||||
" self.{attr} = {value}",
|
||||
"import {module}",
|
||||
"from {module} import {name}",
|
||||
]
|
||||
|
||||
template = self.random.choice(templates)
|
||||
variables = {
|
||||
"func_name": self._generate_word(),
|
||||
"params": ", ".join([self._generate_word() for _ in range(self.random.randint(0, 3))]),
|
||||
"expression": f"{self._generate_word()}({self._generate_word()})",
|
||||
"condition": f"{self._generate_word()} == {self.random.randint(1, 100)}",
|
||||
"statement": f"{self._generate_word()} = {self.random.randint(1, 100)}",
|
||||
"comment": " ".join([self._generate_word() for _ in range(self.random.randint(2, 6))]),
|
||||
"class_name": self._generate_word().capitalize(),
|
||||
"attr": self._generate_word(),
|
||||
"value": str(self.random.randint(1, 100)),
|
||||
"module": self._generate_word(),
|
||||
"name": self._generate_word(),
|
||||
}
|
||||
|
||||
return template.format(**variables)
|
||||
|
||||
|
||||
# Pre-built sample documents
|
||||
SAMPLE_SIMPLE_DOCUMENT = """# Simple Document
|
||||
|
||||
This is a simple test document.
|
||||
|
||||
## Features
|
||||
|
||||
- Feature 1
|
||||
- Feature 2
|
||||
- Feature 3
|
||||
"""
|
||||
|
||||
SAMPLE_COMPLEX_DOCUMENT = (
|
||||
MarkdownDocumentBuilder()
|
||||
.with_metadata("title", "Complex Test Document")
|
||||
.with_metadata("author", "Test Suite")
|
||||
.with_metadata("tags", "test, complex, sample")
|
||||
.with_heading("Complex Test Document")
|
||||
.with_paragraph("This is a complex test document with various markdown features.")
|
||||
.with_heading("Table of Contents", level=2)
|
||||
.with_list([
|
||||
"Introduction",
|
||||
"Features",
|
||||
"Examples",
|
||||
"Conclusion"
|
||||
], ordered=True)
|
||||
.with_heading("Introduction", level=2)
|
||||
.with_paragraph("This document demonstrates various markdown features.")
|
||||
.with_blockquote("This is an important note about the document.")
|
||||
.with_heading("Features", level=2)
|
||||
.with_list([
|
||||
"**Bold text**",
|
||||
"*Italic text*",
|
||||
"`Code inline`",
|
||||
"[Links](https://example.com)"
|
||||
])
|
||||
.with_heading("Code Example", level=3)
|
||||
.with_code_block('''def hello_world():
|
||||
"""Print hello world message."""
|
||||
print("Hello, World!")
|
||||
return "success"''')
|
||||
.with_heading("Data Table", level=3)
|
||||
.with_table(
|
||||
["Name", "Type", "Description"],
|
||||
[
|
||||
["title", "string", "Document title"],
|
||||
["author", "string", "Document author"],
|
||||
["tags", "array", "Document tags"]
|
||||
]
|
||||
)
|
||||
.with_heading("Conclusion", level=2)
|
||||
.with_paragraph("This document shows the power of markdown for documentation.")
|
||||
.build()
|
||||
)
|
||||
|
||||
SAMPLE_TECHNICAL_DOCUMENT = (
|
||||
MarkdownDocumentBuilder()
|
||||
.with_metadata("title", "API Documentation")
|
||||
.with_metadata("version", "1.0.0")
|
||||
.with_metadata("category", "technical")
|
||||
.with_heading("API Documentation")
|
||||
.with_paragraph("This document describes the REST API endpoints.")
|
||||
.with_heading("Authentication", level=2)
|
||||
.with_paragraph("All API requests require authentication via API key.")
|
||||
.with_code_block('''curl -H "Authorization: Bearer YOUR_API_KEY" \\
|
||||
https://api.example.com/v1/endpoint''', "bash")
|
||||
.with_heading("Endpoints", level=2)
|
||||
.with_heading("GET /users", level=3)
|
||||
.with_paragraph("Retrieve a list of users.")
|
||||
.with_table(
|
||||
["Parameter", "Type", "Required", "Description"],
|
||||
[
|
||||
["limit", "integer", "No", "Maximum number of results"],
|
||||
["offset", "integer", "No", "Number of results to skip"],
|
||||
["filter", "string", "No", "Filter criteria"]
|
||||
]
|
||||
)
|
||||
.with_heading("Response", level=4)
|
||||
.with_code_block('''{
|
||||
"users": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"offset": 0,
|
||||
"limit": 10
|
||||
}''', "json")
|
||||
.build()
|
||||
)
|
||||
Reference in New Issue
Block a user