#!/usr/bin/env python3 """Unit tests for scripts/qbz-add-to-steam (binary VDF parser/serializer, shortcut dedupe, appid formula, configset patching). Stdlib unittest only.""" import importlib.util import struct import unittest import zlib from importlib.machinery import SourceFileLoader from pathlib import Path SCRIPT = Path(__file__).resolve().parent / "qbz-add-to-steam" _loader = SourceFileLoader("qbz_add_to_steam", str(SCRIPT)) spec = importlib.util.spec_from_loader("qbz_add_to_steam", _loader) qats = importlib.util.module_from_spec(spec) spec.loader.exec_module(qats) def make_fixture(): """A real-world-shaped shortcuts.vdf: two entries (one non-QBZ with quirky/unknown fields), nested tags map, non-ASCII strings.""" other_entry = [ qats.fld_u32("appid", 0x81234567), qats.fld_str("appname", "Cool Game — déjà vu"), qats.fld_str("Exe", '"/opt/cool game/run.sh"'), qats.fld_str("StartDir", '"/opt/cool game/"'), qats.fld_str("icon", ""), qats.fld_str("ShortcutPath", ""), qats.fld_str("LaunchOptions", "gamemoderun %command%"), qats.fld_u32("IsHidden", 0), qats.fld_u32("AllowDesktopConfig", 1), qats.fld_u32("AllowOverlay", 1), qats.fld_u32("OpenVR", 0), qats.fld_u32("Devkit", 0), qats.fld_str("DevkitGameID", ""), qats.fld_u32("DevkitOverrideAppID", 0), qats.fld_u32("LastPlayTime", 1753000000), qats.fld_str("FlatpakAppID", ""), qats.fld_str("sortas", "cool game"), # newer Steam field qats.fld_map("tags", [qats.fld_str("0", "favorite"), qats.fld_str("1", "deck")]), qats.fld_str("SomeFutureField", "w\xe9ird\xff"), # unknown field ] qbz_entry = qats.build_entry("/usr/bin/qbz", "env X=1 %command%", qats.shortcut_appid("/usr/bin/qbz")) fields = [qats.fld_map("shortcuts", [ qats.fld_map("0", other_entry), qats.fld_map("1", qbz_entry), ])] return fields class TestRoundTrip(unittest.TestCase): def test_roundtrip_byte_identical(self): fields = make_fixture() blob = qats.serialize_vdf(fields, True) parsed, ended = qats.parse_vdf(blob) self.assertTrue(ended) self.assertEqual(qats.serialize_vdf(parsed, ended), blob) def test_roundtrip_preserves_trailing_end_marker(self): fields = make_fixture() with_root_end = qats.serialize_vdf(fields, True) without_root_end = qats.serialize_vdf(fields, False) self.assertEqual(with_root_end, without_root_end + b"\x08") p1, e1 = qats.parse_vdf(with_root_end) p2, e2 = qats.parse_vdf(without_root_end) self.assertTrue(e1) self.assertFalse(e2) self.assertEqual(p1, p2) def test_real_file_shape(self): # header is \x00shortcuts\x00, file ends with \x08\x08 blob = qats.serialize_vdf(make_fixture(), True) self.assertTrue(blob.startswith(b"\x00shortcuts\x00")) self.assertTrue(blob.endswith(b"\x08\x08")) def test_parse_types(self): fields, _ = qats.parse_vdf(qats.serialize_vdf(make_fixture(), True)) top = qats.field_get(fields, "shortcuts") self.assertIsNotNone(top) self.assertEqual(top[0], qats.T_MAP) e0 = top[2][0][2] appid = qats.field_get(e0, "appid") self.assertEqual(appid[0], qats.T_U32) self.assertEqual(struct.unpack("