mirror of
https://github.com/lotabout/skim.git
synced 2026-09-10 07:16:23 -04:00
test: add unit tests for the shell & manpage generators (#1098)
* test: add unit tests for the shell & manpage generators * chore: propagate key bindings generation errors
This commit is contained in:
parent
b56eed4125
commit
8187a12196
3
justfile
3
justfile
|
|
@ -86,3 +86,6 @@ pr-review id="":
|
|||
|
||||
just generate-files
|
||||
(git add man/ shell/ && git commit -m 'chore: generate-files' && git push) || echo "Nothing to do"
|
||||
|
||||
coverage args="":
|
||||
cargo llvm-cov nextest --lib --bins --examples --tests {{ args }}
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@ fn main() -> Result<()> {
|
|||
// Shell completion scripts
|
||||
if let Some(shell) = opts.shell {
|
||||
// Generate completion script directly to stdout
|
||||
skim::shell::generate_completions(&shell);
|
||||
skim::shell::generate_completions(&shell, &mut std::io::stdout());
|
||||
if opts.shell_bindings {
|
||||
skim::shell::generate_key_bindings(&shell);
|
||||
skim::shell::generate_key_bindings(&shell, &mut std::io::stdout())?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -365,3 +365,40 @@ Example:
|
|||
base.render_version_section(w)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn manpage_str() -> String {
|
||||
let mut buf = Vec::new();
|
||||
generate(&mut buf).expect("manpage generation should not fail");
|
||||
String::from_utf8(buf).expect("manpage output is valid UTF-8")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manpage_contains_version() {
|
||||
let out = manpage_str();
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
assert!(
|
||||
out.contains(version),
|
||||
"manpage should contain package version {version}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manpage_contains_key_options() {
|
||||
let out = manpage_str();
|
||||
for flag in ["query", "multi", "preview", "bind", "color"] {
|
||||
assert!(out.contains(flag), "manpage should mention '--{flag}'");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manpage_contains_sections() {
|
||||
let out = manpage_str();
|
||||
for section in ["MODES", "SEARCH", "KEYBINDS", "EXIT CODES"] {
|
||||
assert!(out.contains(section), "manpage should contain section '{section}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
127
src/shell.rs
127
src/shell.rs
|
|
@ -1,4 +1,6 @@
|
|||
//! Provides helpers to easily generate shell completions
|
||||
use std::io::Write;
|
||||
|
||||
use clap::CommandFactory;
|
||||
|
||||
use crate::SkimOptions;
|
||||
|
|
@ -21,9 +23,8 @@ pub enum Shell {
|
|||
}
|
||||
|
||||
/// Generate the completion and write it to stdout
|
||||
pub fn generate_completions(sh: &Shell) {
|
||||
pub fn generate_completions(sh: &Shell, output: &mut impl Write) {
|
||||
use Shell::{Bash, Elvish, Fish, Nushell, PowerShell, Zsh};
|
||||
let output = &mut std::io::stdout();
|
||||
let cmd = &mut SkimOptions::command();
|
||||
let bin_name = "sk";
|
||||
|
||||
|
|
@ -42,8 +43,10 @@ pub fn generate_completions(sh: &Shell) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Generate the key-bindings script and write it to stdout
|
||||
pub fn generate_key_bindings(sh: &Shell) {
|
||||
/// Generate the key-bindings script and write it to the given writer
|
||||
/// # Errors
|
||||
/// This errors if it fails to write the bytes to the output
|
||||
pub fn generate_key_bindings(sh: &Shell, output: &mut impl Write) -> std::io::Result<()> {
|
||||
use Shell::{Bash, Fish, Zsh};
|
||||
let binds_script = match sh {
|
||||
Bash => include_str!("../shell/key-bindings.bash"),
|
||||
|
|
@ -52,6 +55,120 @@ pub fn generate_key_bindings(sh: &Shell) {
|
|||
_ => "",
|
||||
};
|
||||
if !binds_script.is_empty() {
|
||||
println!("{binds_script}");
|
||||
output.write_all(binds_script.as_bytes())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn completions_for(sh: &Shell) -> String {
|
||||
let mut buf = Vec::new();
|
||||
generate_completions(sh, &mut buf);
|
||||
String::from_utf8(buf).expect("completion output is valid UTF-8")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completions_bash_contains_sk() {
|
||||
let out = completions_for(&Shell::Bash);
|
||||
assert!(out.contains("sk"), "bash completion should reference 'sk'");
|
||||
assert!(
|
||||
out.contains("--query") || out.contains("query"),
|
||||
"bash completion should include --query"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completions_zsh_contains_sk() {
|
||||
let out = completions_for(&Shell::Zsh);
|
||||
assert!(out.contains("sk"), "zsh completion should reference 'sk'");
|
||||
assert!(
|
||||
out.contains("--multi") || out.contains("multi"),
|
||||
"zsh completion should include --multi"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completions_fish_contains_sk() {
|
||||
let out = completions_for(&Shell::Fish);
|
||||
assert!(out.contains("sk"), "fish completion should reference 'sk'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completions_nushell_is_non_empty() {
|
||||
let out = completions_for(&Shell::Nushell);
|
||||
assert!(!out.is_empty(), "nushell completion should not be empty");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completions_elvish_is_non_empty() {
|
||||
let out = completions_for(&Shell::Elvish);
|
||||
assert!(!out.is_empty(), "elvish completion should not be empty");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completions_powershell_is_non_empty() {
|
||||
let out = completions_for(&Shell::PowerShell);
|
||||
assert!(!out.is_empty(), "powershell completion should not be empty");
|
||||
}
|
||||
|
||||
fn key_bindings_for(sh: &Shell) -> String {
|
||||
let mut buf = Vec::new();
|
||||
generate_key_bindings(sh, &mut buf).expect("key-bindings generation failed");
|
||||
String::from_utf8(buf).expect("key-bindings output is valid UTF-8")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_bindings_bash() {
|
||||
let out = key_bindings_for(&Shell::Bash);
|
||||
assert!(
|
||||
out.starts_with("# skim key bindings for bash"),
|
||||
"unexpected bash header"
|
||||
);
|
||||
assert!(out.contains("__skim_select__()"), "missing __skim_select__ function");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_bindings_zsh() {
|
||||
let out = key_bindings_for(&Shell::Zsh);
|
||||
assert!(out.starts_with("# skim key bindings for zsh"), "unexpected zsh header");
|
||||
for func in [
|
||||
"__skimcmd()",
|
||||
"__skim_comprun()",
|
||||
"__skim_extract_command()",
|
||||
"__skim_generic_path_completion()",
|
||||
"_skim_complete()",
|
||||
"_skim_complete_kill()",
|
||||
] {
|
||||
assert!(out.contains(func), "missing zsh function {func}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_bindings_fish() {
|
||||
let out = key_bindings_for(&Shell::Fish);
|
||||
assert!(
|
||||
out.starts_with("#!/bin/fish"),
|
||||
"fish key-bindings should start with shebang"
|
||||
);
|
||||
for func in [
|
||||
"function __skimcmd",
|
||||
"function __skim_parse_commandline",
|
||||
"function __skim_get_dir",
|
||||
] {
|
||||
assert!(out.contains(func), "missing fish function '{func}'");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_bindings_unsupported_shells_are_empty() {
|
||||
for sh in [Shell::Elvish, Shell::Nushell, Shell::PowerShell] {
|
||||
assert!(
|
||||
key_bindings_for(&sh).is_empty(),
|
||||
"{sh:?} should produce no key-bindings output"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue