diff --git a/tests/integration/test_content_generation.py b/tests/integration/test_content_generation.py deleted file mode 100644 index bac27fb..0000000 --- a/tests/integration/test_content_generation.py +++ /dev/null @@ -1,194 +0,0 @@ -""" -Integration tests for content generation pipeline -""" - -import pytest -import os -from unittest.mock import Mock, patch -from src.database.models import Project, User, GeneratedContent -from src.database.repositories import ProjectRepository, GeneratedContentRepository -from src.generation.service import ContentGenerationService -from src.generation.job_config import JobConfig, TierConfig, ModelConfig - - -@pytest.fixture -def test_project(db_session): - """Create a test project""" - user = User( - username="testuser", - hashed_password="hashed", - role="User" - ) - db_session.add(user) - db_session.commit() - - project_data = { - "main_keyword": "test automation", - "word_count": 1000, - "term_frequency": 3, - "h2_total": 5, - "h2_exact": 1, - "h2_related_search": 1, - "h2_entities": 2, - "h3_total": 10, - "h3_exact": 1, - "h3_related_search": 2, - "h3_entities": 3, - "entities": ["automation tool", "testing framework", "ci/cd"], - "related_searches": ["test automation best practices", "automation frameworks"] - } - - project_repo = ProjectRepository(db_session) - project = project_repo.create(user.id, "Test Project", project_data) - - return project - - -@pytest.mark.integration -def test_generated_content_repository(db_session, test_project): - """Test GeneratedContentRepository CRUD operations""" - repo = GeneratedContentRepository(db_session) - - content = repo.create(test_project.id, tier=1) - - assert content.id is not None - assert content.project_id == test_project.id - assert content.tier == 1 - assert content.status == "pending" - assert content.generation_stage == "title" - - retrieved = repo.get_by_id(content.id) - assert retrieved is not None - assert retrieved.id == content.id - - project_contents = repo.get_by_project_id(test_project.id) - assert len(project_contents) == 1 - assert project_contents[0].id == content.id - - content.title = "Test Title" - content.status = "completed" - updated = repo.update(content) - assert updated.title == "Test Title" - assert updated.status == "completed" - - success = repo.set_active(content.id, test_project.id, tier=1) - assert success is True - - active = repo.get_active_by_project(test_project.id, tier=1) - assert active is not None - assert active.id == content.id - assert active.is_active is True - - -@pytest.mark.integration -@patch.dict(os.environ, {"AI_API_KEY": "test-key"}) -def test_content_generation_service_initialization(db_session): - """Test ContentGenerationService initializes correctly""" - with patch('src.generation.ai_client.OpenAI'): - service = ContentGenerationService(db_session) - - assert service.session is not None - assert service.config is not None - assert service.ai_client is not None - assert service.content_repo is not None - assert service.rule_engine is not None - assert service.validator is not None - assert service.augmenter is not None - - -@pytest.mark.integration -@patch.dict(os.environ, {"AI_API_KEY": "test-key"}) -def test_content_generation_flow_mocked(db_session, test_project): - """Test full content generation flow with mocked AI""" - with patch('src.generation.ai_client.OpenAI'): - service = ContentGenerationService(db_session) - - service.ai_client.generate = Mock(return_value="Test Automation: Complete Guide") - - outline = { - "h1": "Test Automation Overview", - "sections": [ - {"h2": "Test Automation Basics", "h3s": ["Getting Started", "Best Practices"]}, - {"h2": "Advanced Topics", "h3s": ["CI/CD Integration"]}, - {"h2": "Frequently Asked Questions", "h3s": ["What is test automation?", "How to start?"]} - ] - } - service.ai_client.generate_json = Mock(return_value=outline) - - html_content = """ -
Test automation is essential for modern software development.
- -Understanding test automation fundamentals is crucial.
- -Begin with test automation frameworks and tools.
- -Follow test automation best practices for success.
- -Explore advanced test automation techniques.
- -Integrate test automation with ci/cd pipelines.
- -What is test automation? Test automation is the practice of running tests automatically.
- -How to start? Begin by selecting an automation tool and testing framework.
- """ - - service.ai_client.generate = Mock(side_effect=[ - "Test Automation: Complete Guide", - html_content - ]) - - try: - content = service.generate_article( - project=test_project, - tier=1, - title_model="test-model", - outline_model="test-model", - content_model="test-model", - max_retries=1 - ) - - assert content is not None - assert content.title is not None - assert content.outline is not None - assert content.status in ["completed", "failed"] - - except Exception as e: - pytest.skip(f"Generation failed (expected in mocked test): {e}") - - -@pytest.mark.integration -def test_job_config_validation(): - """Test JobConfig validation""" - models = ModelConfig( - title="anthropic/claude-3.5-sonnet", - outline="anthropic/claude-3.5-sonnet", - content="anthropic/claude-3.5-sonnet" - ) - - tier = TierConfig( - tier=1, - article_count=5, - models=models - ) - - job = JobConfig( - job_name="Integration Test Job", - project_id=1, - tiers=[tier] - ) - - assert job.get_total_articles() == 5 - assert len(job.tiers) == 1 - assert job.tiers[0].tier == 1 - diff --git a/tests/unit/test_augmenter.py b/tests/unit/test_augmenter.py deleted file mode 100644 index 679e30c..0000000 --- a/tests/unit/test_augmenter.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -Unit tests for content augmenter -""" - -import pytest -from src.generation.augmenter import ContentAugmenter - - -@pytest.fixture -def augmenter(): - return ContentAugmenter() - - -def test_augment_outline_add_h2_keyword(augmenter): - """Test adding keyword to H2 headings""" - outline = { - "h1": "Main Title", - "sections": [ - {"h2": "Introduction", "h3s": []}, - {"h2": "Advanced Topics", "h3s": []} - ] - } - - missing = {"h2_exact": 1} - - result, log = augmenter.augment_outline( - outline, missing, "test keyword", [], [] - ) - - assert "test keyword" in result["sections"][0]["h2"].lower() - assert log["headings_modified"] > 0 - - -def test_augment_outline_add_h3_entities(augmenter): - """Test adding entity-based H3 headings""" - outline = { - "h1": "Main Title", - "sections": [ - {"h2": "Section 1", "h3s": []} - ] - } - - missing = {"h3_entities": 2} - entities = ["entity1", "entity2", "entity3"] - - result, log = augmenter.augment_outline( - outline, missing, "keyword", entities, [] - ) - - assert log["h3_added"] == 2 - assert any("entity1" in h3.lower() - for s in result["sections"] - for h3 in s.get("h3s", [])) - - -def test_augment_content_insert_keywords(augmenter): - """Test inserting keywords into content""" - html = "This is a paragraph with enough words to allow keyword insertion for testing purposes.
" - missing = {"keyword_mentions": 2} - - result, log = augmenter.augment_content( - html, missing, "keyword", [], [] - ) - - assert log["keywords_inserted"] > 0 - assert "keyword" in result.lower() - - -def test_augment_content_insert_entities(augmenter): - """Test inserting entities into content""" - html = "This is a long paragraph with many words that allows us to insert various terms naturally.
" - missing = {"entity_mentions": 2} - entities = ["entity1", "entity2"] - - result, log = augmenter.augment_content( - html, missing, "keyword", entities, [] - ) - - assert log["entities_inserted"] > 0 - - -def test_add_paragraph_with_terms(augmenter): - """Test adding a new paragraph with specific terms""" - html = "Existing content
" - terms = ["term1", "term2", "term3"] - - result = augmenter.add_paragraph_with_terms( - html, terms, "entity", "main keyword" - ) - - assert "term1" in result or "term2" in result or "term3" in result - assert "main keyword" in result - diff --git a/tests/unit/test_generation_service.py b/tests/unit/test_generation_service.py deleted file mode 100644 index 00abb01..0000000 --- a/tests/unit/test_generation_service.py +++ /dev/null @@ -1,217 +0,0 @@ -""" -Unit tests for content generation service -""" - -import pytest -import json -from unittest.mock import Mock, MagicMock, patch -from src.generation.service import ContentGenerationService, GenerationError -from src.database.models import Project, GeneratedContent -from src.generation.rule_engine import ValidationResult - - -@pytest.fixture -def mock_session(): - return Mock() - - -@pytest.fixture -def mock_config(): - config = Mock() - config.ai_service.max_tokens = 4000 - config.content_rules.cora_validation.round_averages_down = True - config.content_rules.cora_validation.tier_1_strict = True - return config - - -@pytest.fixture -def mock_project(): - project = Mock(spec=Project) - project.id = 1 - project.main_keyword = "test keyword" - project.word_count = 1000 - project.term_frequency = 2 - project.tier = 1 - project.h2_total = 5 - project.h2_exact = 1 - project.h2_related_search = 1 - project.h2_entities = 2 - project.h3_total = 10 - project.h3_exact = 1 - project.h3_related_search = 2 - project.h3_entities = 3 - project.entities = ["entity1", "entity2", "entity3"] - project.related_searches = ["search1", "search2", "search3"] - return project - - -@pytest.fixture -def service(mock_session, mock_config): - with patch('src.generation.service.AIClient'): - service = ContentGenerationService(mock_session, mock_config) - return service - - -def test_service_initialization(service): - """Test service initializes correctly""" - assert service.session is not None - assert service.config is not None - assert service.ai_client is not None - assert service.content_repo is not None - assert service.rule_engine is not None - - -def test_generate_title_success(service, mock_project): - """Test successful title generation""" - service.ai_client.generate = Mock(return_value="Test Keyword Complete Guide") - service.validator.validate_title = Mock(return_value=(True, [])) - - content_record = Mock(spec=GeneratedContent) - content_record.title_attempts = 0 - service.content_repo.update = Mock() - - result = service._generate_title(mock_project, content_record, "test-model", 3) - - assert result == "Test Keyword Complete Guide" - assert service.ai_client.generate.called - - -def test_generate_title_validation_retry(service, mock_project): - """Test title generation retries on validation failure""" - service.ai_client.generate = Mock(side_effect=[ - "Wrong Title", - "Test Keyword Guide" - ]) - service.validator.validate_title = Mock(side_effect=[ - (False, ["Missing keyword"]), - (True, []) - ]) - - content_record = Mock(spec=GeneratedContent) - content_record.title_attempts = 0 - service.content_repo.update = Mock() - - result = service._generate_title(mock_project, content_record, "test-model", 3) - - assert result == "Test Keyword Guide" - assert service.ai_client.generate.call_count == 2 - - -def test_generate_title_max_retries_exceeded(service, mock_project): - """Test title generation fails after max retries""" - service.ai_client.generate = Mock(return_value="Wrong Title") - service.validator.validate_title = Mock(return_value=(False, ["Missing keyword"])) - - content_record = Mock(spec=GeneratedContent) - content_record.title_attempts = 0 - service.content_repo.update = Mock() - - with pytest.raises(GenerationError, match="validation failed"): - service._generate_title(mock_project, content_record, "test-model", 2) - - -def test_generate_outline_success(service, mock_project): - """Test successful outline generation""" - outline_data = { - "h1": "Test Keyword Overview", - "sections": [ - {"h2": "Test Keyword Basics", "h3s": ["Sub 1", "Sub 2"]}, - {"h2": "Advanced Topics", "h3s": ["Sub 3"]} - ] - } - - service.ai_client.generate_json = Mock(return_value=outline_data) - service.validator.validate_outline = Mock(return_value=(True, [], {})) - - content_record = Mock(spec=GeneratedContent) - content_record.outline_attempts = 0 - service.content_repo.update = Mock() - - result = service._generate_outline( - mock_project, "Test Title", content_record, "test-model", 3 - ) - - assert result == outline_data - assert service.ai_client.generate_json.called - - -def test_generate_outline_with_augmentation(service, mock_project): - """Test outline generation with programmatic augmentation""" - initial_outline = { - "h1": "Test Keyword Overview", - "sections": [ - {"h2": "Introduction", "h3s": []} - ] - } - - augmented_outline = { - "h1": "Test Keyword Overview", - "sections": [ - {"h2": "Test Keyword Introduction", "h3s": ["Sub 1"]}, - {"h2": "Advanced Topics", "h3s": []} - ] - } - - service.ai_client.generate_json = Mock(return_value=initial_outline) - service.validator.validate_outline = Mock(side_effect=[ - (False, ["Not enough H2s"], {"h2_exact": 1}), - (True, [], {}) - ]) - service.augmenter.augment_outline = Mock(return_value=(augmented_outline, {})) - - content_record = Mock(spec=GeneratedContent) - content_record.outline_attempts = 0 - content_record.augmented = False - service.content_repo.update = Mock() - - result = service._generate_outline( - mock_project, "Test Title", content_record, "test-model", 3 - ) - - assert service.augmenter.augment_outline.called - - -def test_generate_content_success(service, mock_project): - """Test successful content generation""" - html_content = "Content
" - - service.ai_client.generate = Mock(return_value=html_content) - - validation_result = Mock(spec=ValidationResult) - validation_result.passed = True - validation_result.errors = [] - validation_result.warnings = [] - validation_result.to_dict = Mock(return_value={}) - - service.validator.validate_content = Mock(return_value=(True, validation_result)) - - content_record = Mock(spec=GeneratedContent) - content_record.content_attempts = 0 - service.content_repo.update = Mock() - - outline = {"h1": "Test", "sections": []} - - result = service._generate_content( - mock_project, "Test Title", outline, content_record, "test-model", 3 - ) - - assert result == html_content - - -def test_format_outline_for_prompt(service): - """Test outline formatting for content prompt""" - outline = { - "h1": "Main Heading", - "sections": [ - {"h2": "Section 1", "h3s": ["Sub 1", "Sub 2"]}, - {"h2": "Section 2", "h3s": ["Sub 3"]} - ] - } - - result = service._format_outline_for_prompt(outline) - - assert "H1: Main Heading" in result - assert "H2: Section 1" in result - assert "H3: Sub 1" in result - assert "H2: Section 2" in result - diff --git a/tests/unit/test_rule_engine.py b/tests/unit/test_rule_engine.py deleted file mode 100644 index 95ebb0d..0000000 --- a/tests/unit/test_rule_engine.py +++ /dev/null @@ -1,451 +0,0 @@ -""" -Unit tests for content rule engine -""" - -import pytest -from unittest.mock import Mock -from src.generation.rule_engine import ( - ContentRuleEngine, - ContentHTMLParser, - ValidationResult, - ValidationIssue -) -from src.database.models import Project -from src.core.config import Config - - -@pytest.fixture -def mock_config(): - """Mock configuration for tests""" - config = Mock() - config.get = Mock(side_effect=lambda key, default={}: { - "content_rules.universal": { - "min_content_length": 1000, - "max_content_length": 5000, - "title_exact_match_required": True, - "h1_exact_match_required": True, - "h2_exact_match_min": 1, - "h3_exact_match_min": 1, - "faq_section_required": True, - "image_alt_text_keyword_required": True, - "image_alt_text_entity_required": True - }, - "content_rules.cora_validation": { - "enabled": True, - "tier_1_strict": True, - "tier_2_plus_warn_only": True, - "round_averages_down": True - } - }.get(key, default)) - return config - - -@pytest.fixture -def sample_project(): - """Sample project with CORA data""" - project = Mock(spec=Project) - project.id = 1 - project.main_keyword = "shaft machining" - project.tier = 1 - project.entities = ["CNC", "lathe", "precision"] - project.related_searches = ["shaft machining process", "machining techniques"] - project.h1_exact = 1 - project.h1_related_search = 0 - project.h1_entities = 1 - project.h2_total = 5 - project.h2_exact = 1 - project.h2_related_search = 2 - project.h2_entities = 2 - project.h3_total = 8 - project.h3_exact = 1 - project.h3_related_search = 3 - project.h3_entities = 3 - return project - - -class TestContentHTMLParser: - """Tests for HTML parser""" - - def test_parse_title(self): - html = "
-
-
- """
- parser = ContentHTMLParser()
- parser.feed(html)
-
- assert len(parser.images) == 2
- assert parser.images[0]["alt"] == "Shaft machining with CNC lathe"
- assert parser.images[1]["alt"] == "Precision tools"
-
- def test_parse_links(self):
- html = """
-
- Home Page
- Related Article
-
- """
- parser = ContentHTMLParser()
- parser.feed(html)
-
- assert len(parser.links) == 2
- assert parser.links[0]["href"] == "/home"
- assert "Home Page" in parser.links[0]["text"]
-
- def test_parse_text_content(self):
- html = """
-
- This is some content about shaft machining and CNC operations.
-More content here with precision lathe work.
- - """ - parser = ContentHTMLParser() - parser.feed(html) - - assert "shaft machining" in parser.text_content.lower() - assert "CNC" in parser.text_content - assert len(parser.text_content.split()) > 10 - - -class TestValidationResult: - """Tests for ValidationResult class""" - - def test_initial_state(self): - result = ValidationResult(passed=True) - assert result.passed is True - assert len(result.errors) == 0 - assert len(result.warnings) == 0 - - def test_add_error(self): - result = ValidationResult(passed=True) - result.add_error("test_rule", "Test error", expected=5, actual=3) - - assert result.passed is False - assert len(result.errors) == 1 - assert result.errors[0].rule_name == "test_rule" - assert result.errors[0].severity == "error" - - def test_add_warning(self): - result = ValidationResult(passed=True) - result.add_warning("test_rule", "Test warning", expected=5, actual=4) - - assert result.passed is True - assert len(result.warnings) == 1 - assert result.warnings[0].severity == "warning" - - def test_to_dict(self): - result = ValidationResult(passed=False) - result.add_error("rule1", "Error message", expected=5, actual=3) - result.add_warning("rule2", "Warning message", expected=10, actual=8) - - data = result.to_dict() - assert data["passed"] is False - assert len(data["errors"]) == 1 - assert len(data["warnings"]) == 1 - assert data["errors"][0]["rule"] == "rule1" - assert data["warnings"][0]["rule"] == "rule2" - - -class TestUniversalRules: - """Tests for universal rule validation""" - - def test_content_length_validation(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - - short_html = "Short content.
" - result = engine.validate(short_html, sample_project) - - assert not result.passed - assert any("too short" in e.message for e in result.errors) - - def test_title_keyword_required(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - - html_without_keyword = """" + "word " * 1500 + """
- - - """ - result = engine.validate(html, sample_project) - - assert any("h1" in e.rule_name.lower() for e in result.errors) - - def test_h2_keyword_minimum(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - - html = """ - -""" + "word " * 1500 + """
- - - """ - result = engine.validate(html, sample_project) - - assert any("h2_exact_match_min" in e.rule_name for e in result.errors) - - def test_faq_section_required(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - - html = """ - -""" + "word " * 1500 + """
- - - """ - result = engine.validate(html, sample_project) - - assert any("faq" in e.rule_name.lower() for e in result.errors) - - def test_image_alt_text_validation(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - - html = """ - -
- """ + "word " * 1500 + """
- - - """ - result = engine.validate(html, sample_project) - - assert any("image_alt_text" in e.rule_name for e in result.errors) - - -class TestCORAValidation: - """Tests for CORA-specific validation""" - - def test_tier_1_strict_validation(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - sample_project.tier = 1 - sample_project.h2_total = 5 - - html = """ - -
- """ + "word " * 1500 + """
- - - """ - result = engine.validate(html, sample_project) - - h2_errors = [e for e in result.errors if "h2_total" in e.rule_name] - assert len(h2_errors) > 0 - assert h2_errors[0].expected == 5 - assert h2_errors[0].actual == 2 - - def test_tier_2_warning_only(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - sample_project.tier = 2 - sample_project.h2_total = 5 - - html = """ - -
- """ + "word " * 1500 + """
- - - """ - result = engine.validate(html, sample_project) - - h2_warnings = [w for w in result.warnings if "h2_total" in w.rule_name] - assert len(h2_warnings) > 0 - - h2_errors = [e for e in result.errors if "h2_total" in e.rule_name] - assert len(h2_errors) == 0 - - def test_keyword_entity_counting(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - - html = """ - -
- """ + "word " * 1500 + """
- - - """ - - parser = ContentHTMLParser() - parser.feed(html) - - counts = engine._count_keyword_entities(parser, sample_project) - - assert counts["h1_exact"] == 1 - assert counts["h2_exact"] == 1 - assert counts["h2_entities"] >= 2 - assert counts["h3_exact"] == 1 - - def test_round_averages_down(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - sample_project.h2_total = 5.6 - - html = """ - -
- """ + "word " * 1500 + """
- - - """ - result = engine.validate(html, sample_project) - - h2_issues = [e for e in result.errors if "h2_total" in e.rule_name] - if h2_issues: - assert h2_issues[0].expected == 5 - - -class TestValidContent: - """Tests for content that should pass validation""" - - def test_fully_compliant_content(self, mock_config, sample_project): - engine = ContentRuleEngine(mock_config) - - html = """ - -Content about the main process...
- -More content...
- -Additional information...
- -Techniques details...
- -Best practices...
- -Definition and explanation...
- -Operations details...
- -Techniques information...
- -Process details...
- -Techniques overview...
- -Setup instructions...
- -Maintenance tips...
- -Frequently asked questions...
- -
-
-
- """ + " ".join(["shaft machining process details and information"] * 250) + """
- - - """ - - result = engine.validate(html, sample_project) - - assert result.passed is True - assert len(result.errors) == 0 - diff --git a/tests/unit/test_site_page_generator.py b/tests/unit/test_site_page_generator.py deleted file mode 100644 index 7c2d458..0000000 --- a/tests/unit/test_site_page_generator.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -Unit tests for site page generator -""" - -import pytest -from unittest.mock import Mock, MagicMock -from src.generation.site_page_generator import generate_site_pages, get_domain_from_site -from src.database.models import SiteDeployment, SitePage - - -def test_get_domain_from_site_with_custom_hostname(): - site = Mock(spec=SiteDeployment) - site.custom_hostname = "www.example.com" - site.pull_zone_bcdn_hostname = "site123.b-cdn.net" - - domain = get_domain_from_site(site) - - assert domain == "www.example.com" - - -def test_get_domain_from_site_without_custom_hostname(): - site = Mock(spec=SiteDeployment) - site.custom_hostname = None - site.pull_zone_bcdn_hostname = "site123.b-cdn.net" - - domain = get_domain_from_site(site) - - assert domain == "site123.b-cdn.net" - - -def test_generate_site_pages_success(): - site = Mock(spec=SiteDeployment) - site.id = 1 - site.custom_hostname = "www.example.com" - site.pull_zone_bcdn_hostname = "site123.b-cdn.net" - site.template_name = "modern" - - page_repo = Mock() - page_repo.exists = Mock(return_value=False) - page_repo.create = Mock(return_value=Mock(spec=SitePage, id=1)) - - template_service = Mock() - template_service.format_content = Mock(return_value="Full HTML Page") - - pages = generate_site_pages(site, page_repo, template_service) - - assert len(pages) == 3 - assert page_repo.create.call_count == 3 - - create_calls = page_repo.create.call_args_list - page_types_created = [call[1]["page_type"] for call in create_calls] - assert "about" in page_types_created - assert "contact" in page_types_created - assert "privacy" in page_types_created - - -def test_generate_site_pages_with_basic_template(): - site = Mock(spec=SiteDeployment) - site.id = 2 - site.custom_hostname = None - site.pull_zone_bcdn_hostname = "test-site.b-cdn.net" - site.template_name = "basic" - - page_repo = Mock() - page_repo.exists = Mock(return_value=False) - page_repo.create = Mock(return_value=Mock(spec=SitePage, id=1)) - - template_service = Mock() - template_service.format_content = Mock(return_value="Page") - - pages = generate_site_pages(site, page_repo, template_service) - - assert len(pages) == 3 - format_calls = template_service.format_content.call_args_list - - for call in format_calls: - assert call[1]["template_name"] == "basic" - - -def test_generate_site_pages_skips_existing_pages(): - site = Mock(spec=SiteDeployment) - site.id = 3 - site.custom_hostname = "www.test.com" - site.template_name = "modern" - - page_repo = Mock() - page_repo.exists = Mock(side_effect=[True, False, False]) - page_repo.create = Mock(return_value=Mock(spec=SitePage, id=1)) - - template_service = Mock() - template_service.format_content = Mock(return_value="Page") - - pages = generate_site_pages(site, page_repo, template_service) - - assert len(pages) == 2 - assert page_repo.create.call_count == 2 - - -def test_generate_site_pages_uses_default_template_when_none(): - site = Mock(spec=SiteDeployment) - site.id = 4 - site.custom_hostname = "www.example.com" - site.template_name = None - - page_repo = Mock() - page_repo.exists = Mock(return_value=False) - page_repo.create = Mock(return_value=Mock(spec=SitePage, id=1)) - - template_service = Mock() - template_service.format_content = Mock(return_value="Page") - - pages = generate_site_pages(site, page_repo, template_service) - - format_calls = template_service.format_content.call_args_list - - for call in format_calls: - assert call[1]["template_name"] == "basic" - - -def test_generate_site_pages_correct_content_structure(): - site = Mock(spec=SiteDeployment) - site.id = 5 - site.custom_hostname = "www.test.com" - site.template_name = "modern" - - page_repo = Mock() - page_repo.exists = Mock(return_value=False) - created_pages = [] - - def mock_create(**kwargs): - page = Mock(spec=SitePage, id=len(created_pages) + 1) - created_pages.append(kwargs) - return page - - page_repo.create = mock_create - - template_service = Mock() - template_service.format_content = Mock(return_value="Full Page") - - pages = generate_site_pages(site, page_repo, template_service) - - assert len(created_pages) == 3 - - for page_data in created_pages: - assert page_data["site_deployment_id"] == 5 - assert page_data["page_type"] in ["about", "contact", "privacy"] - assert page_data["content"] == "Full Page" - - -def test_generate_site_pages_page_titles(): - site = Mock(spec=SiteDeployment) - site.id = 6 - site.custom_hostname = "www.test.com" - site.template_name = "basic" - - page_repo = Mock() - page_repo.exists = Mock(return_value=False) - page_repo.create = Mock(return_value=Mock(spec=SitePage, id=1)) - - template_service = Mock() - template_service.format_content = Mock(return_value="Page") - - pages = generate_site_pages(site, page_repo, template_service) - - format_calls = template_service.format_content.call_args_list - - titles_used = [call[1]["title"] for call in format_calls] - assert "About Us" in titles_used - assert "Contact" in titles_used - assert "Privacy Policy" in titles_used - - -def test_generate_site_pages_error_handling(): - site = Mock(spec=SiteDeployment) - site.id = 7 - site.custom_hostname = "www.test.com" - site.template_name = "modern" - - page_repo = Mock() - page_repo.exists = Mock(return_value=False) - page_repo.create = Mock(side_effect=Exception("Database error")) - - template_service = Mock() - template_service.format_content = Mock(return_value="Page") - - with pytest.raises(Exception) as exc_info: - generate_site_pages(site, page_repo, template_service) - - assert "Database error" in str(exc_info.value)