use quarb::{EnvKind, Environment, QueryResult, Value};
fn doc() -> quarb_json::JsonAdapter {
quarb_json::JsonAdapter::parse(
r#"{"w":["pear","apple","fig"],
"p":[{"n":"a","x":2},{"n":"b","x":1}]}"#,
)
.unwrap()
}
fn run_with(q: &str, envs: Vec<Environment>) -> quarb::Result<Vec<String>> {
let run = quarb::Run {
environments: envs,
..quarb::Run::ambient()
};
let out = quarb::Query::parse(q, &doc())?.run(&doc(), &run)?;
Ok(match out.result {
QueryResult::Values(vs) => vs.iter().map(Value::to_string).collect(),
QueryResult::Nodes(ns) => ns.iter().map(|n| format!("{n:?}")).collect(),
})
}
fn bin() -> Environment {
Environment::parse("u", "exec:/usr/bin").unwrap()
}
fn shell() -> Environment {
Environment::parse("sh", "shell:").unwrap()
}
#[test]
fn the_mount_grammar_names_the_kinds() {
assert_eq!(bin().kind, EnvKind::Exec);
assert_eq!(shell().kind, EnvKind::Shell);
assert!(Environment::parse_mount("ga=events.json").is_none());
assert!(Environment::parse_mount("t=text:book.txt").is_none());
let e = Environment::parse_mount("go=exec:/no/such/dir")
.unwrap()
.unwrap_err()
.to_string();
assert!(e.contains("no such directory or program"), "{e}");
let e = Environment::parse_mount("sh=shell:bash")
.unwrap()
.unwrap_err()
.to_string();
assert!(e.contains("takes no target"), "{e}");
let e = Environment::parse_mount("py=python:./no-such-helpers.py")
.unwrap()
.unwrap_err()
.to_string();
assert!(e.contains("no such module file"), "{e}");
let e = Environment::parse_mount("py=python:python3")
.unwrap()
.unwrap_err()
.to_string();
assert!(e.contains("an interpreter alone is no target"), "{e}");
let e = Environment::parse_mount("py=python:/usr/bin/python")
.unwrap()
.unwrap_err()
.to_string();
assert!(e.contains("an interpreter alone is no target"), "{e}");
let e = Environment::parse_mount("py=python:")
.unwrap()
.unwrap_err()
.to_string();
assert!(e.contains("names no module"), "{e}");
let py = Environment::parse_mount("py=python:pkg.helpers")
.unwrap()
.unwrap();
assert_eq!(py.kind, EnvKind::Python);
assert_eq!(py.target, "pkg.helpers");
let e = Environment::parse_mount("9x=exec:/usr/bin")
.unwrap()
.unwrap_err()
.to_string();
assert!(e.contains("alias is a word"), "{e}");
}
#[test]
fn a_python_mount_a_host_did_not_bind_refuses_naming_the_feature() {
let py = Environment::parse("py", "python:textwrap").unwrap();
let e = run_with("/w/* | :: | py:dedent", vec![py])
.unwrap_err()
.to_string();
assert!(e.contains("python feature"), "{e}");
}
#[test]
fn an_unmounted_alias_refuses_before_the_run() {
let e = run_with("/w/* | :: | sh:tr(a-z; A-Z)", vec![])
.unwrap_err()
.to_string();
assert!(e.contains("environment 'sh' is not mounted"), "{e}");
let e = run_with("/w/* | :: | tr(a-z; A-Z)", vec![shell()])
.unwrap_err()
.to_string();
assert!(e.contains("pipeline command 'tr'"), "{e}");
}
#[test]
fn after_the_plain_pipe_once_per_capsa_on_the_topics_text() {
assert_eq!(
run_with("/w/* | :: | u:tr(a-z; A-Z)", vec![bin()]).unwrap(),
vec!["PEAR", "APPLE", "FIG"]
);
assert_eq!(
run_with("/p/* | ::n | u:printf(\"%s-%s\"; $_; ::x)", vec![bin()]).unwrap(),
vec!["a-2", "b-1"]
);
assert_eq!(
run_with("/w/* | u:tr(a-z; A-Z)", vec![bin()]).unwrap(),
vec!["0", "1", "2"]
);
}
#[test]
fn after_the_aggregation_pipe_once_over_the_context_as_lines() {
let sorted = run_with("/w/* | :: @| u:sort", vec![bin()]).unwrap();
assert_eq!(sorted, vec!["apple", "fig", "pear"]);
assert_eq!(
run_with("/w/* | :: @| u:sort(-r)", vec![bin()]).unwrap(),
vec!["pear", "fig", "apple"]
);
assert_eq!(
run_with("/w/* | :: @| u:wc(-l) | trim", vec![bin()]).unwrap(),
vec!["3"]
);
assert_eq!(
run_with("/p/* | %(n = ::n; x = ::x) @| u:head(-n=1)", vec![bin()]).unwrap(),
vec!["{\"n\": \"a\", \"x\": 2}"]
);
assert_eq!(
run_with(
"/w/* | :: @| .total(count) @| u:sort @| [1] | %(w = $_; total = $.total)",
vec![bin()]
)
.unwrap(),
vec!["%(w = \"apple\"; total = 3)"]
);
}
#[test]
fn the_shell_kind_reaches_the_users_shell() {
assert_eq!(
run_with("/w/* | :: @| [1] | sh:echo(hi; there)", vec![shell()]).unwrap(),
vec!["hi there"]
);
assert_eq!(
run_with("/w/* | :: @| [1] | sh:tr(a-z; A-Z)", vec![shell()]).unwrap(),
vec!["PEAR"]
);
for q in [
"/w/* | :: @| [1] | sh(tr a-z A-Z)",
"/w/* | :: @| [1] | sh('tr a-z A-Z')",
"/w/* | :: @| [1] | `tr a-z A-Z`",
"/w/* | :: @| [1] | (;tr a-z A-Z)",
] {
let e = run_with(q, vec![shell()]).unwrap_err().to_string();
assert!(
e.contains("is retired") && e.contains("sh=shell:"),
"{q}: {e}"
);
}
}
#[test]
fn an_option_takes_a_comma_after_its_equals_as_its_value() {
for q in [
"/w/* | :: @| [1] | u:echo(\"a,b,c\") | u:cut(--delimiter=, --fields=2)",
"/w/* | :: @| [1] | u:echo(\"a,b,c\") | u:cut(-d=, -f=2)",
"/w/* | :: @| [1] | u:echo(\"a,b,c\") | u:cut(\"-d,\"; -f2)",
] {
assert_eq!(run_with(q, vec![bin()]).unwrap(), vec!["b"], "{q}");
}
assert!(
run_with(
"/w/* | :: @| [1] | u:echo(\"a,b,c\") | u:cut(-d, -f2)",
vec![bin()]
)
.is_err()
);
}
#[test]
fn headless_a_text_callee_reads_its_first_operand_on_stdin() {
assert_eq!(
run_with("= u:tr(abc; a-z; A-Z)", vec![bin()]).unwrap(),
vec!["ABC"]
);
assert_eq!(
run_with("= \"abc\" | u:tr(a-z; A-Z)", vec![bin()]).unwrap(),
vec!["ABC"]
);
assert_eq!(
run_with("= sh:tr(abc; a-z; A-Z)", vec![shell()]).unwrap(),
vec!["ABC"]
);
}
#[test]
fn the_allow_shell_switch_is_retired_naming_the_mount() {
let dir = std::env::temp_dir().join(format!("quarb-allow-shell-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("w.json"), r#"{"w":["pear"]}"#).unwrap();
let out = std::process::Command::new(env!("CARGO_BIN_EXE_qua"))
.arg("--allow-shell")
.arg("/w/*::")
.arg(dir.join("w.json"))
.stdin(std::process::Stdio::null())
.output()
.unwrap();
assert!(!out.status.success());
let err = String::from_utf8_lossy(&out.stderr);
assert!(
err.contains("--allow-shell is retired") && err.contains("sh=shell:"),
"{err}"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn failures_are_null_per_capsa_and_a_refusal_over_the_context() {
assert_eq!(
run_with("/w/* | :: @| [1] | u:false | default(\"nil\")", vec![bin()]).unwrap(),
vec!["nil"]
);
let e = run_with("/w/* | :: @| u:false", vec![bin()])
.unwrap_err()
.to_string();
assert!(e.contains("'false' failed"), "{e}");
let e = run_with("/w/* | :: | u:no_such_program_here", vec![bin()])
.unwrap_err()
.to_string();
assert!(
e.contains("environment 'u' has no command 'no_such_program_here'"),
"{e}"
);
let e = run_with("/w/* | :: @| [1] | sh:no_such_program_here", vec![shell()])
.unwrap_err()
.to_string();
assert!(e.contains("environment 'sh' has no command"), "{e}");
}