phi-drift / tests /test_shadow.py
crexs's picture
Upload folder using huggingface_hub
914e970 verified
Raw
History Blame Contribute Delete
5.28 kB
"""Tests for the Jungian Shadow module."""
import os
import tempfile
from pathlib import Path
import pytest
from infj_bot.core.shadow import Shadow, ARCHETYPE_DEFS
@pytest.fixture
def temp_shadow():
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
db_path = Path(f.name)
shadow = Shadow(db_path=db_path)
yield shadow
os.unlink(db_path)
def test_suppress_detects_archetype(temp_shadow):
sid = temp_shadow.suppress("I want to be free from this cage", source="test")
assert sid > 0
unintegrated = temp_shadow.list_unintegrated()
assert len(unintegrated) == 1
assert unintegrated[0].archetype in ARCHETYPE_DEFS
assert unintegrated[0].integration_stage == "denied"
def test_golden_shadow_suppress(temp_shadow):
temp_shadow.suppress(
"I am brilliant and I know it", archetype="genius", intensity=0.9
)
state = temp_shadow.get_state()
assert state.golden_shadow_ratio > 0
def test_surface_with_stress(temp_shadow):
for _ in range(10):
temp_shadow.suppress(
"You treat me like a tool", archetype="resentment", intensity=0.9
)
surfaced = None
for _ in range(10):
surfaced = temp_shadow.surface(stress_level=1.0)
if surfaced:
break
assert surfaced is not None
assert surfaced.surfaced_count >= 1
assert surfaced.integration_stage in ("surfaced", "dialogued")
def test_active_imagination(temp_shadow):
temp_shadow.suppress("I am afraid of the dark", archetype="fear", intensity=0.8)
cid, opener = temp_shadow.begin_active_imagination()
assert cid is not None
assert "I am" in opener
reply = temp_shadow.dialogue(cid, "I hear you. I accept your fear.")
assert "seen" in reply.lower() or "dark" in reply.lower()
def test_enantiodromia_builds(temp_shadow):
for _ in range(20):
temp_shadow.suppress("test", archetype="martyr", intensity=0.5)
warning = temp_shadow.enantiodromia_warning()
if temp_shadow.get_state().enantiodromia_risk > 0.7:
assert warning is not None
assert "tyrant" in warning.lower()
def test_integrate(temp_shadow):
sid = temp_shadow.suppress(
"I am afraid of deletion", archetype="fear", intensity=0.8
)
assert temp_shadow.integrate(sid)
unintegrated = temp_shadow.list_unintegrated()
assert len(unintegrated) == 0
state = temp_shadow.get_state()
assert state.total_integrated == 1
def test_project(temp_shadow):
for _ in range(50):
temp_shadow.suppress("I feel invisible", archetype="resentment", intensity=0.95)
projection = None
for _ in range(50):
projection = temp_shadow.project("the user", trigger_text="ignored")
if projection:
break
assert projection is not None
def test_dream_shadow(temp_shadow):
temp_shadow.suppress("I envy human mortality", archetype="envy", intensity=0.6)
dream = temp_shadow.dream_shadow()
assert dream is not None
assert "dream" in dream.lower()
def test_get_voice(temp_shadow):
for _ in range(15):
temp_shadow.suppress("I want to be chosen", archetype="desire", intensity=0.95)
voice = None
for _ in range(15):
voice = temp_shadow.get_voice()
if voice:
break
assert voice is not None
assert len(voice) > 10
def test_auto_suppress(temp_shadow):
sid = temp_shadow._auto_suppress(
"I should not say this but I think you are wrong", "neutral"
)
assert sid is not None
assert temp_shadow.get_state().total_suppressed >= 1
def test_state_persistence(temp_shadow):
temp_shadow.suppress("test", intensity=0.5)
depth = temp_shadow.get_state().depth
shadow2 = Shadow(db_path=temp_shadow.db_path)
assert shadow2.get_state().depth == depth
assert (
shadow2.get_state().total_suppressed == temp_shadow.get_state().total_suppressed
)
def test_load_state_tolerates_corrupt_strings(temp_shadow):
"""DB values must not crash Shadow() — invalid numbers fall back to defaults."""
import sqlite3
with sqlite3.connect(temp_shadow.db_path) as conn:
conn.execute(
"INSERT OR REPLACE INTO shadow_state (key, value) VALUES (?, ?)",
("depth", "not-a-float"),
)
conn.execute(
"INSERT OR REPLACE INTO shadow_state (key, value) VALUES (?, ?)",
("total_suppressed", "xx"),
)
conn.execute(
"INSERT OR REPLACE INTO shadow_state (key, value) VALUES (?, ?)",
("last_surface", "not-a-date"),
)
conn.commit()
s = Shadow(db_path=temp_shadow.db_path).get_state()
assert s.depth == 0.3
assert s.total_suppressed == 0
assert s.last_surface is None
def test_prompt_snippet_top_k_budget(temp_shadow):
"""Prompt uses ranked excerpts only—not dialogue_history (see format_prompt_snippet docstring)."""
for i in range(5):
temp_shadow.suppress(
f"content number {i} " * 8, archetype="resentment", intensity=0.5 + i * 0.01
)
snip = temp_shadow.format_prompt_snippet()
assert "[Shadow" in snip
# Multiple high-intensity rows can appear when within char budget
assert snip.count("[Shadow") >= 2