86 lines
3.3 KiB
Python
86 lines
3.3 KiB
Python
"""linkedin_utils: the slug vocabulary Find Talent matches applicants on.
|
|
|
|
Pure functions only — the DB annotation path in talent/matching.py reuses
|
|
exactly these, so the extraction cases here are the matching cases there.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from linkedin_utils import (
|
|
NO_SLUG,
|
|
primary_slug_from_text,
|
|
slug_from_url,
|
|
slugs_from_text,
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------- from URLs
|
|
|
|
def test_slug_from_normalized_profile_url():
|
|
assert slug_from_url("https://www.linkedin.com/in/jane-doe-123") == "jane-doe-123"
|
|
assert slug_from_url("https://linkedin.com/in/JaneDoe") == "janedoe"
|
|
|
|
|
|
def test_slug_ignores_subpaths_and_non_linkedin():
|
|
assert slug_from_url("https://www.linkedin.com/in/jane-doe/details/experience") == "jane-doe"
|
|
assert slug_from_url("https://github.com/in/jane-doe") is None
|
|
assert slug_from_url(None) is None
|
|
|
|
|
|
# ---------------------------------------------------------------- from CV text
|
|
|
|
def test_extracts_bare_and_schemed_links():
|
|
text = "Contact: linkedin.com/in/ali-raza-8a1b2c | ali@example.com"
|
|
assert slugs_from_text(text) == ["ali-raza-8a1b2c"]
|
|
text2 = "Profile: https://www.linkedin.com/in/Ali-Raza-8A1B2C/"
|
|
assert slugs_from_text(text2) == ["ali-raza-8a1b2c"]
|
|
|
|
|
|
def test_wrapped_and_spaced_pdf_urls():
|
|
# pypdf wraps the path; glyph-padded CVs insert spaces around slashes.
|
|
assert slugs_from_text("linkedin.com/in/\njane-doe") == ["jane-doe"]
|
|
assert slugs_from_text("linkedin.com / in / jane-doe") == ["jane-doe"]
|
|
assert slugs_from_text("https://pk.linkedin.com/in/jane-doe") == ["jane-doe"]
|
|
|
|
|
|
def test_html_href_and_mobile_path():
|
|
html = '<a href="https://www.linkedin.com/in/jane-doe">LinkedIn</a>'
|
|
assert slugs_from_text(html) == ["jane-doe"]
|
|
assert slugs_from_text("See linkedin.com/mwlite/in/jane-doe") == ["jane-doe"]
|
|
|
|
|
|
def test_profile_url_from_text_prefers_slug_then_short_link():
|
|
from linkedin_utils import profile_url_from_text
|
|
|
|
assert profile_url_from_text("linkedin.com/in/jane-doe") == (
|
|
"https://www.linkedin.com/in/jane-doe"
|
|
)
|
|
assert profile_url_from_text("Contact: lnkd.in/abc12XY") == "https://lnkd.in/abc12XY"
|
|
assert profile_url_from_text("no profile here") is None
|
|
|
|
|
|
def test_percent_encoding_and_trailing_punctuation():
|
|
# PDF extraction often percent-encodes hyphens and glues sentence dots on.
|
|
assert slugs_from_text("see linkedin.com/in/jane%2Ddoe.") == ["jane-doe"]
|
|
|
|
|
|
def test_legacy_pub_path_and_dedup():
|
|
text = "linkedin.com/pub/jane-doe and again https://linkedin.com/in/jane-doe"
|
|
assert slugs_from_text(text) == ["jane-doe"]
|
|
|
|
|
|
def test_primary_slug_sentinel_contract():
|
|
# "" (scanned, none found) must be distinct from None (never scanned):
|
|
# the lazy backfill filters on IS NULL and would otherwise rescan forever.
|
|
assert primary_slug_from_text("no links here") == NO_SLUG
|
|
assert primary_slug_from_text("") == NO_SLUG
|
|
assert primary_slug_from_text("linkedin.com/in/x-y") == "x-y"
|
|
|
|
|
|
def test_cv_and_profile_url_agree_on_the_key():
|
|
# The whole feature: a CV mention and the actor's normalized URL must
|
|
# produce the same key for the same person.
|
|
cv = "Portfolio — www.LinkedIn.com/in/Muhammad%2DTalha%2DAhmed."
|
|
profile_url = "https://www.linkedin.com/in/muhammad-talha-ahmed"
|
|
assert primary_slug_from_text(cv) == slug_from_url(profile_url)
|