""" Unit tests for imptune.services.inf_parser. Covers DRV-02 (INF parsing, token resolution, encoding detection, multi-model) and DRV-05 (unused file detection). """ from pathlib import Path import pytest from imptune.services.inf_parser import ParsedInf, _detect_encoding, parse_inf FIXTURES = Path(__file__).parent / "fixtures" # --------------------------------------------------------------------------- # _detect_encoding tests # --------------------------------------------------------------------------- def test_detect_encoding_utf16le(): """UTF-16 LE BOM (\xff\xfe) is detected as 'utf-16'.""" raw = b"\xff\xfe" + "[Version]\r\n".encode("utf-16-le") assert _detect_encoding(raw) == "utf-16" def test_detect_encoding_utf16be(): """UTF-16 BE BOM (\xfe\xff) is also detected as 'utf-16'.""" raw = b"\xfe\xff" + "[Version]\r\n".encode("utf-16-be") assert _detect_encoding(raw) == "utf-16" def test_detect_encoding_utf8bom(): """UTF-8 BOM (\xef\xbb\xbf) is detected as 'utf-8-sig'.""" raw = b"\xef\xbb\xbf" + b"[Version]\r\n" assert _detect_encoding(raw) == "utf-8-sig" def test_detect_encoding_ansi(): """Byte sequence with no BOM falls back to cp1252 (ANSI).""" raw = b"[Version]\r\nSignature=\"$Windows NT$\"\r\n" assert _detect_encoding(raw) == "cp1252" # --------------------------------------------------------------------------- # parse_inf – simple INF with literal driver description # --------------------------------------------------------------------------- SIMPLE_INF = """ [Version] Signature="$Windows NT$" Class=Printer [Manufacturer] Acme=AcmeModels,NTamd64 [AcmeModels.NTamd64] Acme SuperPrint 9000=Install,{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA} [Strings] """ def test_simple_driver_desc(): """parse_inf extracts literal DriverDesc from a Models section.""" result = parse_inf(SIMPLE_INF, "acme.inf", ["acme.inf", "acme.dll"]) assert "Acme SuperPrint 9000" in result.driver_names # --------------------------------------------------------------------------- # parse_inf – %TOKEN% resolution from [Strings] # --------------------------------------------------------------------------- TOKEN_INF = """ [Version] Signature="$Windows NT$" [Manufacturer] %MFG%=Models,NTamd64 [Models.NTamd64] %HP_DRIVER%=Install,{BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB} [Strings] MFG="HP" HP_DRIVER="HP LaserJet" """ def test_token_resolution(): """parse_inf resolves %TOKEN% references via the [Strings] section.""" result = parse_inf(TOKEN_INF, "hp.inf", ["hp.inf"]) assert "HP LaserJet" in result.driver_names # Raw token should NOT appear in the output assert "%HP_DRIVER%" not in result.driver_names # --------------------------------------------------------------------------- # parse_inf – UTF-16 LE fixture # --------------------------------------------------------------------------- def test_utf16_encoding(): """Reading a UTF-16 LE BOM fixture and passing decoded text to parse_inf produces correct driver_names.""" raw = (FIXTURES / "sample_utf16.inf").read_bytes() encoding = _detect_encoding(raw) assert encoding == "utf-16" text = raw.decode(encoding, errors="replace") result = parse_inf(text, "sample_utf16.inf", ["sample_utf16.inf"]) assert "Test LaserJet Pro" in result.driver_names # --------------------------------------------------------------------------- # parse_inf – multi-model INF (NTamd64 + undecorated) # --------------------------------------------------------------------------- def test_multi_model_inf(): """INF with both NTamd64 and undecorated sections returns deduplicated driver_names.""" text = (FIXTURES / "sample_multi_model.inf").read_text(encoding="cp1252") result = parse_inf(text, "multi.inf", ["multi.inf"]) # Both driver names must appear exactly once assert "Multi Printer 1000" in result.driver_names assert "Multi Printer 2000" in result.driver_names assert result.driver_names.count("Multi Printer 1000") == 1 assert result.driver_names.count("Multi Printer 2000") == 1 # --------------------------------------------------------------------------- # parse_inf – architecture detection # --------------------------------------------------------------------------- AMD64_INF = """ [Version] Signature="$Windows NT$" [Manufacturer] Mfg=Mfg.Models,NTamd64 [Mfg.Models.NTamd64] Some Driver=Install,{CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC} [Strings] """ ARM64_INF = """ [Version] Signature="$Windows NT$" [Manufacturer] Mfg=Mfg.Models,NTarm64 [Mfg.Models.NTarm64] Some Driver=Install,{CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC} [Strings] """ UNDECORATED_INF = """ [Version] Signature="$Windows NT$" [Manufacturer] Mfg=Mfg.Models [Mfg.Models] Some Driver=Install,{CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC} [Strings] """ MIXED_INF = """ [Version] Signature="$Windows NT$" [Manufacturer] Mfg=Mfg.Models,Mfg.Models.NTamd64 [Mfg.Models] Some Driver=Install,{CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC} [Mfg.Models.NTamd64] Some Driver=Install,{CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC} [Strings] """ def test_architecture_detection_amd64(): """NTamd64 decoration -> architecture='x64'.""" result = parse_inf(AMD64_INF, "amd64.inf", []) assert result.architecture == "x64" def test_architecture_detection_arm64(): """NTarm64 decoration -> architecture='arm64'.""" result = parse_inf(ARM64_INF, "arm64.inf", []) assert result.architecture == "arm64" def test_architecture_detection_undecorated(): """Undecorated section only -> architecture='x86'.""" result = parse_inf(UNDECORATED_INF, "x86.inf", []) assert result.architecture == "x86" def test_architecture_detection_mixed(): """Mixed architectures -> architecture=None (ambiguous).""" result = parse_inf(MIXED_INF, "mixed.inf", []) assert result.architecture is None # --------------------------------------------------------------------------- # parse_inf – .cat file detection # --------------------------------------------------------------------------- def test_cat_file_detection_present(): """zip_names containing a .cat file -> has_cat_file=True.""" result = parse_inf(SIMPLE_INF, "acme.inf", ["acme.inf", "driver.cat", "acme.dll"]) assert result.has_cat_file is True def test_cat_file_detection_absent(): """zip_names without a .cat file -> has_cat_file=False.""" result = parse_inf(SIMPLE_INF, "acme.inf", ["acme.inf", "acme.dll"]) assert result.has_cat_file is False # --------------------------------------------------------------------------- # parse_inf – unused files detection # --------------------------------------------------------------------------- def test_unused_files(): """ZIP members not referenced in INF text appear in unused_files.""" inf_text = """ [Version] Signature="$Windows NT$" [Manufacturer] Mfg=Mfg.Models [Mfg.Models] Some Driver=Install,{DDDDDDDD-DDDD-DDDD-DDDD-DDDDDDDDDDDD} [SourceDisksFiles] driver.inf=1 driver.dll=1 [Strings] """ zip_names = ["driver.inf", "driver.dll", "readme.txt"] result = parse_inf(inf_text, "driver.inf", zip_names) # readme.txt is not mentioned anywhere in inf_text assert "readme.txt" in result.unused_files # driver.inf and driver.dll ARE referenced in inf_text assert "driver.inf" not in result.unused_files assert "driver.dll" not in result.unused_files # --------------------------------------------------------------------------- # parse_inf – empty models section # --------------------------------------------------------------------------- EMPTY_MODELS_INF = """ [Version] Signature="$Windows NT$" [Manufacturer] Mfg=MfgModels [MfgModels] [Strings] """ def test_empty_models_section(): """INF with empty Models section returns empty driver_names list.""" result = parse_inf(EMPTY_MODELS_INF, "empty.inf", []) assert result.driver_names == []