Fix CSRF 403, improve registry UI, add phonetic IDs
- Fix CSRF token handling for production: generate tokens with HMAC, set cookie via afterware, inject into HTMX requests via JS - Improve registry page: filter at top with better proportions, compact horizontal pill layout for facets - Add phonetic ID encoding (e.g., "tobi-kafu-meli") for animal display instead of truncated ULIDs - Remove "subadult" life stage (migration converts to juvenile) - Change "Death (natural)" outcome label to just "Death" - Show sex/life stage in animal picker alongside species/location 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# ABOUTME: Tests for ULID generation utility.
|
||||
# ABOUTME: Verifies that generated IDs are valid 26-character ULIDs and unique.
|
||||
# ABOUTME: Tests for ULID generation and phonetic encoding utilities.
|
||||
# ABOUTME: Verifies ULID format, uniqueness, and phonetic display encoding.
|
||||
|
||||
from animaltrack.id_gen import generate_id
|
||||
from animaltrack.id_gen import format_animal_id, generate_id, ulid_to_phonetic
|
||||
|
||||
|
||||
class TestGenerateId:
|
||||
@@ -28,3 +28,74 @@ class TestGenerateId:
|
||||
# Crockford base32 excludes I, L, O, U
|
||||
valid_chars = set("0123456789ABCDEFGHJKMNPQRSTVWXYZ")
|
||||
assert all(c in valid_chars for c in result)
|
||||
|
||||
|
||||
class TestUlidToPhonetic:
|
||||
"""Tests for the ulid_to_phonetic function."""
|
||||
|
||||
def test_returns_hyphenated_syllables(self):
|
||||
"""Result is hyphen-separated syllables."""
|
||||
ulid = generate_id()
|
||||
result = ulid_to_phonetic(ulid)
|
||||
parts = result.split("-")
|
||||
assert len(parts) == 4 # Default syllable count
|
||||
|
||||
def test_syllables_are_cv_format(self):
|
||||
"""Each syllable is consonant-vowel format."""
|
||||
ulid = generate_id()
|
||||
result = ulid_to_phonetic(ulid)
|
||||
consonants = set("bdfgklmnprstvwxz")
|
||||
vowels = set("aeiou")
|
||||
for syllable in result.split("-"):
|
||||
assert len(syllable) == 2
|
||||
assert syllable[0] in consonants
|
||||
assert syllable[1] in vowels
|
||||
|
||||
def test_same_ulid_produces_same_phonetic(self):
|
||||
"""Same ULID always produces the same phonetic."""
|
||||
ulid = "01ARZ3NDEKTSV4RRFFQ69G5FAV"
|
||||
result1 = ulid_to_phonetic(ulid)
|
||||
result2 = ulid_to_phonetic(ulid)
|
||||
assert result1 == result2
|
||||
|
||||
def test_different_ulids_produce_different_phonetics(self):
|
||||
"""Different ULIDs produce different phonetics (with high probability)."""
|
||||
ulids = [generate_id() for _ in range(100)]
|
||||
phonetics = [ulid_to_phonetic(u) for u in ulids]
|
||||
# All should be unique
|
||||
assert len(set(phonetics)) == 100
|
||||
|
||||
def test_custom_syllable_count(self):
|
||||
"""Can specify custom number of syllables."""
|
||||
ulid = generate_id()
|
||||
result = ulid_to_phonetic(ulid, syllable_count=3)
|
||||
assert len(result.split("-")) == 3
|
||||
|
||||
result = ulid_to_phonetic(ulid, syllable_count=5)
|
||||
assert len(result.split("-")) == 5
|
||||
|
||||
|
||||
class TestFormatAnimalId:
|
||||
"""Tests for the format_animal_id function."""
|
||||
|
||||
def test_returns_nickname_when_provided(self):
|
||||
"""Returns nickname if provided."""
|
||||
ulid = generate_id()
|
||||
result = format_animal_id(ulid, nickname="Daisy")
|
||||
assert result == "Daisy"
|
||||
|
||||
def test_returns_phonetic_when_no_nickname(self):
|
||||
"""Returns phonetic encoding when nickname is None."""
|
||||
ulid = generate_id()
|
||||
result = format_animal_id(ulid, nickname=None)
|
||||
# Should be phonetic format (4 syllables, hyphen-separated)
|
||||
parts = result.split("-")
|
||||
assert len(parts) == 4
|
||||
|
||||
def test_returns_phonetic_when_nickname_empty(self):
|
||||
"""Returns phonetic encoding when nickname is empty string."""
|
||||
ulid = generate_id()
|
||||
# Empty string is falsy, should use phonetic
|
||||
result = format_animal_id(ulid, nickname="")
|
||||
parts = result.split("-")
|
||||
assert len(parts) == 4
|
||||
|
||||
Reference in New Issue
Block a user