zoxide/src/shell.rs

365 lines
12 KiB
Rust
Raw Normal View History

2021-05-03 21:12:43 +00:00
use crate::app::InitHook;
2020-11-10 19:11:26 +00:00
#[derive(Debug, Eq, PartialEq)]
pub struct Opts<'a> {
pub cmd: Option<&'a str>,
2021-05-03 21:12:43 +00:00
pub hook: InitHook,
pub echo: bool,
pub resolve_symlinks: bool,
}
macro_rules! make_template {
($name:ident, $path:expr) => {
#[derive(::std::fmt::Debug, ::askama::Template)]
#[template(path = $path)]
pub struct $name<'a>(pub &'a self::Opts<'a>);
impl<'a> ::std::ops::Deref for $name<'a> {
type Target = self::Opts<'a>;
fn deref(&self) -> &Self::Target {
self.0
}
}
};
}
make_template!(Bash, "bash.txt");
2021-04-08 18:35:42 +00:00
make_template!(Elvish, "elvish.txt");
make_template!(Fish, "fish.txt");
2021-03-31 16:45:43 +00:00
make_template!(Nushell, "nushell.txt");
make_template!(Posix, "posix.txt");
2021-03-31 16:45:43 +00:00
make_template!(Powershell, "powershell.txt");
make_template!(Xonsh, "xonsh.txt");
make_template!(Zsh, "zsh.txt");
2021-03-29 15:44:30 +00:00
#[cfg(feature = "shell_tests")]
#[cfg(test)]
mod tests {
use super::*;
use askama::Template;
use assert_cmd::Command;
use once_cell::sync::OnceCell;
2020-11-10 19:11:26 +00:00
use seq_macro::seq;
macro_rules! with_opts_size {
($macro:ident) => {
$macro!(24);
};
}
fn opts() -> &'static [Opts<'static>] {
static OPTS: OnceCell<Vec<Opts>> = OnceCell::new();
2020-11-10 19:11:26 +00:00
const BOOLS: &[bool] = &[false, true];
2021-05-03 21:12:43 +00:00
const HOOKS: &[InitHook] = &[InitHook::None, InitHook::Prompt, InitHook::Pwd];
2020-11-10 19:11:26 +00:00
const CMDS: &[Option<&str>] = &[None, Some("z")];
2020-11-10 19:11:26 +00:00
OPTS.get_or_init(|| {
let mut opts = Vec::new();
for &echo in BOOLS {
for &resolve_symlinks in BOOLS {
for &hook in HOOKS {
for &cmd in CMDS {
let opt = Opts {
2021-03-01 06:10:10 +00:00
cmd,
hook,
echo,
resolve_symlinks,
};
opts.push(opt);
}
}
}
}
2020-11-10 19:11:26 +00:00
// Verify that the value hardcoded into `with_opts_size` is correct.
macro_rules! id {
($x:literal) => {
$x
};
}
assert_eq!(opts.len(), with_opts_size!(id));
opts
})
}
2020-11-10 19:11:26 +00:00
macro_rules! generate_tests {
($N:literal) => {
seq!(i in 0..$N {
#[test]
fn bash_bash_#i() {
let opts = dbg!(&opts()[i]);
let source = Bash(opts).render().unwrap();
Command::new("bash")
2020-12-09 22:07:40 +00:00
.args(&["-c", &source, "--noediting", "--noprofile", "--norc"])
2020-11-10 19:11:26 +00:00
.assert()
.success()
.stdout("")
.stderr("");
}
2020-11-10 19:11:26 +00:00
#[test]
fn bash_shellcheck_#i() {
let opts = dbg!(&opts()[i]);
let source = Bash(opts).render().unwrap();
Command::new("shellcheck")
2020-11-11 12:53:37 +00:00
.args(&["--enable", "all", "--shell", "bash", "-"])
2020-11-10 19:11:26 +00:00
.write_stdin(source)
.assert()
.success()
.stdout("")
.stderr("");
}
2020-11-10 19:11:26 +00:00
#[test]
fn bash_shfmt_#i() {
let opts = dbg!(&opts()[i]);
let mut source = Bash(opts).render().unwrap();
source.push('\n');
2021-04-08 18:35:42 +00:00
2020-11-10 19:11:26 +00:00
Command::new("shfmt")
.args(&["-d", "-s", "-ln", "bash", "-i", "4", "-ci", "-"])
.write_stdin(source)
.assert()
.success()
.stdout("")
.stderr("");
}
2021-04-08 18:35:42 +00:00
#[test]
fn elvish_elvish_#i() {
let opts = dbg!(&opts()[i]);
let mut source = String::new();
// Filter out lines using edit:*, since those functions
// are only available in the interactive editor.
for line in Elvish(opts)
.render()
.unwrap()
.split('\n')
.filter(|line| !line.contains("edit:"))
{
source.push_str(line);
source.push('\n');
}
Command::new("elvish")
.args(&["-c", &source, "-norc"])
.assert()
.success()
.stdout("")
.stderr("");
}
2020-11-10 19:11:26 +00:00
#[test]
fn fish_fish_#i() {
let opts = dbg!(&opts()[i]);
let source = Fish(opts).render().unwrap();
2020-12-13 05:26:51 +00:00
let tempdir = tempfile::tempdir().unwrap();
let tempdir = tempdir.path().to_str().unwrap();
2020-11-10 19:11:26 +00:00
Command::new("fish")
.env("HOME", tempdir)
2020-12-09 22:07:40 +00:00
.args(&["--command", &source, "--private"])
2020-11-10 19:11:26 +00:00
.assert()
.success()
.stdout("")
.stderr("");
}
#[test]
fn fish_fishindent_#i() {
let opts = dbg!(&opts()[i]);
let mut source = Fish(opts).render().unwrap();
source.push('\n');
let tempdir = tempfile::tempdir().unwrap();
let tempdir = tempdir.path().to_str().unwrap();
Command::new("fish")
.env("HOME", tempdir)
.args(&["--command", "fish_indent", "--private"])
.write_stdin(source.to_string())
.assert()
.success()
.stdout(source)
.stderr("");
}
2021-03-31 16:45:43 +00:00
#[test]
fn nushell_nushell_#i() {
let opts = dbg!(&opts()[i]);
let source = Nushell(opts).render().unwrap();
let tempdir = tempfile::tempdir().unwrap();
let tempdir = tempdir.path().to_str().unwrap();
2021-03-31 16:45:43 +00:00
let assert = Command::new("nu")
.env("HOME", tempdir)
2021-03-31 16:45:43 +00:00
.args(&["--commands", &source])
.assert()
.success()
.stderr("");
2021-05-03 21:12:43 +00:00
if opts.hook != InitHook::Pwd {
2021-03-31 16:45:43 +00:00
assert.stdout("");
}
}
2020-11-10 19:11:26 +00:00
#[test]
fn posix_bashposix_#i() {
let opts = dbg!(&opts()[i]);
let source = Posix(opts).render().unwrap();
let assert = Command::new("bash")
2020-12-09 22:07:40 +00:00
.args(&["--posix", "-c", &source, "--noediting", "--noprofile", "--norc"])
2020-11-10 19:11:26 +00:00
.assert()
.success()
.stderr("");
2021-05-03 21:12:43 +00:00
if opts.hook != InitHook::Pwd {
2020-11-10 19:11:26 +00:00
assert.stdout("");
}
}
2020-11-10 19:11:26 +00:00
#[test]
fn posix_dash_#i() {
let opts = dbg!(&opts()[i]);
let source = Posix(opts).render().unwrap();
let assert = Command::new("dash")
.args(&["-c", &source])
.assert()
.success()
.stderr("");
2021-05-03 21:12:43 +00:00
if opts.hook != InitHook::Pwd {
2020-11-10 19:11:26 +00:00
assert.stdout("");
}
}
2020-11-10 19:11:26 +00:00
#[test]
fn posix_shellcheck_#i() {
let opts = dbg!(&opts()[i]);
let source = Posix(opts).render().unwrap();
Command::new("shellcheck")
2020-11-11 12:53:37 +00:00
.args(&["--enable", "all", "--shell", "sh", "-"])
2020-11-10 19:11:26 +00:00
.write_stdin(source)
.assert()
.success()
.stdout("")
.stderr("");
}
#[test]
fn posix_shfmt_#i() {
let opts = dbg!(&opts()[i]);
let mut source = Posix(opts).render().unwrap();
source.push('\n');
2021-04-08 18:35:42 +00:00
2020-11-10 19:11:26 +00:00
Command::new("shfmt")
.args(&["-d", "-s", "-ln", "posix", "-i", "4", "-ci", "-"])
.write_stdin(source)
.assert()
.success()
.stdout("")
.stderr("");
}
2020-11-10 19:11:26 +00:00
#[test]
fn powershell_pwsh_#i() {
let opts = dbg!(&opts()[i]);
2021-03-31 16:45:43 +00:00
let source = Powershell(opts).render().unwrap();
2020-11-10 19:11:26 +00:00
Command::new("pwsh")
2020-12-09 22:07:40 +00:00
.args(&["-Command", &source, "-NoLogo", "-NonInteractive", "-NoProfile"])
2020-11-10 19:11:26 +00:00
.assert()
.success()
.stdout("")
.stderr("");
}
#[test]
fn xonsh_black_#i() {
let opts = dbg!(&opts()[i]);
let mut source = Xonsh(opts).render().unwrap();
source.push('\n');
Command::new("black")
.args(&["--check", "--diff", "-"])
.write_stdin(source)
.assert()
.success()
.stdout("");
}
#[test]
fn xonsh_mypy_#i() {
let opts = dbg!(&opts()[i]);
let source = Xonsh(opts).render().unwrap();
Command::new("mypy")
.args(&["--command", &source])
.assert()
.success()
.stderr("");
}
#[test]
fn xonsh_pylint_#i() {
let opts = dbg!(&opts()[i]);
let mut source = Xonsh(opts).render().unwrap();
source.push('\n');
Command::new("pylint")
.args(&["--from-stdin", "zoxide"])
.write_stdin(source)
.assert()
.success()
.stderr("");
}
#[test]
// Xonsh complains about type-hinting here, although it works fine in practice.
// <https://github.com/xonsh/xonsh/issues/3959>
2020-11-10 19:11:26 +00:00
#[ignore]
fn xonsh_xonsh_#i() {
let opts = dbg!(&opts()[i]);
let source = Xonsh(opts).render().unwrap();
Command::new("xonsh")
2020-12-09 22:07:40 +00:00
.args(&["-c", &source, "--no-rc"])
2020-11-10 19:11:26 +00:00
.assert()
.success()
.stdout("")
.stderr("");
}
#[test]
fn zsh_shellcheck_#i() {
let opts = dbg!(&opts()[i]);
let source = Zsh(opts).render().unwrap();
// ShellCheck doesn't support zsh yet.
// https://github.com/koalaman/shellcheck/issues/809
Command::new("shellcheck")
.args(&["--enable", "all", "--shell", "bash", "-"])
.write_stdin(source)
.assert()
.success()
.stdout("")
.stderr("");
}
2020-11-10 19:11:26 +00:00
#[test]
fn zsh_zsh_#i() {
let opts = dbg!(&opts()[i]);
let source = Zsh(opts).render().unwrap();
Command::new("zsh")
2020-12-09 22:07:40 +00:00
.args(&["-c", &source, "--no-rcs"])
2020-11-10 19:11:26 +00:00
.assert()
.success()
.stdout("")
.stderr("");
}
});
}
}
2020-11-10 19:11:26 +00:00
with_opts_size!(generate_tests);
}