use bubbles::{DialogueEvent, HashMapStorage, Runner, Value, VariableStorage, compile};
fn run_until_done(mut r: Runner<HashMapStorage>) -> (Runner<HashMapStorage>, Vec<String>) {
let mut out = Vec::new();
loop {
let ev = match r.next_event() {
Ok(e) => e,
Err(e) => panic!("{e}"),
};
let Some(ev) = ev else {
return (r, out);
};
match ev {
DialogueEvent::Line { text, .. } => out.push(text),
DialogueEvent::Options(opts) => {
let idx = opts
.iter()
.position(|o| o.available)
.expect("no available option");
r.select_option(idx).expect("select_option");
}
_ => {}
}
}
}
#[test]
fn full_expression_surface_emits_expected_lines() {
let src = r"
title: A
when: 1 < 2
---
<<declare $t = 0>>
<<if $t < 1>>
First branch.
<<elseif 2 * 2 == 4>>
Second branch.
<<else>>
Else branch.
<<endif>>
=> => Line one.
=> => Line two <<if true>>
-> Opt <<if 1+1==2>>
<<set $t = 1>>
After opt.
-> Skip <<if false>>
hidden
<<once if 5 > 3>>
Once line.
<<endonce>>
===
title: B
---
Other node.
===
";
let prog = compile(src).unwrap();
let mut r = Runner::new(prog, HashMapStorage::new());
r.start("A").unwrap();
let lines = run_until_done(r).1;
assert!(
lines.iter().any(|l| l.contains("First branch")),
"expected first if branch, got {lines:?}"
);
assert!(
!lines.iter().any(|l| l.contains("Second branch")),
"did not expect elseif when first if matched: {lines:?}"
);
assert!(lines.iter().any(|l| l.contains("Line one")));
assert!(lines.iter().any(|l| l.contains("After opt")));
assert!(lines.iter().any(|l| l.contains("Once line.")));
let prog2 = compile(src).unwrap();
let mut r2 = Runner::new(prog2, HashMapStorage::new());
r2.start("A").unwrap();
let r2 = run_until_done(r2).0;
assert_eq!(r2.storage().get("$t"), Some(Value::Number(1.0)));
}
#[test]
fn node_group_when_uses_parsed_expression() {
let src = r"
title: G
when: 10 >= 5
---
Hello
===
title: G
when: 1 == 0
---
Wrong
===
";
let prog = compile(src).unwrap();
let mut r = Runner::new(prog, HashMapStorage::new());
r.start("G").unwrap();
let lines = run_until_done(r).1;
assert_eq!(lines, vec!["Hello"]);
}