create src

This commit is contained in:
awfixer
2026-03-11 02:04:19 -07:00
commit 52f7a22bf2
2595 changed files with 402870 additions and 0 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -eu -o pipefail
git init -q
# Shouldn't be necessary, as a repo starts with some config vars, but this removes any doubt.
git config --local foo.bar baz

View File

@@ -0,0 +1,100 @@
use bstr::ByteSlice;
use gix_path::{to_unix_separators, to_windows_separators};
#[test]
fn assure_unix_separators() {
assert_eq!(to_unix_separators(b"no-backslash".as_bstr()).as_bstr(), "no-backslash");
assert_eq!(to_unix_separators(br"\a\b\\".as_bstr()).as_bstr(), "/a/b//");
}
#[test]
fn assure_windows_separators() {
assert_eq!(
to_windows_separators(b"no-backslash".as_bstr()).as_bstr(),
"no-backslash"
);
assert_eq!(to_windows_separators(b"/a/b//".as_bstr()).as_bstr(), r"\a\b\\");
}
mod normalize;
mod join_bstr_unix_pathsep {
use bstr::BStr;
use gix_path::join_bstr_unix_pathsep;
fn b(s: &str) -> &BStr {
s.into()
}
#[test]
fn typical_with_double_slash_avoidance() {
assert_eq!(join_bstr_unix_pathsep(b("base"), "path"), b("base/path"));
assert_eq!(
join_bstr_unix_pathsep(b("base/"), "path"),
b("base/path"),
"no double slashes"
);
assert_eq!(join_bstr_unix_pathsep(b("/base"), "path"), b("/base/path"));
assert_eq!(join_bstr_unix_pathsep(b("/base/"), "path"), b("/base/path"));
}
#[test]
fn relative_base_or_path_are_nothing_special() {
assert_eq!(join_bstr_unix_pathsep(b("base"), "."), b("base/."));
assert_eq!(join_bstr_unix_pathsep(b("base"), ".."), b("base/.."));
assert_eq!(join_bstr_unix_pathsep(b("base"), "../dir"), b("base/../dir"));
}
#[test]
fn absolute_path_produces_double_slashes() {
assert_eq!(join_bstr_unix_pathsep(b("/base"), "/root"), b("/base//root"));
assert_eq!(join_bstr_unix_pathsep(b("base/"), "/root"), b("base//root"));
}
#[test]
fn empty_path_makes_base_end_with_a_slash() {
assert_eq!(join_bstr_unix_pathsep(b("base"), ""), b("base/"));
assert_eq!(join_bstr_unix_pathsep(b("base/"), ""), b("base/"));
}
#[test]
fn empty_base_leaves_everything_untouched() {
assert_eq!(join_bstr_unix_pathsep(b(""), ""), b(""));
assert_eq!(join_bstr_unix_pathsep(b(""), "hi"), b("hi"));
assert_eq!(join_bstr_unix_pathsep(b(""), "/hi"), b("/hi"));
}
}
mod relativize_with_prefix {
fn r(path: &str, prefix: &str) -> String {
gix_path::to_unix_separators_on_windows(
gix_path::os_str_into_bstr(gix_path::relativize_with_prefix(path.as_ref(), prefix.as_ref()).as_os_str())
.expect("no illformed UTF-8"),
)
.to_string()
}
#[test]
fn basics() {
assert_eq!(
r("a", "a"),
".",
"reaching the prefix is signalled by a '.', the current dir"
);
assert_eq!(r("a/b/c", "a/b"), "c", "'c' is clearly within the current directory");
assert_eq!(
r("c/b/c", "a/b"),
"../../c/b/c",
"when there is a complete disjoint prefix, we have to get out of it with ../"
);
assert_eq!(
r("a/a", "a/b"),
"../a",
"when there is mismatch, we have to get out of the CWD"
);
assert_eq!(
r("a/a", ""),
"a/a",
"empty prefix means nothing happens (and no work is done)"
);
assert_eq!(r("", ""), "", "empty stays empty");
}
}

View File

