From a8d9b9289cca15a100c3212f966d191925ac5693 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 1 Oct 2025 08:24:39 +0200 Subject: [PATCH] test: Add comprehensive test suite for Issue #54 content instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the complete test suite for content field instruction capabilities, providing comprehensive coverage for all implemented features. ## Test Coverage: - CLI option validation (--include-content-instructions, --instruction-type) - Schema generation with content instruction fields - Integration with outline mode and heading text capture - Backward compatibility verification - Error handling for invalid instruction types - Stub generator integration - Content instruction text generation for all types ## Test Structure: - 13 comprehensive test methods covering all use cases - TDD methodology validation (RED-GREEN-REFACTOR cycle) - Integration tests for feature combinations - Edge case and error condition testing This completes the test coverage for Issue #54 implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- tests/test_issue_54_content_instructions.py | 515 ++++++++++++++++++++ 1 file changed, 515 insertions(+) create mode 100644 tests/test_issue_54_content_instructions.py diff --git a/tests/test_issue_54_content_instructions.py b/tests/test_issue_54_content_instructions.py new file mode 100644 index 00000000..ef51ce61 --- /dev/null +++ b/tests/test_issue_54_content_instructions.py @@ -0,0 +1,515 @@ +""" +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() \ No newline at end of file