use cucumber::{World, gherkin::Step, given, then, when};
#[derive(Debug, Default, World)]
pub struct GollumWorld {
pub source: String,
pub parse_result: Option<gollum_parser::Result<Vec<gollum_parser::Item>>>,
pub lex_tokens: Vec<String>,
}
#[given("a Gollum parser is initialized")]
async fn parser_initialized(_world: &mut GollumWorld) {}
#[given(regex = r"^the following Gollum code:$")]
async fn set_source(world: &mut GollumWorld, #[step] step: &Step) {
world.source = step
.docstring
.as_deref()
.expect("docstring required")
.trim()
.to_string();
}
#[when("I parse the code")]
async fn parse_code(world: &mut GollumWorld) {
world.parse_result = Some(gollum_parser::parse(&world.source));
}
#[when("I lex the code")]
async fn lex_code(world: &mut GollumWorld) {
use gollum_parser::lexer::tokenize;
world.lex_tokens = tokenize(&world.source)
.into_iter()
.map(|r| match r {
Ok(tok) => tok.to_string(),
Err(()) => "Error".to_string(),
})
.collect();
}
#[then(regex = r"^the resulting AST should be:$")]
async fn check_ast(world: &mut GollumWorld, #[step] step: &Step) {
let items = world
.parse_result
.as_ref()
.expect("parse not yet run")
.as_ref()
.expect("parse failed");
let first = items.first().expect("no items parsed");
let ron_str = step
.docstring
.as_deref()
.expect("docstring required")
.trim();
let expected: gollum_parser::Item = ron::from_str(ron_str)
.unwrap_or_else(|e| panic!("invalid RON in feature file:\n{e}\n\nRON was:\n{ron_str}"));
assert_eq!(expected, *first);
}
#[then("parsing should fail with a syntax error")]
async fn check_failure(world: &mut GollumWorld) {
let result = world.parse_result.as_ref().expect("parse not yet run");
assert!(result.is_err(), "expected parse failure but got success");
}
#[then(regex = r"^the token stream should be:$")]
async fn check_token_stream(world: &mut GollumWorld, #[step] step: &Step) {
let expected: Vec<String> = step
.docstring
.as_deref()
.expect("docstring required")
.split(',')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect();
assert_eq!(
world.lex_tokens,
expected,
"\nExpected: {}\nActual: {}",
expected.join(", "),
world.lex_tokens.join(", ")
);
}
#[tokio::main]
async fn main() {
if std::env::args().any(|x| x == "--list") {
std::process::exit(0);
}
GollumWorld::cucumber()
.run_and_exit(concat!(env!("CARGO_MANIFEST_DIR"), "/../../tests/language"))
.await;
}