Files
systemic-game-design-course/course/10-spellgrid/reference/rust/tests/cli.rs
T
Lucas WintherandClaude Opus 5.5 a0cf9be214 feat: module 10 spellgrid
SpellGrid capstone: Part I's card engine and Part II's grid engine joined at
three seams (rules -> aura data, hazard victims -> one destroy Sequence,
Sequence end -> write text, remove the dead, reparse). Three levels with
scripted solutions, a naive-timing test via a harness-only hook that
reverses the END_OF_PHASE list, CLIs in both tracks, the BATTLECRY IS DOUBLE
Expansion Drop, SpellGrid cards and words in course/cards and the catalog,
level schema cards/hand, and tools staging/copying of module levels.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 05:01:27 +01:00

67 lines
1.9 KiB
Rust

// The SpellGrid command line, played from a script (the reference's own check; not a course test).
use std::cell::RefCell;
use std::io::{Cursor, Write};
use std::rc::Rc;
use engine::cli::{run, Outcome};
/// Collects what the CLI prints.
#[derive(Clone, Default)]
struct Screen(Rc<RefCell<Vec<u8>>>);
impl Write for Screen {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0.borrow_mut().extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
fn play(level: &str, input: &[&str]) -> (Outcome, String) {
let screen = Screen::default();
let input = Box::new(Cursor::new(input.join("\n") + "\n"));
let outcome = run(level, input, Box::new(screen.clone()));
let out = String::from_utf8(screen.0.borrow().clone()).unwrap();
(outcome, out)
}
#[test]
fn cli_wins_level_1() {
let input = ["w", "w", "c Whirlwind", "s", "s", "a", "s", "s", "d", "d"];
let (outcome, out) = play(include_str!("../levels/l1-double-tap.json"), &input);
assert_eq!(outcome, Outcome::Won);
assert!(out.contains("DEA IS DOU"));
assert!(out.contains("You win!"));
}
#[test]
fn cli_wins_level_2_with_choices_and_play() {
let input = [
"c Graft",
"Ember Moth",
"Rune Scribe",
"bottom",
"c Ember Moth (Assembled) 4 3",
"a",
"a",
];
let (outcome, out) = play(include_str!("../levels/l2-spliced-corpse.json"), &input);
assert_eq!(outcome, Outcome::Won);
assert!(out.contains("Choose the base"));
assert!(out.contains("Hand: Ember Moth (Assembled)"));
}
#[test]
fn cli_reports_errors_and_quits() {
let input = ["c Spark", "x", "q"];
let (outcome, out) = play(
include_str!("../levels/l3-simultaneous-paradox.json"),
&input,
);
assert_eq!(outcome, Outcome::Quit);
assert!(out.contains("\"Spark\" is not in the hand"));
assert!(out.contains("Commands:"));
}