0922cc1d68
- Struktur gemäß §8 (Eigentumsgrenzen), PLAN.md als normative Basis - Pflichtdokumente: STATUS.md, ERRORS.md, TEST_REPORT.md, CHANGELOG.md, ADRs - ADR-0001 Python 3.13-Pin, ADR-0002 GStreamer 1.28.6-Pin (Windows), ADR-0003 IPC TCP+MessagePack v1 - Kernpakete: hms_protocol, hms_domain, hms_parameter, hms_artnet, hms_adaptive, hms_capabilities, hms_plugin_sdk - Renderer-Spike: D3D11-Primärpfad + Dev-GL-Pfad (§36 Nr. 4-5) - Control Core: FastAPI REST + WebSocket (§36 Nr. 9) - Beispielplugins: Passthrough + Gaussian Blur (3 Adaptive-Quality- Varianten, HLSL/GLSL/GLES) - Tools: Art-Net-Emulator, Fixture-Generator (Master32/Layer64-CSV), Capability-Probe - JSON-Schemas: IPC, Plugin, Projekt, Cluster - 121 Unit-/Integrationstests grün, Ruff grün Gate 0 bleibt offen: Hardwaremessungen nur auf echter Windows-Referenz- hardware gültig (§29.7, §33).
67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
"""Unit-Tests Fixture-Generator (PLAN.md §16.3, §16.4)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import csv
|
|
from pathlib import Path
|
|
|
|
from fixture_generator import LAYER64, MASTER32, write_csv
|
|
|
|
|
|
def test_master32_has_exactly_32_contiguous_channels() -> None:
|
|
assert len(MASTER32) == 32
|
|
assert [row[0] for row in MASTER32] == list(range(1, 33))
|
|
|
|
|
|
def test_layer64_has_exactly_64_contiguous_channels() -> None:
|
|
assert len(LAYER64) == 64
|
|
assert [row[0] for row in LAYER64] == list(range(1, 65))
|
|
|
|
|
|
def test_master32_key_channels_match_plan() -> None:
|
|
by_channel = {row[0]: row for row in MASTER32}
|
|
assert "Blackout" in by_channel[3][1] # Kanal 3 Blackout
|
|
assert "Preset Recall" in by_channel[8][1] # Kanal 8 steigende Flanke
|
|
assert "Tap Tempo" in by_channel[16][1] # Kanal 16 Tap
|
|
|
|
|
|
def test_layer64_key_channels_match_plan() -> None:
|
|
by_channel = {row[0]: row for row in LAYER64}
|
|
assert "Layer Enable" in by_channel[1][1]
|
|
assert "Opacity" in by_channel[2][1]
|
|
assert "Load/Commit" in by_channel[9][1]
|
|
assert "Blend Mode" in by_channel[21][1]
|
|
assert "FX1 Enable" in by_channel[41][1]
|
|
assert "FX2 Enable" in by_channel[52][1]
|
|
assert "Retrigger" in by_channel[63][1]
|
|
|
|
|
|
def test_layer64_fx_parameter_blocks() -> None:
|
|
by_channel = {row[0]: row for row in LAYER64}
|
|
for slot in range(1, 9):
|
|
assert f"P{slot}" in by_channel[43 + slot][1]
|
|
assert f"P{slot}" in by_channel[54 + slot][1]
|
|
|
|
|
|
def test_eight_layers_fit_exactly_one_universe() -> None:
|
|
# §16.2: „Acht Layer entsprechen damit exakt einem DMX-Universe“
|
|
assert 8 * len(LAYER64) == 512
|
|
|
|
|
|
def test_write_csv_output(tmp_path: Path) -> None:
|
|
out = tmp_path / "layer64" / "layer64.csv"
|
|
write_csv(LAYER64, out)
|
|
with open(out, encoding="utf-8", newline="") as fh:
|
|
rows = list(csv.reader(fh))
|
|
assert rows[0] == ["channel", "parameter", "resolution_behavior"]
|
|
assert len(rows) == 65 # Header + 64
|
|
assert rows[1] == ["1", "Layer Enable", "Schalter"]
|
|
|
|
|
|
def test_write_csv_rejects_gaps(tmp_path: Path) -> None:
|
|
import pytest
|
|
|
|
broken = [(1, "a", "x"), (3, "b", "y")] # Kanal 2 fehlt
|
|
with pytest.raises(ValueError, match="contiguous"):
|
|
write_csv(broken, tmp_path / "broken.csv") # ValueError vor dem Schreiben
|