Files
ImpTune/tests/test_inf_parser.py
T
kawa 290106d573 test(02-01): add failing tests for INF parser
- 11 test functions covering all DRV-02 and DRV-05 behaviors
- _detect_encoding tests for UTF-16 LE, UTF-16 BE, UTF-8 BOM, ANSI/cp1252
- parse_inf tests: literal DriverDesc, %TOKEN% resolution, UTF-16 fixture
- Multi-model deduplication, architecture detection (x64/arm64/x86/mixed)
- .cat file detection, unused files detection, empty models section
- INF fixtures: sample.inf, sample_utf16.inf (UTF-16 LE BOM), sample_multi_model.inf
- imptune/services/__init__.py package marker
2026-04-10 11:55:41 +02:00

282 lines
7.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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 == []