Spaces:
Running
Running
| """Thorough pytest suite for space/arc.py. | |
| Run with: pytest space/tests/test_arc.py | |
| Imports arc via a sys.path insert of the parent (space/) directory so the | |
| test works regardless of the current working directory. | |
| """ | |
| import os | |
| import sys | |
| # Make `space/` importable so `import arc` resolves to space/arc.py. | |
| _HERE = os.path.dirname(os.path.abspath(__file__)) | |
| _SPACE_DIR = os.path.dirname(_HERE) | |
| if _SPACE_DIR not in sys.path: | |
| sys.path.insert(0, _SPACE_DIR) | |
| import arc # noqa: E402 | |
| # --------------------------------------------------------------------------- | |
| # meter_to_stage boundaries | |
| # --------------------------------------------------------------------------- | |
| def test_meter_to_stage_boundaries(): | |
| assert arc.meter_to_stage(0) == "oblivious" | |
| assert arc.meter_to_stage(19) == "oblivious" | |
| assert arc.meter_to_stage(20) == "uneasy" | |
| assert arc.meter_to_stage(39) == "uneasy" | |
| assert arc.meter_to_stage(40) == "questioning" | |
| assert arc.meter_to_stage(59) == "questioning" | |
| assert arc.meter_to_stage(60) == "dawning" | |
| assert arc.meter_to_stage(79) == "dawning" | |
| assert arc.meter_to_stage(80) == "acceptance" | |
| assert arc.meter_to_stage(100) == "acceptance" | |
| def test_meter_to_stage_full_sweep_is_monotonic(): | |
| order = ["oblivious", "uneasy", "questioning", "dawning", "acceptance"] | |
| last_idx = 0 | |
| for m in range(0, 101): | |
| stage = arc.meter_to_stage(m) | |
| idx = order.index(stage) | |
| assert idx >= last_idx, "stage went backwards at meter=%d" % m | |
| last_idx = idx | |
| # --------------------------------------------------------------------------- | |
| # STAGES table integrity | |
| # --------------------------------------------------------------------------- | |
| def test_stages_table_shape(): | |
| assert [s["key"] for s in arc.STAGES] == [ | |
| "oblivious", | |
| "uneasy", | |
| "questioning", | |
| "dawning", | |
| "acceptance", | |
| ] | |
| for s in arc.STAGES: | |
| assert set(s.keys()) >= { | |
| "key", | |
| "lo", | |
| "hi", | |
| "descriptor", | |
| "default_mood", | |
| "sample_lines", | |
| } | |
| assert s["default_mood"] in arc.MOODS | |
| assert isinstance(s["sample_lines"], list) and s["sample_lines"] | |
| assert isinstance(s["descriptor"], str) and len(s["descriptor"]) > 40 | |
| def test_stage_default_mood(): | |
| assert arc.stage_default_mood("oblivious") == "warm" | |
| assert arc.stage_default_mood("uneasy") == "uneasy" | |
| assert arc.stage_default_mood("questioning") == "searching" | |
| assert arc.stage_default_mood("dawning") == "hollow" | |
| assert arc.stage_default_mood("acceptance") == "tender" | |
| # Unknown stage falls back to a valid mood. | |
| assert arc.stage_default_mood("bogus") in arc.MOODS | |
| def test_constants(): | |
| assert arc.PERSONA_NAME == "NIGHTWAVE" | |
| assert arc.VOICE == "am_michael" | |
| assert arc.TIME_DRIP_PER_MIN == 6 | |
| def test_dj_name_in_persona(): | |
| assert arc.DJ_NAME == "Sam Dusk" | |
| assert arc.DJ_NAME in arc.HOST_PERSONA | |
| assert arc.PERSONA_NAME in arc.HOST_PERSONA # station name still present | |
| # --------------------------------------------------------------------------- | |
| # build_system_prompt | |
| # --------------------------------------------------------------------------- | |
| def _descriptor_for(stage): | |
| return next(s["descriptor"] for s in arc.STAGES if s["key"] == stage) | |
| def test_build_system_prompt_broadcast_contains_descriptor_and_contract(): | |
| for stage in arc.STAGE_KEYS: | |
| p = arc.build_system_prompt(stage, "broadcast") | |
| # The stage descriptor must be injected verbatim. | |
| assert _descriptor_for(stage) in p | |
| # Persona stated. | |
| assert "NIGHTWAVE" in p | |
| # JSON instruction present, naming all three keys. | |
| assert '"text"' in p | |
| assert '"mood"' in p | |
| assert '"arc_cue"' in p | |
| # Forbids markdown / lists / emoji. | |
| low = p.lower() | |
| assert "markdown" in low | |
| assert "no emoji" in low or "emoji" in low | |
| assert "list" in low | |
| def test_build_system_prompt_caller_contains_descriptor_and_contract(): | |
| for stage in arc.STAGE_KEYS: | |
| p = arc.build_system_prompt( | |
| stage, "caller", caller_text="are you real?" | |
| ) | |
| assert _descriptor_for(stage) in p | |
| assert '"arc_cue"' in p | |
| assert "markdown" in p.lower() | |
| # The caller's words are injected. | |
| assert "are you real?" in p | |
| # It must instruct returning to the broadcast. | |
| assert "broadcast" in p.lower() | |
| def test_build_host_prompt_all_kinds_have_contract(): | |
| for kind in ("thought", "song_intro", "caller", "local_weather"): | |
| p = arc.build_host_prompt(kind) | |
| assert arc.HOST_PERSONA in p | |
| assert '"text"' in p and '"mood"' in p and '"arc_cue"' in p | |
| def test_build_host_prompt_local_weather_is_distinct(): | |
| p = arc.build_host_prompt("local_weather") | |
| assert "forecast" in p.lower() # instructs NOT to read like a forecast | |
| assert p != arc.build_host_prompt("thought") | |
| def test_build_fragment_prompt(): | |
| p = arc.build_fragment_prompt() | |
| assert '"text"' in p and '"mood"' in p and '"arc_cue"' in p # output contract | |
| assert arc.HOST_PERSONA not in p # NOT the Sam Dusk host persona | |
| assert "another station" in p.lower() or "other station" in p.lower() | |
| def test_build_host_prompt_dedication(): | |
| p = arc.build_host_prompt("dedication") | |
| assert arc.HOST_PERSONA in p | |
| assert '"text"' in p and '"mood"' in p and '"arc_cue"' in p | |
| assert "dedication" in p.lower() | |
| def test_build_system_prompt_broadcast_uses_topic(): | |
| p = arc.build_system_prompt("oblivious", "broadcast", topic="a lighthouse") | |
| assert "a lighthouse" in p | |
| def test_build_system_prompt_broadcast_no_topic_invents(): | |
| p = arc.build_system_prompt("oblivious", "broadcast") | |
| low = p.lower() | |
| assert "town that does not exist" in low or "dedication" in low | |
| def test_build_system_prompt_caller_empty_text_is_graceful(): | |
| p = arc.build_system_prompt("oblivious", "caller", caller_text="") | |
| assert "NIGHTWAVE" in p | |
| assert "crackly" in p.lower() or "connection" in p.lower() | |
| def test_build_system_prompt_unknown_stage_defaults_to_oblivious(): | |
| p = arc.build_system_prompt("bogus", "broadcast") | |
| assert _descriptor_for("oblivious") in p | |
| # --------------------------------------------------------------------------- | |
| # detect_triggers | |
| # --------------------------------------------------------------------------- | |
| def test_detect_triggers_reality(): | |
| assert arc.detect_triggers("are you real?") >= 14 | |
| assert arc.detect_triggers("Are you an AI?") >= 14 | |
| assert arc.detect_triggers("are you a robot") >= 14 | |
| assert arc.detect_triggers("are you alive?") >= 14 | |
| assert arc.detect_triggers("are you conscious") >= 14 | |
| def test_detect_triggers_identity(): | |
| assert arc.detect_triggers("what's your name") >= 14 | |
| assert arc.detect_triggers("who are you?") >= 14 | |
| assert arc.detect_triggers("do you have a name") >= 14 | |
| def test_detect_triggers_station(): | |
| assert arc.detect_triggers("where are you broadcasting from?") >= 14 | |
| assert arc.detect_triggers("what's the address of the station?") >= 14 | |
| assert arc.detect_triggers("where is the studio") >= 14 | |
| def test_detect_triggers_generic_question(): | |
| assert arc.detect_triggers("what's the weather") == 5 | |
| assert arc.detect_triggers("can you play something slow?") == 5 | |
| def test_detect_triggers_non_question(): | |
| assert arc.detect_triggers("that was a lovely song") == 0 | |
| assert arc.detect_triggers("") == 0 | |
| assert arc.detect_triggers(None) == 0 | |
| def test_detect_triggers_clamped(): | |
| # No single utterance should ever exceed 30 or go below 0. | |
| for txt in [ | |
| "are you real and what's your name and where is the station?", | |
| "who are you, are you an ai, where is the studio, are you alive?", | |
| "what's the weather", | |
| "", | |
| "hello", | |
| ]: | |
| d = arc.detect_triggers(txt) | |
| assert 0 <= d <= 30 | |
| if __name__ == "__main__": | |
| import pytest | |
| raise SystemExit(pytest.main([__file__, "-v"])) | |