@@ -0,0 +1,147 @@
use std::{borrow::Cow, path::Path};
use gix_path::normalize;
fn p(input: &str) -> &Path {
Path::new(input)
}
#[test]
fn no_change_if_there_are_no_trailing_relative_components() {
for input in ["./a/b/c/d", "/absolute/path", r"C:\hello\world"] {
let path = p(input);
assert_eq!(normalize(path.into(), &std::env::current_dir().unwrap()).unwrap(), path);
}
}
#[test]
fn special_cases_around_cwd() -> crate::Result {
let cwd = std::env::current_dir()?;
assert_eq!(
normalize(p("./../../.git/modules/src/llvm-project").into(), &cwd).unwrap(),
cwd.parent()
.unwrap()
.parent()
.unwrap()
.join(".git/modules/src/llvm-project"),
"'.' is handled specifically to not fail to swap in the CWD"
);
assert_eq!(
normalize((&cwd).into(), &cwd).unwrap(),
cwd,
"absolute inputs yield absolute outputs"
);
assert_eq!(
normalize(p("a/../..").into(), &cwd).unwrap(),
cwd.parent().expect("parent"),
"it automatically extends the pop-able items by using the current working dir"
);
assert_eq!(
normalize(p("a/..").into(), &cwd).unwrap(),
p("."),
"absolute CWDs are always shortened…"
);
assert_eq!(
normalize(p("./a/..").into(), &cwd).unwrap(),
p("."),
"…like this as well…"
);
assert_eq!(
normalize((&cwd).into(), &cwd).unwrap(),
cwd,
"…but only if there were relative to begin with."
);
assert_eq!(
normalize(p(".").into(), &cwd).unwrap(),
p("."),
"and this means that `.`. stays `.`"
);
{
let mut path = cwd.clone();
let last_component = path.file_name().expect("directory").to_owned();
path.push("..");
path.push(last_component);
assert_eq!(
normalize(path.into(), &cwd).unwrap(),
cwd,
"absolute input paths stay absolute"
);
}
Ok(())
}
#[test]
fn parent_dirs_cause_the_cwd_to_be_used() {
assert_eq!(
normalize(p("./a/b/../../..").into(), "/users/name".as_ref())
.unwrap()
.as_ref(),
p("/users")
);
}
#[test]
fn multiple_parent_dir_movements_eat_into_the_current_dir() {
assert_eq!(
normalize(p("../../../d/e").into(), "/users/name/a/b/c".as_ref())
.unwrap()
.as_ref(),
p("/users/name/d/e")
);
assert_eq!(
normalize(p("c/../../../d/e").into(), "/users/name/a/b".as_ref())
.unwrap()
.as_ref(),
p("/users/name/d/e")
);
}
#[test]
fn walking_up_too_much_yield_none() {
let cwd = "/users/name".as_ref();
assert_eq!(normalize(p("./a/b/../../../../../.").into(), cwd), None);
assert_eq!(normalize(p("./a/../../../..").into(), cwd), None);
}
#[test]
fn trailing_directories_after_too_numerous_parent_dirs_yield_none() {
assert_eq!(
normalize(p("./a/b/../../../../../actually-invalid").into(), "/users".as_ref()).as_ref(),
None,
);
assert_eq!(
normalize(p("/a/b/../../..").into(), "/does-not/matter".as_ref()).as_ref(),
None,
);
}
#[test]
fn trailing_relative_components_are_resolved() {
let cwd = Path::new("/a/b/c");
for (input, expected) in [
("./a/b/./c/../d/..", "./a/b"),
("a/./b/c/.././..", "a"),
("/a/b/c/.././../.", "/a"),
("./a/..", "."),
("a/..", "."),
("./a", "./a"),
("./a/./b", "./a/./b"),
("./a/./b/..", "./a/."),
("/a/./b/c/.././../.", "/a"),
("/a/./b", "/a/./b"),
("././/a/./b", "././/a/./b"),
("/a/././c/.././../.", "/"),
("/a/b/../c/../..", "/"),
("C:/hello/../a", "C:/a"),
("./a/../b/..", "./"),
("/a/../b", "/b"),
] {
let path = p(input);
assert_eq!(
normalize(path.into(), cwd).unwrap_or_else(|| panic!("{path:?}")),
Cow::Borrowed(p(expected)),
"'{input}' got an unexpected result"
);
}
}

100
src-path/tests/path/env.rs Normal file
View File

