#!/usr/bin/env python3 # Copyright (C) 2026 Danilo M. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Self-check: run `python3 test_changelog.py`. Fakes the mirror, exercises parsing, caching and the stale fallback.""" import io import urllib.request import slackware_changelog as c SAMPLE = """Mon Sep 7 22:56:39 UTC 2026 a/util-linux-2.42.3-x86_64-1.txz: Upgraded. This update fixes bugs and security issues. For more information, see: https://www.cve.org/CVERecord?id=CVE-2026-76642 https://www.cve.org/CVERecord?id=CVE-2026-78410 (* Security fix *) l/cryptopp-8.9.0-x86_64-3.txz: Rebuilt. Fixed library location. Thanks to Petri Kaukasoina. n/foo-1.0-x86_64-1.txz: Added. n/bar-1.0-x86_64-1.txz: Removed. +--------------------------+ Sun Sep 6 00:00:00 UTC 2026 a/should-not-appear-1.0-x86_64-1.txz: Upgraded. """ fail = [False] def fake_urlopen(url, timeout=0): if fail[0]: raise OSError("mirror down") return io.BytesIO(SAMPLE.encode()) urllib.request.urlopen = fake_urlopen d = c.parse(SAMPLE) assert d["date"] == "Mon Sep 7 22:56:39 UTC 2026", d["date"] assert (d["packages"], d["upgraded"], d["rebuilt"], d["added"], d["removed"]) == (4, 1, 1, 1, 1), d assert d["security"] == 1, d assert d["cves"] == ["CVE-2026-76642", "CVE-2026-78410"], d["cves"] assert "should-not-appear" not in d["entry"], "the next entry leaked in" assert d["package_list"][0] == {"name": "a/util-linux-2.42.3-x86_64-1.txz", "action": "upgraded"}, d["package_list"][0] assert "1 upgraded" in d["summary"], d["summary"] # An indented note that ends in a word plus a period is not a package line. assert all("Thanks to" not in p["name"] for p in d["package_list"]), d["package_list"] # Cache holds, and a failing refresh keeps serving the last good entry. first = c.fetch() assert first["date"] == d["date"] fail[0] = True stale = c.fetch(force=True) assert stale["date"] == d["date"], "lost the cached entry on a failed refresh" assert "mirror down" in stale["stale"], stale.get("stale") # /top: flat keys, prefix and .txz stripped, overflow line when truncated. t = c.top(d, n=2) assert t["pkg1"] == "util-linux-2.42.3-x86_64-1 - upgraded", t["pkg1"] assert t["pkg3"] == "... and 2 more", t assert t["packages"] == 4 and t["date"] == d["date"], t assert "pkg4" not in t, t assert "pkg5" not in c.top(d, n=10), "overflow line on a complete list" assert c.top(d, n=10)["pkg4"] == "bar-1.0-x86_64-1 - removed", c.top(d, n=10) page = c.render(c._cache["data"]) assert "Sep 7" in page and "util-linux" in page assert "