diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 8fec0140..52c04975 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,6 +1,7 @@ use assert_cmd::Command; use predicates::{prelude::predicate, str::PredicateStrExt}; -use std::path::Path; +use std::env; +use std::path::{Path, PathBuf}; use std::str::from_utf8; const EXAMPLES_DIR: &str = "tests/examples"; @@ -23,6 +24,61 @@ fn bat() -> Command { cmd } +/// For some tests we want mocked versions of some pagers +/// This fn returns the absolute path to the directory with these mocked pagers +fn get_mocked_pagers_dir() -> PathBuf { + let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("Missing CARGO_MANIFEST_DIR"); + Path::new(&cargo_manifest_dir) + .join("tests") + .join("mocked-pagers") +} + +/// Prepends a directory to the PATH environment variable +/// Returns the original value for later restoration +fn prepend_dir_to_path_env_var(dir: PathBuf) -> String { + // Get current PATH + let original_path = env::var("PATH").expect("No PATH?!"); + + // Add the new dir first + let mut split_paths = env::split_paths(&original_path).collect::>(); + split_paths.insert(0, dir); + + // Set PATH with the new dir + let new_path = env::join_paths(split_paths).expect("Failed to join paths"); + env::set_var("PATH", new_path); + + // Return the original value for later restoration of it + original_path +} + +/// Helper to restore the value of PATH +fn restore_path(original_path: String) { + env::set_var("PATH", original_path); +} + +/// Allows test to run that require our mocked versions of 'more' and 'most' +/// in PATH. Temporarily changes PATH while the test code runs, and then restore it +/// to avoid pollution of global state +fn with_mocked_versions_of_more_and_most_in_path(actual_test: fn()) { + let original_path = prepend_dir_to_path_env_var(get_mocked_pagers_dir()); + + // Make sure our own variants of 'more' and 'most' is used + Command::new("more") + .assert() + .success() + .stdout("I am more\n"); + Command::new("most") + .assert() + .success() + .stdout("I am most\n"); + + // Now run the actual test + actual_test(); + + // Make sure to restore PATH since it is global state + restore_path(original_path); +} + #[test] fn basic() { bat() @@ -415,28 +471,77 @@ fn pager_value_bat() { .failure(); } +/// We shall use less instead of most if PAGER is used since PAGER +/// is a generic env var #[test] -fn pager_most() { - bat() - .env("PAGER", "most") - .arg("--paging=always") - .arg("test.txt") - .assert() - .success() - .stdout(predicate::eq("hello world\n").normalize()); - // TODO: How to ensure less is used? +fn pager_most_from_pager_env_var() { + with_mocked_versions_of_more_and_most_in_path(|| { + // If the output is not "I am most\n" then we know 'most' is not used + bat() + .env("PAGER", "most") + .arg("--paging=always") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::eq("hello world\n").normalize()); + }); } +/// If the bat-specific BAT_PAGER is used, obey the wish of the user +/// and allow 'most' +#[test] +fn pager_most_from_bat_pager_env_var() { + with_mocked_versions_of_more_and_most_in_path(|| { + bat() + .env("BAT_PAGER", "most") + .arg("--paging=always") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::eq("I am most\n").normalize()); + }); +} + +/// Same reasoning with --pager as with BAT_PAGER +#[test] +fn pager_most_from_pager_arg() { + with_mocked_versions_of_more_and_most_in_path(|| { + bat() + .arg("--paging=always") + .arg("--pager=most") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::eq("I am most\n").normalize()); + }); +} + +/// Make sure the logic for 'most' applies even if an argument is passed #[test] fn pager_most_with_arg() { - bat() - .env("PAGER", "most -w") - .arg("--paging=always") - .arg("test.txt") - .assert() - .success() - .stdout(predicate::eq("hello world\n").normalize()); - // TODO: How to ensure less is used? + with_mocked_versions_of_more_and_most_in_path(|| { + bat() + .env("PAGER", "most -w") + .arg("--paging=always") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::eq("hello world\n").normalize()); + }); +} + +/// Sanity check that 'more' is treated like 'most' +#[test] +fn pager_more() { + with_mocked_versions_of_more_and_most_in_path(|| { + bat() + .env("PAGER", "more") + .arg("--paging=always") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::eq("hello world\n").normalize()); + }); } #[test] diff --git a/tests/mocked-pagers/more b/tests/mocked-pagers/more new file mode 100755 index 00000000..9b14f0b7 --- /dev/null +++ b/tests/mocked-pagers/more @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "I am more" diff --git a/tests/mocked-pagers/most b/tests/mocked-pagers/most new file mode 100755 index 00000000..ec0962e5 --- /dev/null +++ b/tests/mocked-pagers/most @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "I am most"