@@ -0,0 +1,100 @@
use std::path::Path;
#[test]
fn exe_invocation() {
let actual = gix_path::env::exe_invocation();
assert!(
!actual.as_os_str().is_empty(),
"it finds something as long as git is installed somewhere on the system (or a default location)"
);
}
#[test]
fn shell() {
assert!(
Path::new(gix_path::env::shell()).exists(),
"On CI and on Unix we expect a usable path to the shell that exists on disk"
);
}
#[test]
fn shell_absolute() {
assert!(
Path::new(gix_path::env::shell()).is_absolute(),
"On CI and on Unix we currently expect the path to the shell always to be absolute"
);
}
#[test]
fn shell_unix_path() {
let shell = gix_path::env::shell()
.to_str()
.expect("This test depends on the shell path being valid Unicode");
assert!(
!shell.contains('\\'),
"The path to the shell should have no backslashes, barring strange `GIT_EXEC_PATH` values"
);
}
#[test]
fn installation_config() {
assert_ne!(
gix_path::env::installation_config().map(|p| p.components().count()),
gix_path::env::installation_config_prefix().map(|p| p.components().count()),
"the prefix is a bit shorter than the installation config path itself"
);
}
#[test]
fn core_dir() {
assert!(
gix_path::env::core_dir()
.expect("Git is always in PATH when we run tests")
.is_dir(),
"The core directory is a valid directory"
);
}
#[test]
fn system_prefix() {
assert_ne!(
gix_path::env::system_prefix(),
None,
"git should be present when running tests"
);
}
#[test]
fn home_dir() {
assert_ne!(
gix_path::env::home_dir(),
None,
"we find a home on every system these tests execute"
);
}
mod xdg_config {
use std::ffi::OsStr;
#[test]
fn prefers_xdg_config_bases() {
let actual = gix_path::env::xdg_config("test", &mut |n| {
(n == OsStr::new("XDG_CONFIG_HOME")).then(|| "marker".into())
})
.expect("set");
#[cfg(unix)]
assert_eq!(actual.to_str(), Some("marker/git/test"));
#[cfg(windows)]
assert_eq!(actual.to_str(), Some(r"marker\git\test"));
}
#[test]
fn falls_back_to_home() {
let actual = gix_path::env::xdg_config("test", &mut |n| (n == OsStr::new("HOME")).then(|| "marker".into()))
.expect("set");
#[cfg(unix)]
assert_eq!(actual.to_str(), Some("marker/.config/git/test"));
#[cfg(windows)]
assert_eq!(actual.to_str(), Some(r"marker\.config\git\test"));
}
}

View File

@@ -0,0 +1,19 @@
pub type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error>>;
mod convert;
mod realpath;
mod relative_path;
mod home_dir {
#[test]
fn returns_existing_directory() {
if let Some(home) = gix_path::env::home_dir() {
assert!(
home.is_dir(),
"the home directory would typically exist, even though on unix we don't test for that."
);
}
}
}
mod env;
mod util;

View File

