121 lines
3.9 KiB
Python
121 lines
3.9 KiB
Python
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from constants.presentation import MAX_NUMBER_OF_SLIDES, MAX_OUTLINE_CONTENT_WORDS
|
|
from models.presentation_outline_model import PresentationOutlineModel, SlideOutlineModel
|
|
from utils.outline_limits import count_outline_words
|
|
from utils.outline_utils import (
|
|
_extract_outline_title,
|
|
get_images_for_slides_from_outline,
|
|
get_no_of_toc_required_for_n_outlines,
|
|
get_presentation_outline_model_with_toc,
|
|
get_presentation_title_from_presentation_outline,
|
|
)
|
|
|
|
|
|
def test_get_presentation_title_handles_prefixed_page_heading():
|
|
outline = PresentationOutlineModel(
|
|
slides=[SlideOutlineModel(content="## Page 1: Growth/Plan\\Roadmap\nBody")]
|
|
)
|
|
|
|
title = get_presentation_title_from_presentation_outline(outline)
|
|
assert title == "GrowthPlanRoadmap Body"
|
|
|
|
|
|
def test_get_presentation_title_for_empty_outline():
|
|
outline = PresentationOutlineModel(slides=[])
|
|
assert get_presentation_title_from_presentation_outline(outline) == "Untitled Presentation"
|
|
|
|
|
|
def test_slide_outline_content_is_trimmed_to_word_limit():
|
|
content = " ".join(
|
|
f"word{i}" for i in range(MAX_OUTLINE_CONTENT_WORDS + 3)
|
|
)
|
|
|
|
slide = SlideOutlineModel(content=content)
|
|
|
|
assert count_outline_words(slide.content) == MAX_OUTLINE_CONTENT_WORDS
|
|
assert f"word{MAX_OUTLINE_CONTENT_WORDS - 1}" in slide.content
|
|
assert f"word{MAX_OUTLINE_CONTENT_WORDS}" not in slide.content
|
|
|
|
|
|
def test_presentation_outline_rejects_more_than_max_slides():
|
|
with pytest.raises(ValidationError):
|
|
PresentationOutlineModel(
|
|
slides=[
|
|
SlideOutlineModel(content=f"## Slide {index}")
|
|
for index in range(MAX_NUMBER_OF_SLIDES + 1)
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("n_outlines", "title_slide", "target_total_slides", "expected"),
|
|
[
|
|
(0, True, None, 0),
|
|
(12, True, None, 2),
|
|
(12, False, None, 2),
|
|
(8, True, 25, 3),
|
|
],
|
|
)
|
|
def test_calculate_no_of_toc_required_for_n_outlines(
|
|
n_outlines: int,
|
|
title_slide: bool,
|
|
target_total_slides: int | None,
|
|
expected: int,
|
|
):
|
|
assert (
|
|
get_no_of_toc_required_for_n_outlines(
|
|
n_outlines=n_outlines,
|
|
title_slide=title_slide,
|
|
target_total_slides=target_total_slides,
|
|
)
|
|
== expected
|
|
)
|
|
|
|
|
|
def test_get_presentation_outline_model_with_toc_inserts_expected_slide_structure():
|
|
outline = PresentationOutlineModel(
|
|
slides=[
|
|
SlideOutlineModel(content="## Title slide"),
|
|
SlideOutlineModel(content="## Market Overview"),
|
|
SlideOutlineModel(content="## Product Strategy"),
|
|
]
|
|
)
|
|
|
|
with_toc = get_presentation_outline_model_with_toc(
|
|
outline=outline,
|
|
n_toc_slides=1,
|
|
title_slide=True,
|
|
)
|
|
|
|
assert len(with_toc.slides) == 4
|
|
toc_content = with_toc.slides[1].content
|
|
assert toc_content.startswith("## Table of Contents")
|
|
assert "Page number: 3, Title: Market Overview" in toc_content
|
|
assert "Page number: 4, Title: Product Strategy" in toc_content
|
|
|
|
|
|
def test_extract_outline_title_uses_heading_then_sentence_then_fallback():
|
|
assert _extract_outline_title("## Heading title\nBody") == "Heading title"
|
|
assert _extract_outline_title("First sentence. Second sentence.") == "First sentence."
|
|
assert _extract_outline_title(" \nline fallback\n") == "line fallback"
|
|
assert _extract_outline_title("") == "Slide"
|
|
|
|
|
|
def test_get_images_for_slides_from_outline_deduplicates_and_filters():
|
|
slides = [
|
|
SlideOutlineModel(
|
|
content=(
|
|
"Image https://cdn.example.com/a.png and duplicate "
|
|
"https://cdn.example.com/a.png and invalid https://example.com/nope.txt"
|
|
)
|
|
),
|
|
SlideOutlineModel(content="No URL here"),
|
|
]
|
|
|
|
extracted = get_images_for_slides_from_outline(slides)
|
|
|
|
assert extracted[0] == ["https://cdn.example.com/a.png"]
|
|
assert extracted[1] == []
|