Skip to content

Commit 074b283

Browse files
committed
Add documentation to test-tools.
1 parent 5e58eb4 commit 074b283

File tree

1 file changed

+50
-20
lines changed

1 file changed

+50
-20
lines changed

tests/tools/src/lib.rs

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! Utilities for testing `gitoxide` crates, many of which might be useful for testing programs that use `git` in general.
2+
#![deny(missing_docs)]
3+
use std::ffi::OsString;
14
use std::{
25
collections::BTreeMap,
36
convert::Infallible,
@@ -15,6 +18,20 @@ use once_cell::sync::Lazy;
1518
use parking_lot::Mutex;
1619
pub use tempfile;
1720

21+
/// A result type to allow using the try operator `?` in unit tests.
22+
///
23+
/// Use it like so:
24+
///
25+
/// ```norun
26+
/// use git_testtools::Result;
27+
///
28+
/// #[test]
29+
/// fn this() -> Result {
30+
/// let x: usize = "42".parse()?;
31+
/// Ok(())
32+
///
33+
/// }
34+
/// ```
1835
pub type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error>>;
1936

2037
static SCRIPT_IDENTITY: Lazy<Mutex<BTreeMap<PathBuf, u32>>> = Lazy::new(|| Mutex::new(BTreeMap::new()));
@@ -46,49 +63,58 @@ static EXCLUDE_LUT: Lazy<Mutex<Option<git_worktree::fs::Cache<'static>>>> = Lazy
4663
Mutex::new(cache)
4764
});
4865

66+
/// Define how [scripted_fixture_repo_writable_with_args()] uses produces the writable copy.
4967
pub enum Creation {
68+
/// Run the script once and copy the data from its output to the writable location.
69+
/// This is fast but won't work if absolute paths are produced by the script.
5070
CopyFromReadOnly,
71+
/// Run the script in the writable location. That way, absolute paths match the location.
5172
ExecuteScript,
5273
}
5374

75+
/// Run `git` in `working_dir` with all provided `args`.
5476
pub fn run_git(working_dir: &Path, args: &[&str]) -> std::io::Result<std::process::ExitStatus> {
5577
std::process::Command::new("git")
5678
.current_dir(working_dir)
5779
.args(args)
5880
.status()
5981
}
6082

83+
/// Convert a hexadecimal hash into its corresponding `ObjectId` or _panic_.
6184
pub fn hex_to_id(hex: &str) -> git_hash::ObjectId {
6285
git_hash::ObjectId::from_hex(hex.as_bytes()).expect("40 bytes hex")
6386
}
6487

88+
/// Return the path to the `<crate-root>/tests/fixtures/<path>` directory.
6589
pub fn fixture_path(path: impl AsRef<Path>) -> PathBuf {
6690
PathBuf::from("tests").join("fixtures").join(path.as_ref())
6791
}
6892

69-
pub fn crate_under_test() -> String {
70-
std::env::current_dir()
71-
.expect("CWD is valid")
72-
.file_name()
73-
.expect("typical cargo invocation")
74-
.to_string_lossy()
75-
.into_owned()
76-
}
77-
93+
/// Load the fixture from `<crate-root>/tests/fixtures/<path>` and return its data, or _panic_.
7894
pub fn fixture_bytes(path: impl AsRef<Path>) -> Vec<u8> {
7995
match std::fs::read(fixture_path(path.as_ref())) {
8096
Ok(res) => res,
8197
Err(_) => panic!("File at '{}' not found", path.as_ref().display()),
8298
}
8399
}
100+
101+
/// Run the executable at `script_name`, like `make_repo.sh` to produce a read-only directory to which
102+
/// the path is returned.
103+
/// Note that it persists and the script at `script_name` will only be executed once if it ran without error.
84104
pub fn scripted_fixture_repo_read_only(script_name: impl AsRef<Path>) -> Result<PathBuf> {
85105
scripted_fixture_repo_read_only_with_args(script_name, None)
86106
}
87107

