Files
kennethreitz c624c89a54 Add comprehensive utility tests and clean up about page
- Add 87 new tests covering search, books, stories, biographies,
  red letter, helpers, commentary loader, interlinear, cross-references,
  PDF generation, topics, and reading plans modules
- Coverage improved from 75% to 78% (497 tests total)
- Add pytest-cov dependency for coverage reporting
- Remove Strong's Concordance, Study Guides, and Reading Plans
  links from the About page's Explore Further section

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 10:54:56 -05:00

829 lines
29 KiB
Python

"""
Tests for utility modules - search, books, stories, biographies, etc.
Targeting modules with lower test coverage.
"""
import pytest
from fastapi.testclient import TestClient
class TestSearchModule:
"""Tests for kjvstudy_org.utils.search module"""
def test_calculate_relevance_score_single_term(self):
"""Test relevance score calculation with single term"""
from kjvstudy_org.utils.search import calculate_relevance_score
text = "In the beginning God created the heaven and the earth."
score = calculate_relevance_score(text, ["beginning"])
assert score > 0
def test_calculate_relevance_score_multiple_terms(self):
"""Test relevance score with multiple search terms"""
from kjvstudy_org.utils.search import calculate_relevance_score
text = "For God so loved the world"
score = calculate_relevance_score(text, ["god", "loved"])
# Should get points for both terms
assert score >= 2.0
def test_calculate_relevance_score_word_boundaries(self):
"""Test that exact word matches get bonus"""
from kjvstudy_org.utils.search import calculate_relevance_score
text = "God is love"
score_exact = calculate_relevance_score(text, ["love"])
# Exact word match should have bonus
assert score_exact > 1.0
def test_calculate_relevance_score_multiple_occurrences(self):
"""Test that multiple occurrences increase score"""
from kjvstudy_org.utils.search import calculate_relevance_score
text = "The LORD is my shepherd. The LORD is good."
score = calculate_relevance_score(text, ["lord"])
# Should count both occurrences
assert score >= 2.0
def test_highlight_search_terms_basic(self):
"""Test basic search term highlighting"""
from kjvstudy_org.utils.search import highlight_search_terms
text = "For God so loved the world"
highlighted = highlight_search_terms(text, ["god"])
assert "<mark>" in highlighted
assert "</mark>" in highlighted
def test_highlight_search_terms_case_insensitive(self):
"""Test case insensitive highlighting"""
from kjvstudy_org.utils.search import highlight_search_terms
text = "The LORD is my shepherd"
highlighted = highlight_search_terms(text, ["lord"])
assert "<mark>" in highlighted
def test_highlight_search_terms_multiple(self):
"""Test highlighting multiple terms"""
from kjvstudy_org.utils.search import highlight_search_terms
text = "God is love"
highlighted = highlight_search_terms(text, ["god", "love"])
# Should have two mark tags
assert highlighted.count("<mark>") == 2
def test_ensure_search_index(self):
"""Test search index initialization"""
from kjvstudy_org.utils.search import ensure_search_index
# Should return True if FTS available, False otherwise
result = ensure_search_index()
assert isinstance(result, bool)
def test_perform_full_text_search_verse_reference(self):
"""Test search with verse reference"""
from kjvstudy_org.utils.search import perform_full_text_search
# Test with verse reference format
results = perform_full_text_search("John 3:16")
assert len(results) >= 1
assert results[0]["book"] == "John"
assert results[0]["chapter"] == 3
assert results[0]["verse"] == 16
def test_perform_full_text_search_regular_query(self):
"""Test regular keyword search"""
from kjvstudy_org.utils.search import perform_full_text_search
results = perform_full_text_search("love", limit=10)
assert len(results) > 0
# All results should have the search term (or stem)
for result in results:
text_lower = result["text"].lower()
# FTS may use stemming, so check for love/loved/loves
assert "love" in text_lower or "loved" in text_lower or "loves" in text_lower
class TestBooksModule:
"""Tests for kjvstudy_org.books module"""
def test_get_book_data_genesis(self):
"""Test getting data for Genesis"""
from kjvstudy_org.books import get_book_data
data = get_book_data("Genesis")
assert data is not None
assert "introduction" in data or "name" in data
def test_get_book_data_psalms(self):
"""Test getting data for Psalms"""
from kjvstudy_org.books import get_book_data
data = get_book_data("Psalms")
assert data is not None
def test_get_book_data_invalid(self):
"""Test getting data for non-existent book"""
from kjvstudy_org.books import get_book_data
data = get_book_data("NotABook")
assert data is None
def test_get_book_introduction(self):
"""Test getting book introduction"""
from kjvstudy_org.books import get_book_introduction
intro = get_book_introduction("Genesis")
# Should return string or None
assert intro is None or isinstance(intro, str)
def test_get_book_themes(self):
"""Test getting book themes"""
from kjvstudy_org.books import get_book_themes
themes = get_book_themes("Genesis")
# Should return list or None
assert themes is None or isinstance(themes, list)
def test_get_book_key_verses(self):
"""Test getting key verses"""
from kjvstudy_org.books import get_book_key_verses
verses = get_book_key_verses("John")
assert verses is None or isinstance(verses, list)
def test_get_book_outline(self):
"""Test getting book outline"""
from kjvstudy_org.books import get_book_outline
outline = get_book_outline("Romans")
assert outline is None or isinstance(outline, list)
def test_get_book_christ_in_book(self):
"""Test getting Christ in book section"""
from kjvstudy_org.books import get_book_christ_in_book
result = get_book_christ_in_book("Isaiah")
assert result is None or isinstance(result, str)
def test_get_book_metadata(self):
"""Test getting book metadata"""
from kjvstudy_org.books import get_book_metadata
metadata = get_book_metadata("Matthew")
if metadata:
assert "testament" in metadata or "name" in metadata
def test_get_book_metadata_invalid(self):
"""Test getting metadata for invalid book"""
from kjvstudy_org.books import get_book_metadata
metadata = get_book_metadata("FakeBook")
assert metadata is None
def test_get_all_books_metadata(self):
"""Test getting all books metadata"""
from kjvstudy_org.books import get_all_books_metadata
all_books = get_all_books_metadata()
assert isinstance(all_books, list)
# Should have 66 books
assert len(all_books) == 66
def test_has_book_data(self):
"""Test checking if book has data"""
from kjvstudy_org.books import has_book_data
assert has_book_data("Genesis") is True
assert has_book_data("NotABook") is False
def test_get_books_by_category(self):
"""Test getting books by category"""
from kjvstudy_org.books import get_books_by_category
categories = get_books_by_category()
assert isinstance(categories, dict)
# Should have multiple categories
assert len(categories) > 0
class TestStoriesModule:
"""Tests for kjvstudy_org.stories module"""
def test_load_all_stories(self):
"""Test loading all stories"""
from kjvstudy_org.stories import load_all_stories
stories = load_all_stories()
assert isinstance(stories, list)
def test_get_all_stories_flat(self):
"""Test getting flat list of stories"""
from kjvstudy_org.stories import get_all_stories_flat
stories = get_all_stories_flat()
assert isinstance(stories, list)
if len(stories) > 0:
# Each story should have category info attached
story = stories[0]
assert "category_name" in story or "slug" in story
def test_get_story_by_slug_exists(self):
"""Test getting existing story by slug"""
from kjvstudy_org.stories import get_all_stories_flat, get_story_by_slug
all_stories = get_all_stories_flat()
if len(all_stories) > 0:
first_slug = all_stories[0].get("slug")
if first_slug:
story = get_story_by_slug(first_slug)
assert story is not None
def test_get_story_by_slug_not_exists(self):
"""Test getting non-existent story"""
from kjvstudy_org.stories import get_story_by_slug
story = get_story_by_slug("not-a-real-story-slug-12345")
assert story is None
def test_get_stories_by_category(self):
"""Test getting stories by category"""
from kjvstudy_org.stories import load_all_stories, get_stories_by_category
categories = load_all_stories()
if len(categories) > 0:
cat_slug = categories[0].get("slug")
if cat_slug:
stories = get_stories_by_category(cat_slug)
assert isinstance(stories, list)
def test_get_stories_by_invalid_category(self):
"""Test getting stories from non-existent category"""
from kjvstudy_org.stories import get_stories_by_category
stories = get_stories_by_category("not-a-real-category")
assert stories == []
def test_get_category_by_slug_exists(self):
"""Test getting existing category"""
from kjvstudy_org.stories import load_all_stories, get_category_by_slug
categories = load_all_stories()
if len(categories) > 0:
slug = categories[0].get("slug")
if slug:
category = get_category_by_slug(slug)
assert category is not None
def test_get_category_by_slug_not_exists(self):
"""Test getting non-existent category"""
from kjvstudy_org.stories import get_category_by_slug
category = get_category_by_slug("fake-category-slug-xyz")
assert category is None
def test_get_story_count(self):
"""Test getting story count"""
from kjvstudy_org.stories import get_story_count
count = get_story_count()
assert isinstance(count, int)
assert count >= 0
def test_get_category_count(self):
"""Test getting category count"""
from kjvstudy_org.stories import get_category_count
count = get_category_count()
assert isinstance(count, int)
assert count >= 0
def test_get_categories(self):
"""Test getting categories"""
from kjvstudy_org.stories import get_categories
categories = get_categories()
assert isinstance(categories, list)
def test_refresh_stories(self):
"""Test refreshing story cache"""
from kjvstudy_org.stories import refresh_stories, get_categories
# Should not raise
refresh_stories()
categories = get_categories()
assert isinstance(categories, list)
class TestBiblicalBiographies:
"""Tests for kjvstudy_org.biblical_biographies module"""
def test_get_biography_abraham(self):
"""Test getting Abraham's biography"""
from kjvstudy_org.biblical_biographies import get_biography
bio = get_biography("Abraham")
assert bio is not None
assert isinstance(bio, dict)
def test_get_biography_david(self):
"""Test getting David's biography"""
from kjvstudy_org.biblical_biographies import get_biography
bio = get_biography("David")
assert bio is not None
def test_get_biography_not_exists(self):
"""Test getting non-existent biography"""
from kjvstudy_org.biblical_biographies import get_biography
bio = get_biography("Not A Real Person At All")
assert bio is None
def test_get_biography_via_alias(self):
"""Test getting biography via alias name"""
from kjvstudy_org.biblical_biographies import get_biography, BIOGRAPHY_ALIASES
# If there are aliases, test one
if BIOGRAPHY_ALIASES:
alias = next(iter(BIOGRAPHY_ALIASES.keys()))
bio = get_biography(alias)
# Should either find via alias or return None if canonical not found
# Just verify no crash
assert bio is None or isinstance(bio, dict)
def test_has_biography_exists(self):
"""Test checking existing biography"""
from kjvstudy_org.biblical_biographies import has_biography
assert has_biography("Abraham") is True
def test_has_biography_not_exists(self):
"""Test checking non-existent biography"""
from kjvstudy_org.biblical_biographies import has_biography
assert has_biography("Totally Made Up Person") is False
def test_has_biography_via_alias(self):
"""Test checking biography via alias"""
from kjvstudy_org.biblical_biographies import has_biography, BIOGRAPHY_ALIASES
if BIOGRAPHY_ALIASES:
alias = next(iter(BIOGRAPHY_ALIASES.keys()))
# Should return boolean
result = has_biography(alias)
assert isinstance(result, bool)
class TestRedLetterModule:
"""Tests for kjvstudy_org.red_letter module"""
def test_load_red_letter_verses(self):
"""Test loading red letter verses"""
from kjvstudy_org.red_letter import load_red_letter_verses
verses = load_red_letter_verses()
assert isinstance(verses, dict)
def test_get_christ_words_known_verse(self):
"""Test getting Christ's words from known red letter verse"""
from kjvstudy_org.red_letter import get_christ_words
# John 3:16 - Jesus speaking
words = get_christ_words("John", 3, 16)
# May or may not be marked as red letter depending on data
# Just verify no crash
assert words is None or isinstance(words, str)
def test_get_christ_words_not_red_letter(self):
"""Test verse without Christ's words"""
from kjvstudy_org.red_letter import get_christ_words
# Genesis 1:1 - Not Jesus speaking
words = get_christ_words("Genesis", 1, 1)
assert words is None
def test_wrap_red_letter_text_no_words(self):
"""Test wrapping text when no Christ words"""
from kjvstudy_org.red_letter import wrap_red_letter_text
text = "In the beginning God created the heaven and the earth."
result = wrap_red_letter_text(text, "Genesis", 1, 1)
# Should return unchanged if no red letter
assert result == text
def test_wrap_red_letter_text_full_verse(self):
"""Test wrapping full verse red letter"""
from kjvstudy_org.red_letter import wrap_red_letter_text, load_red_letter_verses
verses = load_red_letter_verses()
# Find a verse marked as 'full'
full_verse = None
for ref, words in verses.items():
if words == 'full':
full_verse = ref
break
if full_verse:
# Parse reference
parts = full_verse.rsplit(' ', 1)
if len(parts) == 2:
book = parts[0]
chap_verse = parts[1].split(':')
if len(chap_verse) == 2:
chapter, verse = int(chap_verse[0]), int(chap_verse[1])
text = "Some verse text"
result = wrap_red_letter_text(text, book, chapter, verse)
assert 'class="words-of-christ"' in result
class TestHelpersModule:
"""Tests for kjvstudy_org.utils.helpers module"""
def test_create_slug_basic(self):
"""Test basic slug creation"""
from kjvstudy_org.utils.helpers import create_slug
slug = create_slug("Hello World")
assert slug == "hello-world"
def test_create_slug_special_chars(self):
"""Test slug with special characters"""
from kjvstudy_org.utils.helpers import create_slug
slug = create_slug("God's Love!")
assert "'" not in slug
assert "!" not in slug
def test_create_slug_numbers(self):
"""Test slug with numbers"""
from kjvstudy_org.utils.helpers import create_slug
slug = create_slug("John 3:16")
assert isinstance(slug, str)
assert len(slug) > 0
def test_is_verse_reference_valid(self):
"""Test valid verse reference detection"""
from kjvstudy_org.utils.helpers import is_verse_reference
assert is_verse_reference("John 3:16") is True
assert is_verse_reference("Genesis 1:1") is True
assert is_verse_reference("1 John 4:8") is True
def test_is_verse_reference_invalid(self):
"""Test invalid verse reference detection"""
from kjvstudy_org.utils.helpers import is_verse_reference
assert is_verse_reference("hello world") is False
assert is_verse_reference("God is love") is False
def test_parse_verse_reference_valid(self):
"""Test parsing valid verse reference"""
from kjvstudy_org.utils.helpers import parse_verse_reference
result = parse_verse_reference("John 3:16")
assert result is not None
assert result["book"] == "John"
assert result["chapter"] == 3
assert result["verse"] == 16
def test_parse_verse_reference_invalid(self):
"""Test parsing invalid verse reference"""
from kjvstudy_org.utils.helpers import parse_verse_reference
result = parse_verse_reference("not a verse")
assert result is None
def test_get_verse_text(self):
"""Test getting verse text"""
from kjvstudy_org.utils.helpers import get_verse_text
text = get_verse_text("John", 3, 16)
assert isinstance(text, str)
assert len(text) > 0
def test_get_verse_text_invalid(self):
"""Test getting text for invalid verse"""
from kjvstudy_org.utils.helpers import get_verse_text
text = get_verse_text("FakeBook", 999, 999)
# Should return some fallback string
assert isinstance(text, str)
def test_get_daily_verse(self):
"""Test getting daily verse"""
from kjvstudy_org.utils.helpers import get_daily_verse
verse = get_daily_verse()
assert isinstance(verse, dict)
assert "book" in verse
assert "chapter" in verse
assert "verse" in verse
assert "text" in verse
def test_get_chapter_popularity_score(self):
"""Test getting chapter popularity score"""
from kjvstudy_org.utils.helpers import get_chapter_popularity_score
# Psalms 23 should be popular
score = get_chapter_popularity_score("Psalms", 23)
assert isinstance(score, int)
assert 1 <= score <= 10
def test_get_chapter_popularity_explanation(self):
"""Test getting chapter popularity explanation"""
from kjvstudy_org.utils.helpers import get_chapter_popularity_explanation
explanation = get_chapter_popularity_explanation("Psalms", 23)
assert isinstance(explanation, str)
assert len(explanation) > 0
def test_get_related_content(self):
"""Test getting related content"""
from kjvstudy_org.utils.helpers import get_related_content
related = get_related_content("John", 3, 16)
assert isinstance(related, dict)
assert "study_guides" in related
assert "topics" in related
class TestCommentaryLoaderModule:
"""Tests for kjvstudy_org.utils.commentary_loader module"""
def test_load_commentary(self):
"""Test loading commentary data"""
from kjvstudy_org.utils.commentary_loader import load_commentary
commentary = load_commentary()
assert isinstance(commentary, dict)
def test_load_commentary_flat(self):
"""Test loading flat commentary"""
from kjvstudy_org.utils.commentary_loader import load_commentary_flat
flat = load_commentary_flat()
assert isinstance(flat, dict)
# Keys should be like "Book Chapter:Verse"
if flat:
key = next(iter(flat.keys()))
assert ":" in key
def test_normalize_entry_valid(self):
"""Test normalizing valid entry"""
from kjvstudy_org.utils.commentary_loader import _normalize_entry
entry = {
"analysis": "Some analysis",
"historical": "Historical context",
"questions": ["Q1", "Q2"]
}
normalized = _normalize_entry(entry)
assert normalized["analysis"] == "Some analysis"
assert normalized["historical"] == "Historical context"
assert len(normalized["questions"]) == 2
def test_normalize_entry_with_historical_context(self):
"""Test normalizing entry with historical_context key"""
from kjvstudy_org.utils.commentary_loader import _normalize_entry
entry = {
"analysis": "Analysis",
"historical_context": "Context via alternative key"
}
normalized = _normalize_entry(entry)
assert normalized["historical"] == "Context via alternative key"
def test_normalize_entry_invalid(self):
"""Test normalizing non-dict entry"""
from kjvstudy_org.utils.commentary_loader import _normalize_entry
result = _normalize_entry("not a dict")
assert result["analysis"] == ""
assert result["historical"] == ""
assert result["questions"] == []
def test_slugify(self):
"""Test slugify function"""
from kjvstudy_org.utils.commentary_loader import _slugify
assert _slugify("Genesis") == "genesis"
assert _slugify("1 John") == "1_john"
assert _slugify("Song of Solomon") == "song_of_solomon"
class TestInterlinearLoader:
"""Tests for kjvstudy_org.interlinear_loader module"""
def test_get_interlinear_data_genesis(self):
"""Test getting interlinear data for Genesis 1:1"""
from kjvstudy_org.interlinear_loader import get_interlinear_data
data = get_interlinear_data("Genesis", 1, 1)
# Returns list of word data or None
assert data is None or isinstance(data, (dict, list))
if isinstance(data, list) and len(data) > 0:
# Each item should have word info
assert "original" in data[0] or "english" in data[0]
def test_get_interlinear_data_john(self):
"""Test getting interlinear data for John 1:1"""
from kjvstudy_org.interlinear_loader import get_interlinear_data
data = get_interlinear_data("John", 1, 1)
assert data is None or isinstance(data, (dict, list))
def test_get_interlinear_data_invalid(self):
"""Test getting interlinear data for invalid verse"""
from kjvstudy_org.interlinear_loader import get_interlinear_data
data = get_interlinear_data("FakeBook", 999, 999)
assert data is None
class TestCrossReferencesModule:
"""Tests for kjvstudy_org.cross_references module"""
def test_get_cross_references_john_3_16(self):
"""Test getting cross references for John 3:16"""
from kjvstudy_org.cross_references import get_cross_references
refs = get_cross_references("John", 3, 16)
assert isinstance(refs, list)
def test_get_cross_references_genesis(self):
"""Test getting cross references for Genesis 1:1"""
from kjvstudy_org.cross_references import get_cross_references
refs = get_cross_references("Genesis", 1, 1)
assert isinstance(refs, list)
def test_get_cross_references_invalid(self):
"""Test getting cross references for invalid verse"""
from kjvstudy_org.cross_references import get_cross_references
refs = get_cross_references("NotABook", 999, 999)
assert isinstance(refs, list)
assert len(refs) == 0
class TestPdfModule:
"""Tests for kjvstudy_org.utils.pdf module"""
def test_weasyprint_available_flag(self):
"""Test that WEASYPRINT_AVAILABLE flag is set"""
from kjvstudy_org.utils.pdf import WEASYPRINT_AVAILABLE
assert isinstance(WEASYPRINT_AVAILABLE, bool)
def test_render_html_to_pdf_when_available(self):
"""Test PDF rendering when weasyprint available"""
from kjvstudy_org.utils.pdf import WEASYPRINT_AVAILABLE, render_html_to_pdf
if WEASYPRINT_AVAILABLE:
html = "<html><body><h1>Test</h1></body></html>"
pdf_buffer = render_html_to_pdf(html)
assert pdf_buffer is not None
# Should be at position 0
assert pdf_buffer.tell() == 0
# Should have PDF content
content = pdf_buffer.read()
assert content.startswith(b'%PDF')
else:
# Should raise RuntimeError when not available
with pytest.raises(RuntimeError):
render_html_to_pdf("<html></html>")
def test_render_html_to_pdf_async(self):
"""Test async PDF rendering function exists"""
from kjvstudy_org.utils.pdf import WEASYPRINT_AVAILABLE, render_html_to_pdf_async
import asyncio
# Just verify the async function exists and is callable
assert callable(render_html_to_pdf_async)
# If weasyprint available, test via sync wrapper
if WEASYPRINT_AVAILABLE:
html = "<html><body><p>Async Test</p></body></html>"
# Run async function synchronously for testing
loop = asyncio.new_event_loop()
try:
pdf_buffer = loop.run_until_complete(render_html_to_pdf_async(html))
assert pdf_buffer is not None
content = pdf_buffer.read()
assert content.startswith(b'%PDF')
finally:
loop.close()
class TestTopicsModule:
"""Tests for kjvstudy_org.topics module"""
def test_get_all_topics(self):
"""Test getting all topics"""
from kjvstudy_org.topics import get_all_topics
topics = get_all_topics()
assert isinstance(topics, dict)
assert len(topics) > 0
def test_get_topic_valid(self):
"""Test getting valid topic"""
from kjvstudy_org.topics import get_all_topics, get_topic
all_topics = get_all_topics()
if all_topics:
topic_name = next(iter(all_topics.keys()))
topic = get_topic(topic_name)
assert topic is not None
def test_get_topic_invalid(self):
"""Test getting invalid topic"""
from kjvstudy_org.topics import get_topic
topic = get_topic("not_a_real_topic_xyz123")
assert topic is None
class TestStoriesRoutes:
"""Tests for kjvstudy_org.routes.stories module"""
def test_stories_index_page(self, client):
"""Test stories index page loads"""
response = client.get("/stories")
assert response.status_code == 200
assert "Stories" in response.text or "stories" in response.text.lower()
def test_stories_category_page(self, client):
"""Test stories category page"""
from kjvstudy_org.stories import load_all_stories
categories = load_all_stories()
if categories:
slug = categories[0].get("slug")
if slug:
response = client.get(f"/stories/category/{slug}")
# Should return 200 or redirect
assert response.status_code in [200, 301, 302, 307, 404]
def test_stories_invalid_category(self, client):
"""Test invalid category returns 404"""
response = client.get("/stories/category/not-a-real-category-xyz")
assert response.status_code == 404
def test_story_detail_page(self, client):
"""Test individual story page"""
from kjvstudy_org.stories import get_all_stories_flat
stories = get_all_stories_flat()
if stories:
slug = stories[0].get("slug")
if slug:
response = client.get(f"/story/{slug}")
# Should return 200 or 404
assert response.status_code in [200, 404]
def test_story_invalid_slug(self, client):
"""Test invalid story slug returns 404"""
response = client.get("/story/not-a-real-story-slug-xyz")
assert response.status_code == 404
class TestReadingPlansModule:
"""Tests for kjvstudy_org.reading_plans module"""
def test_get_all_plans(self):
"""Test getting all reading plans"""
from kjvstudy_org.reading_plans import get_all_plans
plans = get_all_plans()
assert isinstance(plans, dict)
assert len(plans) > 0
def test_get_plan_by_id(self):
"""Test getting reading plan by ID"""
from kjvstudy_org.reading_plans import get_all_plans, get_plan
plans = get_all_plans()
if plans:
plan_id = next(iter(plans.keys()))
plan = get_plan(plan_id)
assert plan is not None
def test_get_plan_invalid_id(self):
"""Test getting reading plan with invalid ID"""
from kjvstudy_org.reading_plans import get_plan
plan = get_plan("not-a-real-plan-id-xyz")
assert plan is None
def test_get_plan_summary(self):
"""Test getting plan summary"""
from kjvstudy_org.reading_plans import get_plan_summary
summary = get_plan_summary()
assert isinstance(summary, list)
assert len(summary) > 0
# Each item should have name and id
if summary:
assert "name" in summary[0] or "id" in summary[0]