The backend had zero tests. This adds 33, all pure (no DB, no network), plus the harness to run them in the gate: - backend/Dockerfile.test: the app's deps + pinned pytest/ruff, code bind-mounted at run time so it always tests the working tree. Isolated from the prod Dockerfile, so the published image never carries test tooling. - requirements-dev.txt: pytest==8.4.2, ruff==0.15.21 (the version the gate already runs) — the backend lane is now pinned, not just host-global. - tests: normalize_title (de-shout, hashtag strip, emoji drop, trilingual letters survive); storage sanitize/rel_path/download_filename and the safe_abs_path traversal guard (../ and absolute-path escapes rejected — verified by mutation); links HMAC grants (round-trip, wrong-token, tampered sig/exp, expiry) + is_expired; a DB-free app-assembly smoke (every router wires up, OpenAPI generates). DB-backed router smoke (auth/feed/downloads) needs a test Postgres + migrations — deferred. useCardPager needs hook-test infra (jsdom/renderHook) — deferred.
42 lines
1.5 KiB
Python
42 lines
1.5 KiB
Python
"""normalize_title: de-shout / de-clutter video titles without mangling non-English text."""
|
|
from app.titles import normalize_title
|
|
|
|
|
|
def test_empty_and_whitespace_pass_through_unchanged():
|
|
assert normalize_title(None) is None
|
|
assert normalize_title("") == ""
|
|
assert normalize_title(" ") == " "
|
|
|
|
|
|
def test_plain_title_is_left_alone():
|
|
assert normalize_title("How I built a boat") == "How I built a boat"
|
|
|
|
|
|
def test_shouting_title_is_de_capsed_and_first_letter_kept_upper():
|
|
# >=2 all-caps runs and >=50% caps → treated as shouting: title-case the long words.
|
|
out = normalize_title("THIS IS A HUGE ANNOUNCEMENT")
|
|
assert out is not None
|
|
assert out == out[0].upper() + out[1:] # first alpha char stays capitalized
|
|
assert "HUGE" not in out and "ANNOUNCEMENT" not in out
|
|
|
|
|
|
def test_trailing_hashtags_are_stripped():
|
|
assert normalize_title("Great cooking video #food #yummy") == "Great cooking video"
|
|
|
|
|
|
def test_emoji_and_symbols_are_dropped():
|
|
assert "🔥" not in (normalize_title("Fire recipe 🔥🔥") or "")
|
|
|
|
|
|
def test_repeated_punctuation_is_collapsed():
|
|
assert normalize_title("Wait what!!!!") == "Wait what!"
|
|
|
|
|
|
def test_accented_non_english_letters_survive():
|
|
# Siftlode is trilingual — Hungarian/German letters must not be ASCII-folded away.
|
|
for title in ["Gulyásleves főzés", "Über die Straße"]:
|
|
out = normalize_title(title) or ""
|
|
for ch in "áöüőűé":
|
|
if ch in title:
|
|
assert ch in out
|