mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 23:00:16 +00:00
a1f2228c1a
62 new tests covering: - Data loading and basic lookup (Hebrew/Greek entries) - Helper functions (definition, word, transliteration, KJV usage) - format_strongs_entry function - Search functionality (both languages, limits, case-insensitive) - Paginated listing (get_all_strongs) - Web routes (index, search, entry, Hebrew/Greek indexes, pagination) - API endpoints - Edge cases (boundaries, common words, derivation links) - Integration tests (search flow, navigation, breadcrumbs) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
491 lines
17 KiB
Python
491 lines
17 KiB
Python
"""
|
|
Tests for Strong's Concordance functionality.
|
|
|
|
Tests cover:
|
|
- Strong's data loading and lookup
|
|
- Hebrew and Greek entry retrieval
|
|
- Search functionality
|
|
- Pagination
|
|
- Web routes
|
|
- API endpoints
|
|
"""
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from kjvstudy_org.server import app
|
|
from kjvstudy_org.strongs import (
|
|
get_strongs_entry,
|
|
get_strongs_definition,
|
|
get_strongs_word,
|
|
get_strongs_transliteration,
|
|
get_strongs_kjv_usage,
|
|
format_strongs_entry,
|
|
search_strongs,
|
|
get_all_strongs,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def client():
|
|
"""Create test client"""
|
|
return TestClient(app)
|
|
|
|
|
|
class TestStrongsDataLoading:
|
|
"""Tests for Strong's data loading and basic lookup"""
|
|
|
|
def test_get_hebrew_entry(self):
|
|
"""Test retrieving a Hebrew Strong's entry"""
|
|
entry = get_strongs_entry("H1")
|
|
assert entry is not None
|
|
assert "lemma" in entry
|
|
|
|
def test_get_greek_entry(self):
|
|
"""Test retrieving a Greek Strong's entry"""
|
|
entry = get_strongs_entry("G1")
|
|
assert entry is not None
|
|
assert "lemma" in entry
|
|
|
|
def test_get_entry_case_insensitive(self):
|
|
"""Test Strong's lookup is case-insensitive"""
|
|
entry1 = get_strongs_entry("H430")
|
|
entry2 = get_strongs_entry("h430")
|
|
assert entry1 == entry2
|
|
|
|
def test_get_entry_with_whitespace(self):
|
|
"""Test Strong's lookup handles whitespace"""
|
|
entry = get_strongs_entry(" H1 ")
|
|
assert entry is not None
|
|
|
|
def test_get_invalid_entry(self):
|
|
"""Test invalid Strong's number returns None"""
|
|
entry = get_strongs_entry("X9999")
|
|
assert entry is None
|
|
|
|
def test_get_nonexistent_entry(self):
|
|
"""Test nonexistent Strong's number returns None"""
|
|
entry = get_strongs_entry("H99999")
|
|
assert entry is None
|
|
|
|
def test_get_empty_entry(self):
|
|
"""Test empty string returns None"""
|
|
entry = get_strongs_entry("")
|
|
assert entry is None
|
|
|
|
def test_get_none_entry(self):
|
|
"""Test None input returns None"""
|
|
entry = get_strongs_entry(None)
|
|
assert entry is None
|
|
|
|
|
|
class TestStrongsHelperFunctions:
|
|
"""Tests for Strong's helper functions"""
|
|
|
|
def test_get_definition(self):
|
|
"""Test getting Strong's definition"""
|
|
definition = get_strongs_definition("G26")
|
|
assert definition is not None
|
|
assert len(definition) > 0
|
|
|
|
def test_get_word(self):
|
|
"""Test getting original word (lemma)"""
|
|
word = get_strongs_word("G26")
|
|
assert word is not None
|
|
# Greek agape
|
|
assert "γάπ" in word or "agap" in word.lower()
|
|
|
|
def test_get_transliteration(self):
|
|
"""Test getting transliteration"""
|
|
translit = get_strongs_transliteration("G26")
|
|
assert translit is not None
|
|
# Transliteration is "agápē" - check for base characters
|
|
assert "ag" in translit.lower() and "p" in translit.lower()
|
|
|
|
def test_get_kjv_usage(self):
|
|
"""Test getting KJV usage"""
|
|
usage = get_strongs_kjv_usage("G26")
|
|
assert usage is not None
|
|
assert "love" in usage.lower()
|
|
|
|
def test_get_hebrew_transliteration(self):
|
|
"""Test Hebrew transliteration uses xlit field"""
|
|
translit = get_strongs_transliteration("H1")
|
|
assert translit is not None
|
|
|
|
def test_helper_functions_invalid_number(self):
|
|
"""Test helper functions handle invalid numbers"""
|
|
assert get_strongs_definition("X9999") is None
|
|
assert get_strongs_word("X9999") is None
|
|
assert get_strongs_transliteration("X9999") is None
|
|
assert get_strongs_kjv_usage("X9999") is None
|
|
|
|
|
|
class TestFormatStrongsEntry:
|
|
"""Tests for format_strongs_entry function"""
|
|
|
|
def test_format_greek_entry(self):
|
|
"""Test formatting Greek entry"""
|
|
entry = format_strongs_entry("G26")
|
|
assert entry is not None
|
|
assert entry["strongs"] == "G26"
|
|
assert entry["language"] == "Greek"
|
|
assert "word" in entry
|
|
assert "definition" in entry
|
|
|
|
def test_format_hebrew_entry(self):
|
|
"""Test formatting Hebrew entry"""
|
|
entry = format_strongs_entry("H430")
|
|
assert entry is not None
|
|
assert entry["strongs"] == "H430"
|
|
assert entry["language"] == "Hebrew"
|
|
assert "word" in entry
|
|
assert "definition" in entry
|
|
|
|
def test_format_entry_has_all_fields(self):
|
|
"""Test formatted entry has all expected fields"""
|
|
entry = format_strongs_entry("G26")
|
|
expected_fields = [
|
|
"strongs", "language", "word", "transliteration",
|
|
"definition", "kjv_usage", "derivation"
|
|
]
|
|
for field in expected_fields:
|
|
assert field in entry
|
|
|
|
def test_format_hebrew_has_pronunciation(self):
|
|
"""Test Hebrew entries include pronunciation"""
|
|
entry = format_strongs_entry("H1")
|
|
assert "pronunciation" in entry
|
|
|
|
def test_format_invalid_entry(self):
|
|
"""Test formatting invalid entry returns None"""
|
|
entry = format_strongs_entry("X9999")
|
|
assert entry is None
|
|
|
|
|
|
class TestSearchStrongs:
|
|
"""Tests for Strong's search functionality"""
|
|
|
|
def test_search_finds_results(self):
|
|
"""Test search returns results"""
|
|
results = search_strongs("love")
|
|
assert len(results) > 0
|
|
|
|
def test_search_result_structure(self):
|
|
"""Test search results have correct structure"""
|
|
results = search_strongs("love", limit=1)
|
|
assert len(results) > 0
|
|
result = results[0]
|
|
assert "strongs" in result
|
|
assert "language" in result
|
|
assert "word" in result
|
|
assert "definition" in result
|
|
|
|
def test_search_hebrew_only(self):
|
|
"""Test search Hebrew only"""
|
|
results = search_strongs("God", language="hebrew")
|
|
for result in results:
|
|
assert result["language"] == "Hebrew"
|
|
|
|
def test_search_greek_only(self):
|
|
"""Test search Greek only"""
|
|
results = search_strongs("love", language="greek")
|
|
for result in results:
|
|
assert result["language"] == "Greek"
|
|
|
|
def test_search_both_languages(self):
|
|
"""Test search both languages"""
|
|
results = search_strongs("peace", language="both")
|
|
languages = set(r["language"] for r in results)
|
|
# Should have at least one result
|
|
assert len(results) > 0
|
|
|
|
def test_search_respects_limit(self):
|
|
"""Test search respects limit parameter"""
|
|
results = search_strongs("the", limit=5)
|
|
assert len(results) <= 5
|
|
|
|
def test_search_case_insensitive(self):
|
|
"""Test search is case-insensitive"""
|
|
results1 = search_strongs("love")
|
|
results2 = search_strongs("LOVE")
|
|
assert len(results1) == len(results2)
|
|
|
|
def test_search_no_results(self):
|
|
"""Test search with no results"""
|
|
results = search_strongs("xyznonexistent123")
|
|
assert len(results) == 0
|
|
|
|
|
|
class TestGetAllStrongs:
|
|
"""Tests for paginated Strong's listing"""
|
|
|
|
def test_get_all_hebrew(self):
|
|
"""Test getting all Hebrew entries"""
|
|
data = get_all_strongs("hebrew", page=1, per_page=100)
|
|
assert "entries" in data
|
|
assert "total" in data
|
|
assert "page" in data
|
|
assert "total_pages" in data
|
|
assert len(data["entries"]) == 100
|
|
assert data["total"] > 8000 # Should have ~8674 Hebrew entries
|
|
|
|
def test_get_all_greek(self):
|
|
"""Test getting all Greek entries"""
|
|
data = get_all_strongs("greek", page=1, per_page=100)
|
|
assert len(data["entries"]) == 100
|
|
assert data["total"] > 5000 # Should have ~5523 Greek entries
|
|
|
|
def test_pagination_page_2(self):
|
|
"""Test pagination returns different entries"""
|
|
page1 = get_all_strongs("hebrew", page=1, per_page=10)
|
|
page2 = get_all_strongs("hebrew", page=2, per_page=10)
|
|
|
|
# Entries should be different
|
|
page1_ids = [e["strongs"] for e in page1["entries"]]
|
|
page2_ids = [e["strongs"] for e in page2["entries"]]
|
|
assert page1_ids != page2_ids
|
|
|
|
def test_pagination_total_pages(self):
|
|
"""Test total pages calculation"""
|
|
data = get_all_strongs("hebrew", page=1, per_page=100)
|
|
expected_pages = (data["total"] + 99) // 100
|
|
assert data["total_pages"] == expected_pages
|
|
|
|
def test_entries_sorted_by_number(self):
|
|
"""Test entries are sorted by Strong's number"""
|
|
data = get_all_strongs("hebrew", page=1, per_page=10)
|
|
numbers = [int(e["strongs"][1:]) for e in data["entries"]]
|
|
assert numbers == sorted(numbers)
|
|
|
|
def test_invalid_language(self):
|
|
"""Test invalid language returns empty"""
|
|
data = get_all_strongs("invalid", page=1)
|
|
assert data["entries"] == []
|
|
assert data["total"] == 0
|
|
|
|
def test_entry_has_required_fields(self):
|
|
"""Test paginated entries have required fields"""
|
|
data = get_all_strongs("greek", page=1, per_page=1)
|
|
entry = data["entries"][0]
|
|
assert "strongs" in entry
|
|
assert "language" in entry
|
|
assert "word" in entry
|
|
assert "transliteration" in entry
|
|
assert "definition" in entry
|
|
|
|
|
|
class TestStrongsWebRoutes:
|
|
"""Tests for Strong's web routes"""
|
|
|
|
def test_strongs_index_page(self, client):
|
|
"""Test Strong's index page loads"""
|
|
response = client.get("/strongs")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
assert "Strong" in content
|
|
|
|
def test_strongs_search_page(self, client):
|
|
"""Test Strong's search with query"""
|
|
response = client.get("/strongs?q=love")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
assert "love" in content.lower()
|
|
|
|
def test_strongs_entry_page_greek(self, client):
|
|
"""Test Greek Strong's entry page"""
|
|
response = client.get("/strongs/G26")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
assert "G26" in content
|
|
assert "Greek" in content
|
|
|
|
def test_strongs_entry_page_hebrew(self, client):
|
|
"""Test Hebrew Strong's entry page"""
|
|
response = client.get("/strongs/H430")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
assert "H430" in content
|
|
assert "Hebrew" in content
|
|
|
|
def test_strongs_entry_case_insensitive(self, client):
|
|
"""Test entry page handles lowercase"""
|
|
response = client.get("/strongs/g26")
|
|
assert response.status_code == 200
|
|
|
|
def test_strongs_invalid_entry(self, client):
|
|
"""Test invalid entry returns 404"""
|
|
response = client.get("/strongs/X9999")
|
|
assert response.status_code == 404
|
|
|
|
def test_strongs_hebrew_index(self, client):
|
|
"""Test Hebrew index page"""
|
|
response = client.get("/strongs/hebrew")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
assert "Hebrew" in content
|
|
assert "H1" in content
|
|
|
|
def test_strongs_greek_index(self, client):
|
|
"""Test Greek index page"""
|
|
response = client.get("/strongs/greek")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
assert "Greek" in content
|
|
assert "G1" in content
|
|
|
|
def test_strongs_hebrew_pagination(self, client):
|
|
"""Test Hebrew index pagination"""
|
|
response = client.get("/strongs/hebrew?page=2")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
assert "Page 2" in content
|
|
|
|
def test_strongs_greek_pagination(self, client):
|
|
"""Test Greek index pagination"""
|
|
response = client.get("/strongs/greek?page=2")
|
|
assert response.status_code == 200
|
|
|
|
def test_strongs_entry_has_verse_occurrences(self, client):
|
|
"""Test entry page shows verse occurrences"""
|
|
# Use a common word that should have occurrences
|
|
response = client.get("/strongs/G2316") # theos (God)
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
# Should have occurrences section if interlinear data exists
|
|
assert "Occurrence" in content or "verse" in content.lower()
|
|
|
|
|
|
class TestStrongsAPIRoutes:
|
|
"""Tests for Strong's API endpoints"""
|
|
|
|
def test_api_strongs_entry(self, client):
|
|
"""Test API Strong's entry endpoint"""
|
|
response = client.get("/api/strongs/G26")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["strongs"] == "G26"
|
|
assert data["language"] == "Greek"
|
|
|
|
def test_api_strongs_hebrew_entry(self, client):
|
|
"""Test API Hebrew Strong's entry"""
|
|
response = client.get("/api/strongs/H430")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["strongs"] == "H430"
|
|
assert data["language"] == "Hebrew"
|
|
|
|
def test_api_strongs_invalid(self, client):
|
|
"""Test API invalid Strong's number"""
|
|
response = client.get("/api/strongs/X9999")
|
|
assert response.status_code == 404
|
|
|
|
def test_api_strongs_search(self, client):
|
|
"""Test API Strong's search endpoint"""
|
|
response = client.get("/api/strongs?q=love")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "results" in data
|
|
assert len(data["results"]) > 0
|
|
|
|
|
|
class TestStrongsEdgeCases:
|
|
"""Edge case tests for Strong's functionality"""
|
|
|
|
def test_first_hebrew_entry(self, client):
|
|
"""Test first Hebrew entry (H1)"""
|
|
response = client.get("/strongs/H1")
|
|
assert response.status_code == 200
|
|
|
|
def test_last_hebrew_entry(self, client):
|
|
"""Test last Hebrew entry (H8674)"""
|
|
response = client.get("/strongs/H8674")
|
|
assert response.status_code == 200
|
|
|
|
def test_first_greek_entry(self, client):
|
|
"""Test first Greek entry (G1)"""
|
|
response = client.get("/strongs/G1")
|
|
assert response.status_code == 200
|
|
|
|
def test_last_greek_entry(self, client):
|
|
"""Test last Greek entry (G5624)"""
|
|
response = client.get("/strongs/G5624")
|
|
assert response.status_code == 200
|
|
|
|
def test_hebrew_boundary_plus_one(self, client):
|
|
"""Test beyond Hebrew range returns 404"""
|
|
response = client.get("/strongs/H9999")
|
|
assert response.status_code == 404
|
|
|
|
def test_greek_boundary_plus_one(self, client):
|
|
"""Test beyond Greek range returns 404"""
|
|
response = client.get("/strongs/G9999")
|
|
assert response.status_code == 404
|
|
|
|
def test_common_hebrew_words(self, client):
|
|
"""Test common Hebrew Strong's numbers"""
|
|
common = ["H430", "H3068", "H1", "H7965", "H2617"]
|
|
for num in common:
|
|
response = client.get(f"/strongs/{num}")
|
|
assert response.status_code == 200, f"Failed for {num}"
|
|
|
|
def test_common_greek_words(self, client):
|
|
"""Test common Greek Strong's numbers"""
|
|
common = ["G26", "G2316", "G3056", "G4102", "G5485"]
|
|
for num in common:
|
|
response = client.get(f"/strongs/{num}")
|
|
assert response.status_code == 200, f"Failed for {num}"
|
|
|
|
def test_strongs_with_derivation_links(self, client):
|
|
"""Test entry with derivation containing Strong's references"""
|
|
# H1580 has derivation with references to other Strong's numbers
|
|
response = client.get("/strongs/H1580")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
# Should have linked Strong's references in derivation
|
|
assert "/strongs/H" in content or "derivation" in content.lower()
|
|
|
|
|
|
class TestStrongsIntegration:
|
|
"""Integration tests for Strong's functionality"""
|
|
|
|
def test_search_then_view_entry(self, client):
|
|
"""Test searching and then viewing an entry"""
|
|
# Search for love
|
|
search_response = client.get("/strongs?q=love")
|
|
assert search_response.status_code == 200
|
|
|
|
# View G26 (agape)
|
|
entry_response = client.get("/strongs/G26")
|
|
assert entry_response.status_code == 200
|
|
content = entry_response.content.decode()
|
|
assert "love" in content.lower()
|
|
|
|
def test_browse_hebrew_then_entry(self, client):
|
|
"""Test browsing Hebrew index then viewing entry"""
|
|
# Browse Hebrew
|
|
index_response = client.get("/strongs/hebrew")
|
|
assert index_response.status_code == 200
|
|
|
|
# View first entry
|
|
entry_response = client.get("/strongs/H1")
|
|
assert entry_response.status_code == 200
|
|
|
|
def test_navigate_between_entries(self, client):
|
|
"""Test navigation between Strong's entries"""
|
|
response = client.get("/strongs/H100")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
|
|
# Should have navigation to adjacent entries
|
|
assert "H99" in content or "H101" in content
|
|
|
|
def test_strongs_page_has_breadcrumbs(self, client):
|
|
"""Test Strong's pages have breadcrumb navigation"""
|
|
response = client.get("/strongs/G26")
|
|
assert response.status_code == 200
|
|
content = response.content.decode()
|
|
|
|
# Should have link back to Strong's index
|
|
assert "/strongs" in content
|