"""Tests for metadata parsing (tolerant of real-world dump quirks).""" from __future__ import annotations import pytest from sjaur.errors import CacheCorruptError from sjaur.metadata import format_timestamp, parse_packages def test_parse_minimal_entry(): packages, skipped = parse_packages([{"Name": "firefox"}]) assert skipped == 0 (package,) = packages assert package.name == "firefox" assert package.version == "" assert package.description == "" assert package.maintainer == "" assert package.votes == 0 assert package.popularity == 0.0 assert package.out_of_date is None assert package.is_orphan assert package.aur_url == "https://aur.archlinux.org/packages/firefox" def test_parse_full_entry(): entry = { "Name": "cower", "PackageBase": "cower", "Version": "14-2", "Description": "A simple AUR agent", "URL": "http://example.com", "NumVotes": 590, "Popularity": 24.59, "OutOfDate": None, "Maintainer": "falconindy", "FirstSubmitted": 1293676237, "LastModified": 1441804093, "Depends": ["curl", "openssl"], "MakeDepends": ["perl"], "Keywords": ["aur"], "License": ["MIT"], } packages, skipped = parse_packages([entry]) assert skipped == 0 (package,) = packages assert package.name == "cower" assert package.version == "14-2" assert package.votes == 590 assert package.popularity == 24.59 assert package.out_of_date is None assert package.maintainer == "falconindy" assert package.depends == ("curl", "openssl") assert package.make_depends == ("perl",) assert package.keywords == ("aur",) assert package.licenses == ("MIT",) assert not package.is_orphan def test_out_of_date_timestamp_is_kept(): packages, _ = parse_packages([{"Name": "x", "OutOfDate": 1720000000}]) assert packages[0].out_of_date == 1720000000 def test_missing_fields_are_omitted_by_server(): # The dump omits fields a package does not have; lists must be empty, not None. packages, _ = parse_packages([{"Name": "x", "Depends": None, "Keywords": []}]) assert packages[0].depends == () assert packages[0].keywords == () def test_malformed_entries_are_skipped_and_counted(): packages, skipped = parse_packages( [ {"Name": "ok"}, "not a dict", 42, {"Version": "1.0"}, # no Name {"Name": " "}, # blank Name None, ] ) assert [p.name for p in packages] == ["ok"] assert skipped == 5 def test_non_list_payload_is_rejected(): with pytest.raises(CacheCorruptError): parse_packages({"Name": "firefox"}) def test_type_mismatches_do_not_crash(): entry = { "Name": "weird", "Version": 123, "NumVotes": "many", "Popularity": None, "Depends": "python", # wrong container type "Keywords": [1, None, "ok"], } packages, _ = parse_packages([entry]) package = packages[0] assert package.version == "" assert package.votes == 0 assert package.popularity == 0.0 assert package.depends == () assert package.keywords == ("ok",) def test_format_timestamp(): assert format_timestamp(None) == "unknown" assert format_timestamp(0) == "unknown" assert format_timestamp(1441804093) == "2015-09-09 13:08 UTC"