Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dmcheck/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,10 @@ def main(argv=None):
ch["dice_authors"] = a.dice_bot
transcript = load_transcript(a.transcript)
ledger = load_ledger(a.ledger)
findings, code = check(transcript, ch, ledger)
except (OSError, ValueError, json.JSONDecodeError) as e:
print(json.dumps({"error": str(e)}), file=sys.stderr)
return 2
findings, code = check(transcript, ch, ledger)
print(json.dumps({"charter_version": ch.get("charter_version"),
"messages": len(transcript),
"findings": findings,
Expand Down
4 changes: 2 additions & 2 deletions dmcheck/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ def check(transcript, charter, ledger=None, closed=True, now=None):
enabled = set(ch.get("rules_enabled", list(RULES)))
gm_idx = [r["i"] for r in T if _is_gm(r, ch)]
if not ch["gm"]:
return [{"error": "charter names no GM author — cannot referee; "
"set charter.gm or pass --gm"}], 2
raise ValueError("charter names no GM author — cannot referee; "
"set charter.gm or pass --gm")

# R1 unanswered-player: a non-GM, non-dice message containing a question,
# with NO GM message in the next `answer_within_messages` messages.
Expand Down
4 changes: 4 additions & 0 deletions dmcheck/watch.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ def watch_main(a):
ch["gm"] = a.gm
if a.dice_bot:
ch["dice_authors"] = a.dice_bot
if not ch.get("gm"):
print(json.dumps({"error": "charter names no GM author — cannot referee; "
"set charter.gm or pass --gm"}), file=sys.stderr)
return 2
ledger = load_ledger(a.ledger)
w = Watcher(ch, ledger, notify_cmd=a.notify_cmd,
craft=getattr(a, "craft", False), scene=getattr(a, "scene", "SOCIAL"),
Expand Down
35 changes: 32 additions & 3 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,40 @@ def test_exit_code(self):

class TestGuards(unittest.TestCase):
def test_no_gm_declared_is_unusable(self):
"""check() raises — it never returns a finding without a 'rule' key."""
ch = load_charter(CH)
ch["gm"] = []
findings, code = check(load_transcript(os.path.join(FIX, "clean-session.jsonl")), ch)
self.assertEqual(code, 2)
self.assertIn("error", findings[0])
with self.assertRaises(ValueError):
check(load_transcript(os.path.join(FIX, "clean-session.jsonl")), ch)

def test_cli_no_gm_is_exit_2_not_traceback(self):
"""The 0.5.5 regression class: `dmcheck run <transcript>` with the
packaged default charter (no GM) must exit 2 with a JSON error on
stderr — never a KeyError traceback from the counts summary."""
import subprocess
r = subprocess.run(
[sys.executable, "-c",
"import sys; sys.path.insert(0, %r); from dmcheck.cli import main; "
"sys.argv = ['dmcheck', 'run', %r]; sys.exit(main())"
% (os.path.join(os.path.dirname(__file__), ".."),
os.path.join(FIX, "clean-session.jsonl"))],
capture_output=True, text=True)
self.assertEqual(r.returncode, 2, r.stderr)
self.assertNotIn("Traceback", r.stderr)
err = json.loads(r.stderr.strip().splitlines()[-1])
self.assertIn("no GM author", err["error"])

def test_watch_no_gm_is_exit_2(self):
import subprocess
r = subprocess.run(
[sys.executable, "-c",
"import sys; sys.path.insert(0, %r); from dmcheck.cli import main; "
"sys.argv = ['dmcheck', 'watch', %r]; sys.exit(main())"
% (os.path.join(os.path.dirname(__file__), ".."),
os.path.join(FIX, "clean-session.jsonl"))],
capture_output=True, text=True)
self.assertEqual(r.returncode, 2, r.stderr)
self.assertNotIn("Traceback", r.stderr)


if __name__ == "__main__":
Expand Down
Loading