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
This commit is contained in:
2026-04-10 11:55:41 +02:00
parent 9f5ee24811
commit 290106d573
5 changed files with 313 additions and 0 deletions
+281
View File
@@ -0,0 +1,281 @@
"""
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 == []