#[cfg(test)]
mod test {
use axum::http::HeaderMap;
use roto::{FileTree, Val, Verdict};
use std::sync::Arc;
use crate::means_of_production::{Error, IocaineContext, MeansOfProduction, Outcome, Request};
fn run_init(script: &str) -> Result<IocaineContext, Error> {
let runtime = MeansOfProduction::new_runtime()?;
let mut compiled =
FileTree::test_file(file!(), script, line!() as usize - 1).compile(runtime)?;
let init = compiled.get_function::<IocaineContext, fn() -> Verdict<(), Arc<str>>>("init");
let mut context = IocaineContext::default();
if let Ok(init) = init {
init.call(&mut context)
.into_result()
.map_err(|e| Error::String(format!("init script failed: {e}")))?;
}
Ok(context)
}
fn new_handler(script: &str) -> Result<MeansOfProduction, Error> {
let context = run_init(script)?;
let runtime = MeansOfProduction::new_runtime()?;
let mut compiled =
FileTree::test_file(file!(), script, line!() as usize - 1).compile(runtime)?;
let decider = compiled
.get_function::<IocaineContext, fn(Val<Request>) -> Verdict<Val<Outcome>, Val<Outcome>>>(
"decide",
)
.map_err(|e| e.to_string())?;
Ok(MeansOfProduction { decider, context })
}
fn assert_verdict(headers: HeaderMap, script: &str, v: Result<Outcome, Outcome>) {
let handler = new_handler(script)
.inspect_err(|e| eprintln!("{e}"))
.unwrap();
let res = handler.decide(headers, Some("/".to_string()), "GET");
assert_eq!(res, v);
}
#[test]
fn test_handler_static_verdict() {
assert_verdict(
HeaderMap::new(),
r#"
function decide(request: Request) -> Verdict[Outcome, Outcome] {
accept Outcome.garbage()
}
"#,
Ok(Outcome::Garbage),
);
assert_verdict(
HeaderMap::new(),
r#"
function decide(request: Request) -> Verdict[Outcome, Outcome] {
reject Outcome.not_for_us()
}
"#,
Err(Outcome::NotForUs),
);
}
#[test]
fn test_handler_failable_init() {
let result = run_init(r#"function init() -> Verdict[Unit, String] { reject "testing" }"#);
assert!(result.is_err());
let result = run_init(r#"function init() -> Verdict[Unit, String] { accept }"#);
assert!(result.is_ok());
}
#[test]
fn test_handler_context() {
let init_script = r#"
function init() -> Verdict[Unit, String] {
let list = MutableStringList.new();
list.push("testing");
iocaine_patterns.insert("tests", PatternFinder.new(list));
iocaine_regexes.insert("tests", RegexFinder.new("^testing$"));
accept
}
"#;
let classify_script = r#"
function decide(request: Request) -> Verdict[Outcome, Outcome] {
if iocaine_patterns.get("none").is_match("nope") {
reject Outcome.not_for_us()
}
if iocaine_regexes.get("none").is_match(".") {
reject Outcome.not_for_us()
}
if iocaine_patterns.get("tests").is_match("testing") {
accept Outcome.garbage()
}
if iocaine_regexes.get("tests").is_match("testing") {
accept Outcome.garbage()
}
reject Outcome.not_for_us()
}
"#;
assert_verdict(HeaderMap::new(), classify_script, Err(Outcome::NotForUs));
assert_verdict(
HeaderMap::new(),
&format!("{init_script} {classify_script}"),
Ok(Outcome::Garbage),
);
}
#[test]
fn test_handler_request() {
fn make_script(body: &str) -> String {
format!(
r#"
function decide(request: Request) -> Verdict[Outcome, Outcome] {{
{body}
}}
"#
)
}
let mut headers = HeaderMap::new();
headers.insert("user-agent", "tester".parse().unwrap());
assert_verdict(
headers,
&make_script(
r#"
if request.method() != "GET" {
reject Outcome.not_for_us()
}
if request.path() != "/" {
reject Outcome.not_for_us()
}
if request.header("user-agent") != "tester" {
reject Outcome.not_for_us()
}
accept Outcome.garbage()
"#,
),
Ok(Outcome::Garbage),
);
}
}