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
Separate capability-specific tests from core system tests to establish clear test organization and separation of concerns. ## Test Reorganization: - **markitect-content tests**: Moved 6 tests to capabilities/markitect-content/tests/ - **markitect-finance tests**: Moved 7 tests to markitect/finance/tests/ - **markitect-query tests**: Moved 1 test to markitect/query_paradigms/tests/ - **markitect-graphql tests**: Moved 2 tests to markitect/graphql/tests/ - **markitect-plugins tests**: Moved 2 tests to markitect/plugins/tests/ ## Makefile Updates: - **make test**: Excludes capability tests, runs only core system tests - **make test-capabilities**: Runs all capability tests - **make test-capability-***: Individual capability test targets - Updated all test targets (test-red, test-green, test-ultra-fast, test-perf) - Added capability test targets to help documentation ## Benefits: - Clear separation between core system tests and capability-specific tests - Faster core test execution (capability tests not run by default) - Individual capability testing for focused development - Supports future capability extraction workflow - Maintains capability test independence Test verification: - Core tests: 1291 tests (capability tests excluded) - Finance capability: 143 tests working independently - Content capability: 79 tests working independently 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
515 lines
17 KiB
Python
515 lines
17 KiB
Python
"""
|
|
Tests for Issue #54: Add content field instruction capabilities
|
|
|
|
This test module implements comprehensive tests for content field instructions
|
|
that provide guidance for content authors during document generation.
|
|
|
|
Following TDD8 methodology - these tests are written before implementation.
|
|
"""
|
|
|
|
import json
|
|
import pytest
|
|
from pathlib import Path
|
|
from tempfile import NamedTemporaryFile
|
|
from click.testing import CliRunner
|
|
|
|
from markitect.cli import cli
|
|
from markitect.schema_generator import SchemaGenerator
|
|
from markitect.stub_generator import StubGenerator
|
|
from markitect.exceptions import InvalidInstructionTypeError
|
|
|
|
|
|
class TestIssue54ContentInstructions:
|
|
"""Test suite for content field instruction functionality."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test fixtures."""
|
|
self.schema_generator = SchemaGenerator()
|
|
self.stub_generator = StubGenerator()
|
|
self.runner = CliRunner()
|
|
|
|
def test_cli_accepts_include_content_instructions_option(self):
|
|
"""Test that CLI accepts --include-content-instructions option."""
|
|
# Arrange
|
|
markdown_content = """# Architecture Document
|
|
|
|
## Introduction
|
|
This section provides an overview of the system.
|
|
|
|
## Design Principles
|
|
Core principles guiding the design.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
result = self.runner.invoke(cli, [
|
|
'schema-generate',
|
|
'--include-content-instructions',
|
|
str(temp_file)
|
|
])
|
|
|
|
# Assert
|
|
assert result.exit_code == 0, f"CLI should accept --include-content-instructions option, got: {result.output}"
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_schema_generation_with_content_instructions_includes_instruction_fields(self):
|
|
"""Test that schema generation with content instructions includes instruction fields."""
|
|
# Arrange
|
|
markdown_content = """# Software Architecture Document
|
|
|
|
## Introduction
|
|
This section provides an overview of the system architecture.
|
|
|
|
### Purpose
|
|
Explain the purpose and goals of this document.
|
|
|
|
## System Design
|
|
Describe the overall system design and architecture.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
schema = self.schema_generator.generate_schema_from_file(
|
|
temp_file,
|
|
include_content_instructions=True
|
|
)
|
|
|
|
# Assert - Schema should contain content instruction fields
|
|
assert "properties" in schema
|
|
assert "headings" in schema["properties"]
|
|
|
|
headings = schema["properties"]["headings"]["properties"]
|
|
|
|
# Level 1 heading should have content instructions
|
|
level_1 = headings["level_1"]
|
|
items_props = level_1["items"]["properties"]
|
|
assert "x-markitect-content-instructions" in items_props
|
|
assert items_props["x-markitect-content-instructions"]["type"] == "string"
|
|
|
|
# Level 2 headings should have content instructions
|
|
level_2 = headings["level_2"]
|
|
items_props = level_2["items"]["properties"]
|
|
assert "x-markitect-content-instructions" in items_props
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_schema_includes_content_instruction_metaschema_extension(self):
|
|
"""Test that schemas with content instructions include metaschema extension."""
|
|
# Arrange
|
|
markdown_content = """# Test Document
|
|
|
|
## Section A
|
|
Content for section A.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
schema = self.schema_generator.generate_schema_from_file(
|
|
temp_file,
|
|
include_content_instructions=True
|
|
)
|
|
|
|
# Assert - Should have metaschema extension
|
|
assert "x-markitect-content-instructions-enabled" in schema
|
|
assert schema["x-markitect-content-instructions-enabled"] is True
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_content_instructions_support_different_instruction_types(self):
|
|
"""Test that content instructions can specify different instruction types."""
|
|
# Arrange
|
|
markdown_content = """# Requirements Document
|
|
|
|
## Functional Requirements
|
|
List all functional requirements.
|
|
|
|
## Non-Functional Requirements
|
|
Describe performance, security, and usability requirements.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
schema = self.schema_generator.generate_schema_from_file(
|
|
temp_file,
|
|
include_content_instructions=True,
|
|
instruction_type="description"
|
|
)
|
|
|
|
# Assert - Should have instruction type specified
|
|
headings = schema["properties"]["headings"]["properties"]
|
|
level_2 = headings["level_2"]
|
|
items_props = level_2["items"]["properties"]
|
|
|
|
assert "x-markitect-instruction-type" in items_props
|
|
assert items_props["x-markitect-instruction-type"]["enum"] == ["description"]
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_content_instructions_integration_with_outline_mode(self):
|
|
"""Test that content instructions work with outline mode."""
|
|
# Arrange
|
|
markdown_content = """# Project Plan
|
|
|
|
## Phase 1: Planning
|
|
Planning activities and deliverables.
|
|
|
|
### Requirements Gathering
|
|
Gather and document all requirements.
|
|
|
|
### Architecture Design
|
|
Design the system architecture.
|
|
|
|
## Phase 2: Implementation
|
|
Implementation activities.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
result = self.runner.invoke(cli, [
|
|
'schema-generate',
|
|
'--mode', 'outline',
|
|
'--include-content-instructions',
|
|
'--depth', '2',
|
|
str(temp_file)
|
|
])
|
|
|
|
# Assert
|
|
assert result.exit_code == 0
|
|
schema = json.loads(result.output)
|
|
|
|
# Should have both outline mode and content instructions extensions
|
|
assert schema.get("x-markitect-outline-mode") is True
|
|
assert schema.get("x-markitect-content-instructions-enabled") is True
|
|
|
|
# Should only include headings up to depth 2
|
|
headings = schema["properties"]["headings"]["properties"]
|
|
assert "level_1" in headings
|
|
assert "level_2" in headings
|
|
assert "level_3" not in headings
|
|
|
|
# Should have content instructions in the headings
|
|
level_2 = headings["level_2"]
|
|
items_props = level_2["items"]["properties"]
|
|
assert "x-markitect-content-instructions" in items_props
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_content_instructions_for_paragraphs_and_lists(self):
|
|
"""Test that content instructions can be added for paragraphs and lists."""
|
|
# Arrange
|
|
markdown_content = """# User Guide
|
|
|
|
## Overview
|
|
This guide explains how to use the system.
|
|
|
|
Some introductory text here.
|
|
|
|
- Feature A
|
|
- Feature B
|
|
- Feature C
|
|
|
|
## Getting Started
|
|
Follow these steps to get started.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
schema = self.schema_generator.generate_schema_from_file(
|
|
temp_file,
|
|
include_content_instructions=True
|
|
)
|
|
|
|
# Assert - Paragraphs should have content instructions
|
|
if "paragraphs" in schema["properties"]:
|
|
paragraphs_schema = schema["properties"]["paragraphs"]
|
|
items_props = paragraphs_schema["items"]["properties"]
|
|
assert "x-markitect-content-instructions" in items_props
|
|
|
|
# Lists should have content instructions
|
|
if "lists" in schema["properties"]:
|
|
lists_schema = schema["properties"]["lists"]
|
|
items_props = lists_schema["items"]["properties"]
|
|
assert "x-markitect-content-instructions" in items_props
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_stub_generation_includes_content_instruction_placeholders(self):
|
|
"""Test that stub generation includes content instruction placeholders."""
|
|
# Arrange
|
|
schema = {
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"type": "object",
|
|
"title": "Test Schema",
|
|
"x-markitect-content-instructions-enabled": True,
|
|
"properties": {
|
|
"headings": {
|
|
"type": "object",
|
|
"properties": {
|
|
"level_1": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"content": {"type": "string"},
|
|
"x-markitect-content-instructions": {
|
|
"type": "string",
|
|
"const": "Provide the main title of the document"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"level_2": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"content": {"type": "string"},
|
|
"x-markitect-content-instructions": {
|
|
"type": "string",
|
|
"const": "Describe each major section of the document"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Act
|
|
stub_content = self.stub_generator.generate_stub_from_schema(schema)
|
|
|
|
# Assert - Stub should include instruction placeholders
|
|
assert "Provide the main title of the document" in stub_content
|
|
assert "Describe each major section of the document" in stub_content
|
|
|
|
def test_cli_supports_instruction_type_parameter(self):
|
|
"""Test that CLI supports --instruction-type parameter."""
|
|
# Arrange
|
|
markdown_content = """# API Documentation
|
|
|
|
## Authentication
|
|
How to authenticate with the API.
|
|
|
|
## Endpoints
|
|
Available API endpoints.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
result = self.runner.invoke(cli, [
|
|
'schema-generate',
|
|
'--include-content-instructions',
|
|
'--instruction-type', 'example',
|
|
str(temp_file)
|
|
])
|
|
|
|
# Assert
|
|
assert result.exit_code == 0
|
|
schema = json.loads(result.output)
|
|
|
|
# Check that instruction type is set correctly
|
|
headings = schema["properties"]["headings"]["properties"]
|
|
level_1 = headings["level_1"]
|
|
items_props = level_1["items"]["properties"]
|
|
assert items_props["x-markitect-instruction-type"]["enum"] == ["example"]
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_backward_compatibility_without_content_instructions(self):
|
|
"""Test that existing behavior is maintained when content instructions are not enabled."""
|
|
# Arrange
|
|
markdown_content = """# Test Document
|
|
|
|
## Section One
|
|
Content here.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act - Generate schema without content instructions (default behavior)
|
|
schema = self.schema_generator.generate_schema_from_file(temp_file)
|
|
|
|
# Assert - Should NOT have content instruction fields
|
|
headings = schema["properties"]["headings"]["properties"]
|
|
level_1 = headings["level_1"]
|
|
items_props = level_1["items"]["properties"]
|
|
|
|
# Should not have content instruction fields
|
|
assert "x-markitect-content-instructions" not in items_props
|
|
assert "x-markitect-instruction-type" not in items_props
|
|
|
|
# Should NOT have content instructions extension
|
|
assert "x-markitect-content-instructions-enabled" not in schema
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_content_instructions_with_heading_text_capture_integration(self):
|
|
"""Test that content instructions work with heading text capture."""
|
|
# Arrange
|
|
markdown_content = """# Architecture Overview
|
|
|
|
## System Components
|
|
Core system components and their responsibilities.
|
|
|
|
## Data Flow
|
|
How data flows through the system.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
schema = self.schema_generator.generate_schema_from_file(
|
|
temp_file,
|
|
capture_heading_text=True,
|
|
include_content_instructions=True
|
|
)
|
|
|
|
# Assert - Should have both heading text capture and content instructions
|
|
assert schema.get("x-markitect-heading-text-capture") is True
|
|
assert schema.get("x-markitect-content-instructions-enabled") is True
|
|
|
|
# Headings should have both enum constraints and content instructions
|
|
headings = schema["properties"]["headings"]["properties"]
|
|
level_1 = headings["level_1"]
|
|
items_props = level_1["items"]["properties"]
|
|
|
|
# Should have enum constraint from heading text capture
|
|
assert "enum" in items_props["content"]
|
|
assert items_props["content"]["enum"] == ["Architecture Overview"]
|
|
|
|
# Should also have content instructions
|
|
assert "x-markitect-content-instructions" in items_props
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_cli_help_includes_content_instructions_options(self):
|
|
"""Test that CLI help includes documentation for content instruction options."""
|
|
# Act
|
|
result = self.runner.invoke(cli, ['schema-generate', '--help'])
|
|
|
|
# Assert
|
|
assert result.exit_code == 0
|
|
help_text = result.output
|
|
assert "--include-content-instructions" in help_text
|
|
assert "--instruction-type" in help_text
|
|
assert "content instructions" in help_text or "content guidance" in help_text
|
|
|
|
def test_instruction_type_validation(self):
|
|
"""Test that --instruction-type parameter validates input correctly."""
|
|
# Arrange
|
|
markdown_content = """# Test Document
|
|
|
|
## Section
|
|
Content here.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act - Test invalid instruction type
|
|
result = self.runner.invoke(cli, [
|
|
'schema-generate',
|
|
'--include-content-instructions',
|
|
'--instruction-type', 'invalid-type',
|
|
str(temp_file)
|
|
])
|
|
|
|
# Assert
|
|
assert result.exit_code != 0
|
|
assert "Invalid instruction type" in result.output or "invalid-type" in result.output
|
|
|
|
finally:
|
|
temp_file.unlink()
|
|
|
|
def test_content_instructions_generate_appropriate_default_text(self):
|
|
"""Test that content instructions generate appropriate default guidance text."""
|
|
# Arrange
|
|
markdown_content = """# Development Guide
|
|
|
|
## Prerequisites
|
|
System requirements and prerequisites.
|
|
|
|
### Software Requirements
|
|
Required software and versions.
|
|
|
|
## Installation
|
|
Step-by-step installation instructions.
|
|
|
|
## Configuration
|
|
How to configure the system.
|
|
"""
|
|
|
|
with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
f.write(markdown_content)
|
|
temp_file = Path(f.name)
|
|
|
|
try:
|
|
# Act
|
|
schema = self.schema_generator.generate_schema_from_file(
|
|
temp_file,
|
|
include_content_instructions=True,
|
|
instruction_type="description"
|
|
)
|
|
|
|
# Assert - Content instructions should contain appropriate guidance
|
|
headings = schema["properties"]["headings"]["properties"]
|
|
|
|
# Level 1 should have appropriate instructions
|
|
level_1 = headings["level_1"]
|
|
items_props = level_1["items"]["properties"]
|
|
instructions = items_props["x-markitect-content-instructions"]["const"]
|
|
assert len(instructions) > 0
|
|
assert isinstance(instructions, str)
|
|
|
|
# Instructions should be contextually appropriate
|
|
# (implementation will determine specific text)
|
|
|
|
finally:
|
|
temp_file.unlink() |