ipin-vr/tests/test_export.py
Oskar Kapala 921a85d30b Add export subcommand and Unity PoC-1 scaffold (ONDEVICE §4)
Python (ipin_vr/export.py):
- generate_bank(): levels 1–2 enumerated exhaustively (120/720 combos),
  level 3 random with dedup; all deduplicated per-level
- run_export(): CLI --per-level / --out / --seed flags per ONDEVICE §4.1
- cli.py routes "export" subcommand before session args (backward-compat)
- 14 new tests: format, dedup for all 3 levels, space caps (L1=120, L2=720),
  seed determinism, file output

Unity scaffold (ondevice/Scripts/):
- CommandBank.cs: loads commands.json from StreamingAssets (WebRequest on Android)
- TtsManager.cs: sherpa-onnx integration with [SHERPA] stubs, StreamingAssets→
  persistentDataPath copy, defensive Speak() with onDone callback
- SessionController.cs: passthrough flow §6, level switching, busy guard on Next
- ondevice/README.md: full manual Editor steps §5 (Unity setup, Meta XR SDK,
  sherpa-onnx install, scene wiring, font, build, metrics)

pytest: 37/37 passed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 16:11:53 +02:00

128 lines
3.9 KiB
Python
Raw Permalink 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.

import json
import os
import tempfile
import pytest
from ipin_vr.export import generate_bank, run_export
# Rozmiary wyczerpujące przestrzeni:
# Poziom 1: 2 × 10 × 6 = 120
# Poziom 2: 2 × 10 × 6 × 6 = 720
# --- format JSON ---
def test_meta_fields():
bank = generate_bank(per_level=5, seed=0)
assert bank["meta"]["version"] == "1"
assert bank["meta"]["per_level"] == 5
def test_commands_structure():
bank = generate_bank(per_level=5, seed=0)
for cmd in bank["commands"]:
assert "level" in cmd
assert "text" in cmd
assert cmd["level"] in {1, 2, 3}
assert isinstance(cmd["text"], str)
assert len(cmd["text"]) > 0
def test_commands_end_with_period():
bank = generate_bank(per_level=5, seed=0)
for cmd in bank["commands"]:
assert cmd["text"].endswith("."), f"Brak kropki: {cmd['text']!r}"
def test_json_roundtrip():
bank = generate_bank(per_level=5, seed=0)
dumped = json.dumps(bank, ensure_ascii=False)
reloaded = json.loads(dumped)
assert reloaded["meta"] == bank["meta"]
assert reloaded["commands"] == bank["commands"]
# --- deduplikacja w obrębie poziomu ---
def test_dedup_level1():
bank = generate_bank(per_level=50, seed=1)
texts = [c["text"] for c in bank["commands"] if c["level"] == 1]
assert len(texts) == len(set(texts)), "Duplikaty w poziomie 1"
def test_dedup_level2():
bank = generate_bank(per_level=50, seed=1)
texts = [c["text"] for c in bank["commands"] if c["level"] == 2]
assert len(texts) == len(set(texts)), "Duplikaty w poziomie 2"
def test_dedup_level3():
bank = generate_bank(per_level=50, seed=1)
texts = [c["text"] for c in bank["commands"] if c["level"] == 3]
assert len(texts) == len(set(texts)), "Duplikaty w poziomie 3"
# --- ograniczenie przez rozmiar przestrzeni ---
def test_level1_capped_at_space():
"""Poziom 1: 2 × 10 × 6 = 120 unikatów — więcej nie istnieje."""
bank = generate_bank(per_level=300, seed=2)
texts = [c["text"] for c in bank["commands"] if c["level"] == 1]
assert len(texts) == 120
assert len(texts) == len(set(texts))
def test_level2_capped_at_space():
"""Poziom 2: 2 × 10 × 6 × 6 = 720 unikatów."""
bank = generate_bank(per_level=1000, seed=2)
texts = [c["text"] for c in bank["commands"] if c["level"] == 2]
assert len(texts) == 720
assert len(texts) == len(set(texts))
def test_level3_respects_per_level():
bank = generate_bank(per_level=30, seed=3)
texts = [c["text"] for c in bank["commands"] if c["level"] == 3]
assert len(texts) == 30
# --- dokładna liczba na poziom ---
def test_counts_per_level_small():
bank = generate_bank(per_level=10, seed=4)
for level in [1, 2, 3]:
texts = [c["text"] for c in bank["commands"] if c["level"] == level]
assert len(texts) == 10, f"Poziom {level}: oczekiwano 10, jest {len(texts)}"
# --- flagi CLI ---
def test_cli_out_file():
with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as tf:
path = tf.name
try:
run_export(["--per-level", "5", "--out", path, "--seed", "7"])
with open(path, encoding="utf-8") as f:
data = json.load(f)
assert data["meta"]["per_level"] == 5
assert len(data["commands"]) == 15 # 5 per level × 3 levels
finally:
os.unlink(path)
def test_cli_seed_deterministic():
"""Ten sam seed → identyczny wynik."""
b1 = generate_bank(per_level=10, seed=99)
b2 = generate_bank(per_level=10, seed=99)
assert b1["commands"] == b2["commands"]
def test_cli_different_seeds():
"""Różne seedy → różne wyniki (z bardzo dużym prawdopodobieństwem)."""
b1 = generate_bank(per_level=50, seed=1)
b2 = generate_bank(per_level=50, seed=2)
t1 = [c["text"] for c in b1["commands"] if c["level"] == 3]
t2 = [c["text"] for c in b2["commands"] if c["level"] == 3]
assert t1 != t2