#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
use super::ast::{BashExpr, BashStmt, TestExpr};
use super::parser::BashParser;
fn expand(content: &str) -> BashExpr {
let parser = BashParser::new("echo x").unwrap();
parser.parse_variable_expansion(content).unwrap()
}
fn parse_script(script: &str) -> Vec<BashStmt> {
let mut parser = BashParser::new(script).unwrap();
parser.parse().unwrap().statements
}
fn parse_condition(test_clause: &str) -> BashExpr {
let script = format!("if {test_clause}; then\n echo ok\nfi");
let stmts = parse_script(&script);
match &stmts[0] {
BashStmt::If { condition, .. } => condition.clone(),
other => panic!("expected If statement, got: {other:?}"),
}
}
fn unwrap_test(expr: BashExpr) -> TestExpr {
match expr {
BashExpr::Test(inner) => *inner,
other => panic!("expected BashExpr::Test, got: {other:?}"),
}
}
#[test]
fn test_parse_var_expansion_simple_variable() {
assert_eq!(expand("myvar"), BashExpr::Variable("myvar".to_string()));
}
#[test]
fn test_parse_var_expansion_braced_variable() {
assert_eq!(expand("var"), BashExpr::Variable("var".to_string()));
}
#[test]
fn test_parse_var_expansion_default_value() {
let result = expand("var:-default");
assert_eq!(
result,
BashExpr::DefaultValue {
variable: "var".to_string(),
default: Box::new(BashExpr::Literal("default".to_string())),
}
);
}
#[test]
fn test_parse_var_expansion_default_value_empty() {
let result = expand("var:-");
assert_eq!(
result,
BashExpr::DefaultValue {
variable: "var".to_string(),
default: Box::new(BashExpr::Literal(String::new())),
}
);
}
#[test]
fn test_parse_var_expansion_assign_default() {
let result = expand("var:=fallback");
assert_eq!(
result,
BashExpr::AssignDefault {
variable: "var".to_string(),
default: Box::new(BashExpr::Literal("fallback".to_string())),
}
);
}
#[test]
fn test_parse_var_expansion_alternate_value() {
let result = expand("var:+alt");
assert_eq!(
result,
BashExpr::AlternativeValue {
variable: "var".to_string(),
alternative: Box::new(BashExpr::Literal("alt".to_string())),
}
);
}
#[test]
fn test_parse_var_expansion_error_if_unset() {
let result = expand("var:?variable not set");
assert_eq!(
result,
BashExpr::ErrorIfUnset {
variable: "var".to_string(),
message: Box::new(BashExpr::Literal("variable not set".to_string())),
}
);
}
#[test]
fn test_parse_var_expansion_string_length() {
let result = expand("#var");
assert_eq!(
result,
BashExpr::StringLength {
variable: "var".to_string(),
}
);
}
#[test]
fn test_parse_var_expansion_string_length_multichar() {
let result = expand("#MY_LONG_VAR");
assert_eq!(
result,
BashExpr::StringLength {
variable: "MY_LONG_VAR".to_string(),
}
);
}
#[test]
fn test_parse_var_expansion_remove_suffix() {
let result = expand("filename%.txt");
assert_eq!(
result,
BashExpr::RemoveSuffix {
variable: "filename".to_string(),
pattern: Box::new(BashExpr::Literal(".txt".to_string())),
}
);
}
#[test]
fn test_parse_var_expansion_remove_longest_suffix() {
let result = expand("path%%/*");
assert_eq!(
result,
BashExpr::RemoveLongestSuffix {
variable: "path".to_string(),
pattern: Box::new(BashExpr::Literal("/*".to_string())),
}
);
}
#[test]
fn test_parse_var_expansion_remove_prefix() {
let result = expand("path#*/");
assert_eq!(
result,
BashExpr::RemovePrefix {
variable: "path".to_string(),
pattern: Box::new(BashExpr::Literal("*/".to_string())),
}
);
}
#[test]
fn test_parse_var_expansion_remove_longest_prefix() {
let result = expand("path##*/");
assert_eq!(
result,
BashExpr::RemoveLongestPrefix {
variable: "path".to_string(),
pattern: Box::new(BashExpr::Literal("*/".to_string())),
}
);
}
#[test]
fn test_parse_var_expansion_substitution_single() {
let result = expand("var/old/new");
assert_eq!(result, BashExpr::Variable("var/old/new".to_string()),);
}
#[test]
fn test_parse_var_expansion_global_substitution() {
let result = expand("var//old/new");
assert_eq!(result, BashExpr::Variable("var//old/new".to_string()),);
}
#[test]
fn test_parse_var_expansion_positional_param() {
assert_eq!(expand("1"), BashExpr::Variable("1".to_string()));
}
#[test]
fn test_parse_var_expansion_all_params_at() {
assert_eq!(expand("@"), BashExpr::Variable("@".to_string()));
}
#[test]
fn test_parse_var_expansion_all_params_star() {
assert_eq!(expand("*"), BashExpr::Variable("*".to_string()));
}
#[test]
fn test_parse_var_expansion_param_count() {
assert_eq!(expand("#"), BashExpr::Variable("#".to_string()));
}
#[test]
fn test_parse_var_expansion_exit_status() {
assert_eq!(expand("?"), BashExpr::Variable("?".to_string()));
}
#[test]
fn test_parse_var_expansion_process_id() {
assert_eq!(expand("$"), BashExpr::Variable("$".to_string()));
}
#[test]
fn test_parse_var_expansion_in_echo_default() {
let stmts = parse_script("echo ${NAME:-World}");
match &stmts[0] {
BashStmt::Command { args, .. } => {
assert_eq!(
args[0],
BashExpr::DefaultValue {
variable: "NAME".to_string(),
default: Box::new(BashExpr::Literal("World".to_string())),
}
);
}
other => panic!("expected Command, got: {other:?}"),
}
}
#[test]
fn test_parse_var_expansion_in_assignment_string_length() {
let stmts = parse_script("LEN=${#STR}");
match &stmts[0] {
BashStmt::Assignment { value, .. } => {
assert_eq!(
*value,
BashExpr::StringLength {
variable: "STR".to_string(),
}
);
}
other => panic!("expected Assignment, got: {other:?}"),
}
}
#[test]
fn test_parse_test_file_exists() {
let expr = parse_condition("[ -f /tmp/file ]");
let test = unwrap_test(expr);
match test {
TestExpr::FileExists(BashExpr::Literal(path)) => {
assert!(path.contains("tmp") || path.contains("file"));
}
other => panic!("expected FileExists, got: {other:?}"),
}
}
#[test]
fn test_parse_test_directory() {
let expr = parse_condition("[ -d /tmp ]");
let test = unwrap_test(expr);
assert!(
matches!(test, TestExpr::FileDirectory(_)),
"expected FileDirectory, got: {test:?}"
);
}
#[test]
include!("parser_expr_tests_tests_parse.rs");