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