108+
/// Run the executable at `script_name`, like `make_repo.sh` to produce a writable directory to which
109+
/// the tempdir is returned. It will be removed automatically, courtesy of [`tempfile::TempDir`].
110+
///
111+
/// Note that `script_name` is only executed once, so the data can be copied from its read-only location.
88112
pub fn scripted_fixture_repo_writable(script_name: &str) -> Result<tempfile::TempDir> {
89113
scripted_fixture_repo_writable_with_args(script_name, None, Creation::CopyFromReadOnly)
90114
}
91115

116+
/// Like [`scripted_fixture_repo_writable()`], but passes `args` to `script_name` while providing control over
117+
/// the way files are created with `mode`.
92118
pub fn scripted_fixture_repo_writable_with_args(
93119
script_name: &str,
94120
args: impl IntoIterator<Item = &'static str>,
@@ -108,6 +134,7 @@ pub fn scripted_fixture_repo_writable_with_args(
108134
})
109135
}
110136

137+
/// A utility to copy the entire contents of `src_dir` into `dst_dir`.
111138
pub fn copy_recursively_into_existing_dir(src_dir: impl AsRef<Path>, dst_dir: impl AsRef<Path>) -> std::io::Result<()> {
112139
fs_extra::copy_items(
113140
&std::fs::read_dir(src_dir)?
@@ -125,7 +152,8 @@ pub fn copy_recursively_into_existing_dir(src_dir: impl AsRef<Path>, dst_dir: im
125152
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?;
126153
Ok(())
127154
}
128-
/// Returns the directory at which the data is present
155+
156+
/// Like `scripted_fixture_repo_read_only()`], but passes `args` to `script_name`.
129157
pub fn scripted_fixture_repo_read_only_with_args(
130158
script_name: impl AsRef<Path>,
131159
args: impl IntoIterator<Item = &'static str>,
@@ -387,6 +415,7 @@ fn extract_archive(
387415
Ok((archive_identity, platform))
388416
}
389417

418+
/// Transform a verbose bom errors from raw bytes into a `BStr` to make printing/debugging human-readable.
390419
pub fn to_bstr_err(err: nom::Err<VerboseError<&[u8]>>) -> VerboseError<&BStr> {
391420
let err = match err {
392421
nom::Err::Error(err) | nom::Err::Failure(err) => err,
@@ -405,35 +434,36 @@ fn family_name() -> &'static str {
405434
}
406435
}
407436

408-
pub fn sleep_forever() -> ! {
409-
loop {
410-
std::thread::sleep(std::time::Duration::from_secs(u64::MAX))
411-
}
412-
}
413-
437+
/// A utility to set environment variables, while unsetting them (or resetting them to their previous value) on drop.
414438
#[derive(Default)]
415439
pub struct Env<'a> {
416-
altered_vars: Vec<&'a str>,
440+
altered_vars: Vec<(&'a str, Option<OsString>)>,
417441
}
418442

419443
impl<'a> Env<'a> {
444+
/// Create a new instance.
420445
pub fn new() -> Self {
421446
Env {
422447
altered_vars: Vec::new(),
423448
}
424449
}
425450

451+
/// Set `var` to `value`.
426452
pub fn set(mut self, var: &'a str, value: impl Into<String>) -> Self {
453+
let prev = std::env::var_os(var);
427454
std::env::set_var(var, value.into());
428-
self.altered_vars.push(var);
455+
self.altered_vars.push((var, prev));
429456
self
430457
}
431458
}
432459

433460
impl<'a> Drop for Env<'a> {
434461
fn drop(&mut self) {
435-
for var in &self.altered_vars {
436-
std::env::remove_var(var);
462+
for (var, prev_value) in &self.altered_vars {
463+
match prev_value {
464+
Some(value) => std::env::set_var(var, value),
465+
None => std::env::remove_var(var),
466+
}
437467
}
438468
}
439469
}

0 commit comments

Comments
 (0)