@@ -0,0 +1,169 @@
use std::{
path::{Path, PathBuf},
time::Duration,
};
use bstr::ByteVec;
use gix_path::{realpath::Error, realpath_opts};
use gix_testtools::tempfile;
#[test]
fn fuzzed_timeout() -> crate::Result {
let path = PathBuf::from(std::fs::read("tests/fixtures/fuzzed/54k-path-components.path")?.into_string()?);
assert_eq!(path.components().count(), 54862);
let start = std::time::Instant::now();
assert!(matches!(
gix_path::realpath_opts(&path, Path::new("/cwd"), gix_path::realpath::MAX_SYMLINKS).unwrap_err(),
gix_path::realpath::Error::ExcessiveComponentCount {
max_symlink_checks: 2048
}
));
assert!(
start.elapsed() < Duration::from_millis(if cfg!(windows) { 1000 } else { 500 }),
"took too long: {:.02} , we can't take too much time for this, and should keep the amount of work reasonable\
as paths can be part of URls which sometimes are canonicalized",
start.elapsed().as_secs_f32()
);
Ok(())
}
#[test]
fn assorted() -> crate::Result {
let cwd = tempfile::tempdir()?;
let cwd = cwd.path();
let symlinks_disabled = 0;
assert!(
matches!(
realpath_opts("".as_ref(), cwd, symlinks_disabled),
Err(Error::EmptyPath)
),
"Empty path is not allowed"
);
assert_eq!(
realpath_opts("b/.git".as_ref(), cwd, symlinks_disabled)?,
cwd.join("b").join(".git"),
"relative paths are prefixed with current dir"
);
assert_eq!(
realpath_opts("b//.git".as_ref(), cwd, symlinks_disabled)?,
cwd.join("b").join(".git"),
"empty path components are ignored"
);
assert_eq!(
realpath_opts("./tmp/.git".as_ref(), cwd, symlinks_disabled)?,
cwd.join("tmp").join(".git"),
"path starting with dot is relative and is prefixed with current dir"
);
assert_eq!(
realpath_opts("./tmp/a/./.git".as_ref(), cwd, symlinks_disabled)?,
cwd.join("tmp").join("a").join(".git"),
"all ./ path components are ignored unless they the one at the beginning of the path"
);
assert_eq!(
realpath_opts("./b/../tmp/.git".as_ref(), cwd, symlinks_disabled)?,
cwd.join("tmp").join(".git"),
"dot dot goes to parent path component"
);
{
#[cfg(not(windows))]
let absolute_path = Path::new("/c/d/.git");
#[cfg(windows)]
let absolute_path = Path::new(r"C:\c\d\.git");
assert_eq!(
realpath_opts(absolute_path, cwd, symlinks_disabled)?,
absolute_path,
"absolute path without symlinks has nothing to resolve and remains unchanged"
);
}
Ok(())
}
#[test]
fn link_cycle_is_detected() -> crate::Result {
let tmp_dir = canonicalized_tempdir()?;
let dir = tmp_dir.path();
let link_name = "link";
let link_destination = dir.join(link_name);
let link_path = dir.join(link_name);
create_symlink(&link_path, link_destination)?;
let max_symlinks = 8;
assert!(
matches!(
realpath_opts(&link_path.join(".git"), "".as_ref(), max_symlinks),
Err(Error::MaxSymlinksExceeded { max_symlinks: 8 })
),
"link cycle is detected"
);
Ok(())
}
#[test]
fn symlink_with_absolute_path_gets_expanded() -> crate::Result {
let tmp_dir = canonicalized_tempdir()?;
let dir = tmp_dir.path();
let link_from = dir.join("a").join("b").join("tmp_p_q_link");
let link_to = dir.join("p").join("q");
create_symlink(&link_from, &link_to)?;
let max_symlinks = 8;
assert_eq!(
realpath_opts(&link_from.join(".git"), tmp_dir.path(), max_symlinks)?,
link_to.join(".git"),
"symlink with absolute path gets expanded"
);
Ok(())
}
#[test]
fn symlink_to_relative_path_gets_expanded_into_absolute_path() -> crate::Result {
let cwd = canonicalized_tempdir()?;
let dir = cwd.path();
let link_name = "pq_link";
create_symlink(dir.join("r").join(link_name), Path::new("p").join("q"))?;
assert_eq!(
realpath_opts(&Path::new(link_name).join(".git"), &dir.join("r"), 8)?,
dir.join("r").join("p").join("q").join(".git"),
"symlink to relative path gets expanded into absolute path"
);
Ok(())
}
#[test]
fn symlink_processing_is_disabled_if_the_value_is_zero() -> crate::Result {
let cwd = canonicalized_tempdir()?;
let link_name = "x_link";
create_symlink(cwd.path().join(link_name), Path::new("link destination does not exist"))?;
assert!(
matches!(
realpath_opts(&Path::new(link_name).join(".git"), cwd.path(), 0),
Err(Error::MaxSymlinksExceeded { max_symlinks: 0 })
),
"symlink processing is disabled if the value is zero"
);
Ok(())
}
fn create_symlink(from: impl AsRef<Path>, to: impl AsRef<Path>) -> std::io::Result<()> {
std::fs::create_dir_all(from.as_ref().parent().unwrap())?;
#[cfg(not(windows))]
{
std::os::unix::fs::symlink(to, from)
}
#[cfg(windows)]
std::os::windows::fs::symlink_file(to, from)
}
fn canonicalized_tempdir() -> crate::Result<tempfile::TempDir> {
let canonicalized_tempdir = gix_path::realpath(std::env::temp_dir())?;
Ok(tempfile::tempdir_in(canonicalized_tempdir)?)
}

