Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 3 additions & 17 deletions crates/git-cli/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use nils_test_support::StubBinDir;
use nils_test_support::bin::resolve;
use nils_test_support::cmd::{CmdOptions, CmdOutput, run_with};
pub use nils_test_support::git::git;
use nils_test_support::git::{InitRepoOptions, init_repo_with};
use nils_test_support::git::init_repo_main_with_initial_commit;
use tempfile::TempDir;

pub struct GitCliHarness {
Expand All @@ -22,17 +22,7 @@ impl GitCliHarness {
std::fs::create_dir_all(&xdg_config_home).expect("create XDG_CONFIG_HOME");

let stub_bin_dir = StubBinDir::new();
let pbcopy = nils_test_support::stubs::pbcopy_stub_script();
stub_bin_dir.write_exe("pbcopy", pbcopy.as_str());
let wl_copy = nils_test_support::stubs::wl_copy_stub_script();
stub_bin_dir.write_exe("wl-copy", wl_copy.as_str());
let xclip = nils_test_support::stubs::xclip_stub_script();
stub_bin_dir.write_exe("xclip", xclip.as_str());
let xsel = nils_test_support::stubs::xsel_stub_script();
stub_bin_dir.write_exe("xsel", xsel.as_str());
stub_bin_dir.write_exe("file", nils_test_support::stubs::file_stub_script());
let git_scope = nils_test_support::stubs::git_scope_stub_script();
stub_bin_dir.write_exe("git-scope", git_scope.as_str());
nils_test_support::stubs::install_git_cli_runtime_stubs(&stub_bin_dir);

Self {
home_dir,
Expand Down Expand Up @@ -75,11 +65,7 @@ impl Default for GitCliHarness {
}

pub fn init_repo() -> tempfile::TempDir {
init_repo_with(
InitRepoOptions::new()
.with_branch("main")
.with_initial_commit(),
)
init_repo_main_with_initial_commit()
}

pub fn init_bare_remote() -> tempfile::TempDir {
Expand Down
24 changes: 8 additions & 16 deletions crates/git-lock/tests/common.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,34 @@
#![allow(dead_code)]

use std::path::Path;
use std::process::Output;

use nils_test_support::bin::resolve;
use nils_test_support::cmd::{options_in_dir_with_envs, run_resolved};
use nils_test_support::git::{InitRepoOptions, init_repo_with};
use nils_test_support::cmd::run_resolved_in_dir_with_stdin_str;
use nils_test_support::git::init_repo_main_with_initial_commit;
#[allow(unused_imports)]
pub use nils_test_support::git::{commit_file, git, repo_id};

#[allow(dead_code)]
pub fn init_repo() -> tempfile::TempDir {
init_repo_with(
InitRepoOptions::new()
.with_branch("main")
.with_initial_commit(),
)
init_repo_main_with_initial_commit()
}

#[allow(dead_code)]
pub fn git_lock_bin() -> std::path::PathBuf {
resolve("git-lock")
}

#[allow(dead_code)]
pub fn run_git_lock_output(
dir: &Path,
args: &[&str],
envs: &[(&str, &str)],
input: Option<&str>,
) -> Output {
let mut options = options_in_dir_with_envs(dir, envs);
options = match input {
Some(data) => options.with_stdin_str(data),
None => options.with_stdin_bytes(&[]),
};

let output = run_resolved("git-lock", args, &options);
let output = run_resolved_in_dir_with_stdin_str("git-lock", dir, args, envs, input);
output.into_output()
}

#[allow(dead_code)]
pub fn run_git_lock(
dir: &Path,
args: &[&str],
Expand Down
31 changes: 0 additions & 31 deletions crates/image-processing/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,6 @@ impl Operation {
}
}

#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FromSvgValidationRule {
pub when: &'static str,
pub expect: &'static str,
}

#[allow(dead_code)]
pub const FROM_SVG_VALIDATION_MATRIX: [FromSvgValidationRule; 5] = [
FromSvgValidationRule {
when: "subcommand=convert",
expect: "requires --from-svg + --to png|webp|svg + --out",
},
FromSvgValidationRule {
when: "subcommand=convert",
expect: "forbids --in",
},
FromSvgValidationRule {
when: "subcommand=convert",
expect: "accepts optional --width/--height for png|webp outputs",
},
FromSvgValidationRule {
when: "subcommand=svg-validate",
expect: "requires exactly one --in and explicit --out",
},
FromSvgValidationRule {
when: "subcommand=svg-validate",
expect: "forbids --from-svg/--to/--width/--height",
},
];

#[derive(Debug, Parser)]
#[command(
name = "image-processing",
Expand Down
7 changes: 5 additions & 2 deletions crates/memo-cli/tests/support/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
#![allow(dead_code)]

use nils_test_support::cmd::{CmdOptions, CmdOutput, run_resolved};
use std::fs;
use std::path::{Path, PathBuf};

#[allow(dead_code)]
pub fn test_db_path(name: &str) -> PathBuf {
let dir = tempfile::tempdir().expect("tempdir should be created");
dir.keep().join(format!("{name}.db"))
}

#[allow(dead_code)]
pub fn parse_json_stdout(output: &CmdOutput) -> serde_json::Value {
serde_json::from_slice(&output.stdout).expect("stdout should be valid JSON")
}

#[allow(dead_code)]
pub fn fixture_json(name: &str) -> serde_json::Value {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests")
Expand All @@ -26,10 +27,12 @@ pub fn fixture_json(name: &str) -> serde_json::Value {
})
}

#[allow(dead_code)]
pub fn run_memo_cli(db_path: &Path, args: &[&str], stdin: Option<&str>) -> CmdOutput {
run_memo_cli_with_env(db_path, args, stdin, &[])
}

#[allow(dead_code)]
pub fn run_memo_cli_with_env(
db_path: &Path,
args: &[&str],
Expand Down
20 changes: 20 additions & 0 deletions crates/nils-test-support/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,26 @@ pub fn run_resolved_in_dir(
run_resolved(bin_name, args, &options)
}

/// Resolve and run a workspace binary in a specific directory with optional
/// UTF-8 stdin.
///
/// When `stdin` is `None`, this helper sends empty stdin bytes to keep test
/// command execution non-interactive.
pub fn run_resolved_in_dir_with_stdin_str(
bin_name: &str,
dir: &Path,
args: &[&str],
envs: &[(&str, &str)],
stdin: Option<&str>,
) -> CmdOutput {
let mut options = options_in_dir_with_envs(dir, envs);
options = match stdin {
Some(input) => options.with_stdin_str(input),
None => options.with_stdin_bytes(&[]),
};
run_resolved(bin_name, args, &options)
}

pub fn run_with(bin: &Path, args: &[&str], options: &CmdOptions) -> CmdOutput {
run_impl(bin, args, options, None)
}
Expand Down
8 changes: 8 additions & 0 deletions crates/nils-test-support/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ pub fn write_text(path: &Path, contents: &str) -> PathBuf {
path.to_path_buf()
}

pub fn write_text_in_dir(dir: &Path, rel: &str, contents: &str) -> PathBuf {
write_text(&dir.join(rel), contents)
}

pub fn write_bytes(path: &Path, contents: &[u8]) -> PathBuf {
ensure_parent_dir(path);
std::fs::write(path, contents).expect("write bytes");
Expand Down Expand Up @@ -41,3 +45,7 @@ pub fn write_executable(path: &Path, contents: &str) -> PathBuf {

path.to_path_buf()
}

pub fn write_executable_in_dir(dir: &Path, rel: &str, contents: &str) -> PathBuf {
write_executable(&dir.join(rel), contents)
}
12 changes: 12 additions & 0 deletions crates/nils-test-support/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ pub fn init_repo_with(options: InitRepoOptions) -> TempDir {
dir
}

pub fn init_repo_main() -> TempDir {
init_repo_with(InitRepoOptions::new().with_branch("main"))
}

pub fn init_repo_main_with_initial_commit() -> TempDir {
init_repo_with(
InitRepoOptions::new()
.with_branch("main")
.with_initial_commit(),
)
}

pub fn worktree_add_branch(repo: &Path, worktree_path: &Path, branch: &str) {
let worktree_path = worktree_path.to_string_lossy().to_string();
git(repo, &["worktree", "add", &worktree_path, "-b", branch]);
Expand Down
32 changes: 32 additions & 0 deletions crates/nils-test-support/src/stubs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,27 @@ pub fn git_scope_stub_script() -> String {
script
}

/// Install the default external command stubs used by git-cli integration
/// harnesses.
pub fn install_git_cli_runtime_stubs(dir: &crate::StubBinDir) {
let pbcopy = pbcopy_stub_script();
dir.write_exe("pbcopy", &pbcopy);

let wl_copy = wl_copy_stub_script();
dir.write_exe("wl-copy", &wl_copy);

let xclip = xclip_stub_script();
dir.write_exe("xclip", &xclip);

let xsel = xsel_stub_script();
dir.write_exe("xsel", &xsel);

dir.write_exe("file", file_stub_script());

let git_scope = git_scope_stub_script();
dir.write_exe("git-scope", &git_scope);
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -448,4 +469,15 @@ mod tests {
let git_scope = git_scope_stub_script();
assert_all_contains(&git_scope, &["echo \"git-scope $*\"", "exit 0"]);
}

#[test]
fn install_git_cli_runtime_stubs_writes_expected_executables() {
let dir = crate::StubBinDir::new();
install_git_cli_runtime_stubs(&dir);

for name in ["pbcopy", "wl-copy", "xclip", "xsel", "file", "git-scope"] {
let path = dir.path().join(name);
assert!(path.exists(), "missing stub executable: {}", path.display());
}
}
}
38 changes: 38 additions & 0 deletions crates/nils-test-support/tests/bin_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,44 @@ printf "%s|%s" "${NTS_REMOVE_ME-unset}" "${NTS_KEEP_ME-unset}"
assert_eq!(output.stdout_text(), "unset|present");
}

#[cfg(unix)]
#[test]
fn run_resolved_in_dir_with_stdin_str_supports_optional_text_stdin() {
let lock = GlobalStateLock::new();
let temp = TempDir::new().expect("tempdir");
let script = r#"#!/bin/sh
printf "%s|" "${NTS_VALUE-unset}"
cat -
"#;
write_exe(temp.path(), "resolved-stdin-test", script);
let bin = temp.path().join("resolved-stdin-test");
let _guard = EnvGuard::set(
&lock,
"CARGO_BIN_EXE_resolved-stdin-test",
bin.to_str().expect("path"),
);

let with_text = cmd::run_resolved_in_dir_with_stdin_str(
"resolved-stdin-test",
temp.path(),
&[],
&[("NTS_VALUE", "ok")],
Some("payload"),
);
assert_eq!(with_text.code, 0);
assert_eq!(with_text.stdout_text(), "ok|payload");

let without_text = cmd::run_resolved_in_dir_with_stdin_str(
"resolved-stdin-test",
temp.path(),
&[],
&[("NTS_VALUE", "ok")],
None,
);
assert_eq!(without_text.code, 0);
assert_eq!(without_text.stdout_text(), "ok|");
}

#[cfg(unix)]
#[test]
fn run_with_env_set_wins_after_env_remove() {
Expand Down
17 changes: 17 additions & 0 deletions crates/nils-test-support/tests/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ fn write_text_creates_parents_and_writes_contents() {
assert_eq!(std_fs::read_to_string(written).expect("read"), "hello\n");
}

#[test]
fn write_text_in_dir_joins_relative_path_and_writes_contents() {
let temp = tempfile::TempDir::new().expect("tempdir");
let written = fs::write_text_in_dir(temp.path(), "nested/dir/file.txt", "hello\n");
assert_eq!(std_fs::read_to_string(written).expect("read"), "hello\n");
}

#[test]
fn write_bytes_preserves_raw_bytes() {
let temp = tempfile::TempDir::new().expect("tempdir");
Expand Down Expand Up @@ -42,6 +49,16 @@ fn write_executable_writes_contents() {
);
}

#[test]
fn write_executable_in_dir_joins_relative_path() {
let temp = tempfile::TempDir::new().expect("tempdir");
let written = fs::write_executable_in_dir(temp.path(), "bin/run.sh", "#!/bin/sh\necho ok\n");
assert_eq!(
std_fs::read_to_string(written).expect("read"),
"#!/bin/sh\necho ok\n"
);
}

#[cfg(unix)]
#[test]
fn write_executable_sets_unix_mode() {
Expand Down
17 changes: 17 additions & 0 deletions crates/nils-test-support/tests/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ fn init_repo_with_default_branch_and_config() {
assert_eq!(email.trim_end(), "test@example.com");
}

#[test]
fn init_repo_main_sets_main_branch() {
let repo = git::init_repo_main();
let branch = git::git(repo.path(), &["symbolic-ref", "--short", "HEAD"]);
assert_eq!(branch.trim_end(), "main");
}

#[test]
fn init_repo_main_with_initial_commit_sets_main_and_commits() {
let repo = git::init_repo_main_with_initial_commit();
let branch = git::git(repo.path(), &["symbolic-ref", "--short", "HEAD"]);
assert_eq!(branch.trim_end(), "main");

let head = git::git(repo.path(), &["rev-parse", "HEAD"]);
assert_eq!(head.trim().len(), 40);
}

#[test]
fn init_repo_with_initial_commit_creates_commit() {
let repo = git::init_repo_with(git::InitRepoOptions::new().with_initial_commit());
Expand Down
Loading