from __future__ import annotations import pytest from companyatlas.connectors._util import ats_sensor_spec, country_code, job_fingerprint, parse_date, parse_location from companyatlas.connectors.generic_html import looks_like_name, parse_price, role_category from companyatlas.sdk import connector as C from companyatlas.taxonomy import Surface from companyatlas.urls import classify_url, detect_ats @pytest.mark.parametrize("url,anchor,surface", [ ("https://stripe.com/pricing", "Pricing", Surface.PRICING), ("https://stripe.com/jobs", "Jobs", Surface.CAREERS), ("https://boards.greenhouse.io/stripe", None, Surface.JOBS_BOARD), ("https://stripe.com/newsroom", "Newsroom", Surface.NEWSROOM), ("https://investors.example.com/", None, Surface.INVESTOR_RELATIONS), ("https://example.com/about/leadership", "Leadership", Surface.LEADERSHIP), ("https://example.com/legal/privacy", None, Surface.LEGAL_PRIVACY), ("https://example.com/blog/atom.xml", None, Surface.FEED), ("https://example.com/sitemap.xml", None, Surface.SITEMAP), ]) def test_classify_url(url: str, anchor: str | None, surface: Surface) -> None: s, conf = classify_url(url, anchor=anchor, canonical_domain="example.com") assert s == surface and conf >= 0.55 def test_connector_selection() -> None: assert C.for_surface("jobs_board", "https://boards-api.greenhouse.io/v1/boards/stripe/jobs?content=false").connector_id == "greenhouse-v1" assert C.for_surface("jobs_board", "https://api.lever.co/v0/postings/palantir?mode=json").connector_id == "lever-v1" assert C.for_surface("jobs_board", "https://nvidia.wd5.myworkdayjobs.com/wday/cxs/nvidia/NVIDIAExternalCareerSite/jobs").connector_id == "workday-v1" assert C.for_surface("feed", "https://x.com/blog/feed.xml").connector_id == "feed-v1" assert C.for_surface("sitemap", "https://x.com/sitemap_index.xml").connector_id == "sitemap-v1" assert C.for_surface("status", "https://status.x.com/api/v2/summary.json").connector_id == "statuspage-v1" assert C.for_surface("pricing", "https://x.com/pricing").connector_id == "generic-html-v1" assert C.for_surface("legal_terms", "https://x.com/terms").connector_id == "generic-html-v1" assert C.get("greenhouse-v0").connector_id == "greenhouse-v1" # older ids fall back to the family's newest # vendor connectors are pattern-bound: a non-ATS jobs_board URL never gets an ATS parser assert C.for_surface("jobs_board", "https://x.com/jobs").connector_id == "jsonld-jobs-v1" assert C.for_surface("status", "https://status.x.com/").connector_id == "generic-html-v1" def test_ats_detection_and_specs() -> None: assert detect_ats("https://boards.greenhouse.io/stripe") == ("greenhouse", "stripe") spec = ats_sensor_spec("workday", "nvidia", "https://nvidia.wd5.myworkdayjobs.com/en-US/NVIDIAExternalCareerSite") assert spec and spec[0].endswith("/wday/cxs/nvidia/NVIDIAExternalCareerSite/jobs") and spec[1] == "workday-v1" assert ats_sensor_spec("teamtailor", "acme", "https://career.acme.com/jobs")[0] == "https://career.acme.com/jobs.json" assert ats_sensor_spec("lever", "x", "https://jobs.eu.lever.co/x")[0].startswith("https://api.eu.lever.co/") @pytest.mark.parametrize("text,city,region,country,remote", [ ("San Francisco, CA", "San Francisco", "CA", None, None), # CA is ambiguous → no country guess ("Austin, TX", "Austin", "TX", "US", None), ("Toronto, ON, Canada", "Toronto", "ON", "CA", None), ("US, MA, Westford", "Westford", "MA", "US", None), ("Remote - US", None, None, "US", True), ("Germany", None, None, "DE", None), ("Paris, France (Hybrid)", "Paris", None, "FR", False), ("Dublin", None, None, None, None), ("London EC2M 2PF, United Kingdom", "London", None, "GB", None), ]) def test_parse_location(text: str, city: str | None, region: str | None, country: str | None, remote: bool | None) -> None: loc = parse_location(text) assert (loc["city"], loc["region"], loc["country"], loc["remote"]) == (city, region, country, remote) def test_country_code_and_dates() -> None: assert country_code("United Kingdom") == "GB" and country_code("usa") == "US" and country_code("DEU") == "DE" and country_code("Atlantis") is None assert parse_date("2026-09-10T09:00:00Z").isoformat().startswith("2026-09-10T09:00") assert parse_date(1711403416463).year == 2024 assert parse_date("Posted Yesterday") is None or parse_date("Posted Yesterday").year >= 2020 assert parse_date("garbage") is None def test_job_fingerprint_is_stable() -> None: a = job_fingerprint("Senior Engineer", "Toronto, ON", "123", None) b = job_fingerprint("senior engineer", "toronto, on", "123", "https://x/other") assert a == b and a != job_fingerprint("Senior Engineer", "Toronto, ON", "124", None) @pytest.mark.parametrize("title,category,is_exec", [ ("Chief Executive Officer", "ceo", True), ("Co-Founder & CEO", "founder", True), ("Chief Financial Officer", "cfo", True), ("SVP, Global Sales", "vp", False), ("Head of People", "head", False), ("Chairman of the Board", "chair", True), ("Independent Director", "board", False), ("Chief People Officer", "other", True), ("Software Engineer", "other", False), ]) def test_role_category(title: str, category: str, is_exec: bool) -> None: assert role_category(title) == (category, is_exec) def test_looks_like_name() -> None: assert looks_like_name("María García-López") and looks_like_name("Tom O'Neill") and looks_like_name("Dr. Jane Doe") assert not looks_like_name("Meet the team") and not looks_like_name("Chief Executive Officer") and not looks_like_name("Read more") @pytest.mark.parametrize("text,price,currency,period,unit,contact", [ ("$29 per month", 29.0, "USD", "month", None, False), ("€1.299,00 / Jahr", 1299.0, "EUR", "year", None, False), ("£12 per user / month, billed annually", 12.0, "GBP", "month", "user", False), ("From $1,000/year", 1000.0, "USD", "year", None, False), ("Contact sales", None, None, "contact", None, True), ("Free", 0.0, None, None, None, False), ("CHF 49 monthly", 49.0, "CHF", "month", None, False), ("$0.10 per 1,000 requests", 0.10, "USD", "usage", "1,000", False), ]) def test_parse_price(text: str, price: float | None, currency: str | None, period: str | None, unit: str | None, contact: bool) -> None: info = parse_price(text) assert info is not None assert (info["price"], info["currency"], info["billing_period"], info["unit"], info["contact_sales"]) == (price, currency, period, unit, contact) def test_parse_price_none_for_prose() -> None: assert parse_price("Up to 5 users and email support") is None