View File

@@ -0,0 +1,159 @@
use bstr::{BStr, BString};
use gix_path::{relative_path::Error, RelativePath};
#[cfg(not(windows))]
#[test]
fn absolute_paths_return_err() {
let path_str: &str = "/refs/heads";
let path_bstr: &BStr = path_str.into();
let path_u8a: &[u8; 11] = b"/refs/heads";
let path_u8: &[u8] = &b"/refs/heads"[..];
let path_bstring: BString = "/refs/heads".into();
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_str),
Err(Error::IsAbsolute)
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_bstr),
Err(Error::IsAbsolute)
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_u8),
Err(Error::IsAbsolute)
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_u8a),
Err(Error::IsAbsolute)
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(&path_bstring),
Err(Error::IsAbsolute)
));
}
#[cfg(windows)]
#[test]
fn absolute_paths_with_backslashes_return_err() {
let path_str: &str = r"c:\refs\heads";
let path_bstr: &BStr = path_str.into();
let path_u8: &[u8] = &b"c:\\refs\\heads"[..];
let path_bstring: BString = r"c:\refs\heads".into();
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_str),
Err(Error::IsAbsolute)
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_bstr),
Err(Error::IsAbsolute)
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_u8),
Err(Error::IsAbsolute)
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(&path_bstring),
Err(Error::IsAbsolute)
));
}
#[test]
fn dots_in_paths_return_err() {
let path_str: &str = "./heads";
let path_bstr: &BStr = path_str.into();
let path_u8: &[u8] = &b"./heads"[..];
let path_bstring: BString = "./heads".into();
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_str),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_bstr),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_u8),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(&path_bstring),
Err(Error::ContainsInvalidComponent(_))
));
}
#[test]
fn dots_in_paths_with_backslashes_return_err() {
let path_str: &str = r".\heads";
let path_bstr: &BStr = path_str.into();
let path_u8: &[u8] = &b".\\heads"[..];
let path_bstring: BString = r".\heads".into();
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_str),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_bstr),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_u8),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(&path_bstring),
Err(Error::ContainsInvalidComponent(_))
));
}
#[test]
fn double_dots_in_paths_return_err() {
let path_str: &str = "../heads";
let path_bstr: &BStr = path_str.into();
let path_u8: &[u8] = &b"../heads"[..];
let path_bstring: BString = "../heads".into();
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_str),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_bstr),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_u8),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(&path_bstring),
Err(Error::ContainsInvalidComponent(_))
));
}
#[test]
fn double_dots_in_paths_with_backslashes_return_err() {
let path_str: &str = r"..\heads";
let path_bstr: &BStr = path_str.into();
let path_u8: &[u8] = &b"..\\heads"[..];
let path_bstring: BString = r"..\heads".into();
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_str),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_bstr),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(path_u8),
Err(Error::ContainsInvalidComponent(_))
));
assert!(matches!(
TryInto::<&RelativePath>::try_into(&path_bstring),
Err(Error::ContainsInvalidComponent(_))
));
}

View File

@@ -0,0 +1,42 @@
mod is_absolute {
#[test]
fn absolute_linux_path_is_true() {
assert!(gix_path::is_absolute("/"));
assert!(gix_path::is_absolute("/abs/path"));
}
#[test]
fn relative_linux_path_is_false() {
assert!(!gix_path::is_absolute("./relative/path"));
assert!(!gix_path::is_absolute("relative/path"));
}
#[cfg(not(windows))]
mod not_on_windows {
#[test]
fn drive_prefixes_are_false() {
assert!(!gix_path::is_absolute(r"c:\abs/path"));
assert!(!gix_path::is_absolute(r"c:\abs\path"));
}
}
#[cfg(windows)]
mod on_windows {
#[test]
fn drive_prefixes_are_true() {
assert!(gix_path::is_absolute(r"c:\abs/path"));
assert!(gix_path::is_absolute(r"c:\abs\path"));
}
#[test]
fn relative_paths_with_backslashes_are_false() {
assert!(!gix_path::is_absolute(r".\rel/path"));
assert!(!gix_path::is_absolute(r"rel\path"));
}
#[test]
fn path_starting_with_backslash_is_false() {
assert!(!gix_path::is_absolute(r"\rel\path"));
}
}
}