mod common;
use common::sqry_bin;
use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::TempDir;
#[test]
fn cli_shell_callers_simple_function() {
let project = TempDir::new().unwrap();
let shell_code = r#"#!/bin/bash
helper() {
echo "helper called"
}
main() {
helper
echo "done"
}
main
"#;
std::fs::write(project.path().join("script.sh"), shell_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:helper")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("main"));
}
#[test]
fn cli_shell_callers_nested_function() {
let project = TempDir::new().unwrap();
let shell_code = r#"#!/bin/bash
validate() {
return 0
}
process() {
validate
echo "processing"
}
run() {
process
}
"#;
std::fs::write(project.path().join("nested.sh"), shell_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:validate")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("process"));
}
#[test]
fn cli_shell_callers_command_substitution() {
let project = TempDir::new().unwrap();
let shell_code = r#"#!/bin/bash
get_value() {
echo "42"
}
compute() {
local result=$(get_value)
echo "$result"
}
"#;
std::fs::write(project.path().join("subst.sh"), shell_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:get_value")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("compute"));
}
#[test]
fn cli_shell_callees_function() {
let project = TempDir::new().unwrap();
let shell_code = r#"#!/bin/bash
log() {
echo "$1"
}
validate() {
return 0
}
process() {
log "starting"
validate
log "done"
}
"#;
std::fs::write(project.path().join("callees.sh"), shell_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callees:process")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("log").and(predicate::str::contains("validate")));
}
#[test]
fn cli_shell_multiple_callers() {
let project = TempDir::new().unwrap();
let shell_code = r#"#!/bin/bash
log() {
echo "$1"
}
process() {
log "processing"
}
main() {
log "starting"
process
}
"#;
std::fs::write(project.path().join("multiple.sh"), shell_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:log")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("process").and(predicate::str::contains("main")));
}
#[test]
fn cli_shell_exports_function_definitions() {
let project = TempDir::new().unwrap();
let shell_code = r#"#!/bin/bash
# User-defined function
my_function() {
echo "exported function"
}
# Another function
helper() {
return 0
}
"#;
std::fs::write(project.path().join("functions.sh"), shell_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:my_function")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("my_function"));
}
#[test]
fn cli_shell_exports_exclude_builtins() {
let project = TempDir::new().unwrap();
let shell_code = r#"#!/bin/bash
my_script() {
echo "user function"
cd /tmp
ls -la
}
"#;
std::fs::write(project.path().join("script.sh"), shell_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:my_script")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("my_script"));
Command::new(sqry_bin())
.arg("query")
.arg("exports:echo")
.arg(project.path())
.assert()
.success()
.stderr(predicate::str::contains("No matches found").or(predicate::str::is_empty()));
}