mod reflog { mod packed { use git_ref::file::ReferenceExt; use crate::file; #[test] fn iter() -> crate::Result { let store = file::store_with_packed_refs()?; let r = store.find("main")?; assert_eq!(r.log_iter(&store).all()?.expect("log exists").count(), 1); assert!(r.log_exists(&store), "it exists if its readable"); Ok(()) } #[test] fn iter_rev() -> crate::Result { let store = file::store_with_packed_refs()?; let r = store.find("main")?; assert_eq!(r.log_iter(&store).rev()?.expect("log exists").count(), 1); Ok(()) } } mod loose { use crate::file; #[test] fn iter() -> crate::Result { let store = file::store()?; let r = store.find_loose("HEAD")?; let mut buf = Vec::new(); assert_eq!(r.log_iter(&store, &mut buf)?.expect("log exists").count(), 1); assert!(r.log_exists(&store), "it exists if its readable"); Ok(()) } #[test] fn iter_rev() -> crate::Result { let store = file::store()?; let r = store.find_loose("HEAD")?; let mut buf = [0u8; 256]; assert_eq!(r.log_iter_rev(&store, &mut buf)?.expect("log exists").count(), 1); Ok(()) } }} mod peel { use git_odb::pack::Find; use git_ref::{file::ReferenceExt, peel, Reference}; use git_testtools::hex_to_id; use crate::{file, file::store_with_packed_refs}; #[test] fn one_level() -> crate::Result { let store = file::store()?; let r = store.find_loose("HEAD")?; assert_eq!(r.kind(), git_ref::Kind::Symbolic, "there is something to peel"); let nr = Reference::from(r).follow(&store).expect("exists").expect("no failure"); assert!( matches!(nr.target.to_ref(), git_ref::TargetRef::Peeled(_)), "iteration peels a single level" ); assert!(nr.follow(&store).is_none(), "end of iteration"); assert_eq!( nr.target.to_ref(), git_ref::TargetRef::Peeled(&hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03")), "we still have the peeled target" ); Ok(()) } #[test] fn peel_with_packed_involvement() -> crate::Result { let store = store_with_packed_refs()?; let mut head: Reference = store.find_loose("HEAD")?.into(); let expected = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03"); assert_eq!(head.peel_to_id_in_place(&store, peel::none)?, expected); assert_eq!(head.target.as_id().map(ToOwned::to_owned), Some(expected)); let mut head = store.find("dt1")?; assert_eq!(head.peel_to_id_in_place(&store, peel::none)?, expected); assert_eq!(head.target.into_id(), expected); Ok(()) } #[test] fn peel_one_level_with_pack() -> crate::Result { let store = store_with_packed_refs()?; let head = store.find("dt1")?; assert_eq!( head.target.as_id().map(ToOwned::to_owned), Some(hex_to_id("4c3f4cce493d7beb45012e478021b5f65295e5a3")) ); assert_eq!( head.kind(), git_ref::Kind::Peeled, "its peeled, but does have another step to peel to" ); let peeled = head.follow(&store).expect("a peeled ref for the object")?; assert_eq!( peeled.target.as_id().map(ToOwned::to_owned), Some(hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03")), "packed refs are always peeled (at least the ones we choose to read)" ); assert_eq!(peeled.kind(), git_ref::Kind::Peeled, "it's terminally peeled now"); assert!(peeled.follow(&store).is_none()); Ok(()) } #[test] fn to_id_multi_hop() -> crate::Result { let store = file::store()?; let mut r: Reference = store.find_loose("multi-link")?.into(); assert_eq!(r.kind(), git_ref::Kind::Symbolic, "there is something to peel"); let commit = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03"); assert_eq!(r.peel_to_id_in_place(&store, peel::none)?, commit); assert_eq!(r.name.as_bstr(), "refs/remotes/origin/multi-link-target3"); let mut r: Reference = store.find_loose("dt1")?.into(); assert_eq!( r.peel_to_id_in_place(&store, peel::none)?, hex_to_id("4c3f4cce493d7beb45012e478021b5f65295e5a3"), "points to a tag object without actual object lookup" ); let odb = git_odb::at(store.base().join("objects"))?; let mut r: Reference = store.find_loose("dt1")?.into(); assert_eq!( r.peel_to_id_in_place(&store, |oid, buf| { odb.try_find(oid, buf) .map(|obj| obj.map(|(obj, _)| (obj.kind, obj.data))) })?, commit, "points to the commit with lookup" ); Ok(()) } #[test] fn to_id_cycle() -> crate::Result { let store = file::store()?; let mut r: Reference = store.find_loose("loop-a")?.into(); assert_eq!(r.kind(), git_ref::Kind::Symbolic, "there is something to peel"); assert_eq!(r.name.as_bstr(), "refs/loop-a"); assert!(matches!( r.peel_to_id_in_place(&store, peel::none).unwrap_err(), git_ref::peel::to_id::Error::Cycle { .. } )); assert_eq!(r.name.as_bstr(), "refs/loop-a", "the ref is not changed on error"); Ok(()) }} mod parse { mod invalid { use git_ref::file::loose::Reference; macro_rules! mktest { ($name:ident, $input:literal, $err:literal) => { #[test] fn $name() { use std::convert::TryInto; let err = Reference::try_from_path("HEAD".try_into().expect("this is a valid name"), $input).unwrap_err(); assert_eq!(err.to_string(), $err); } }; } mktest!(hex_id, b"foobar", "\"foobar\" could not be parsed"); mktest!(ref_tag, b"reff: hello", "\"reff: hello\" could not be parsed"); } mod valid { use git_object::bstr::ByteSlice; use git_ref::file::loose::Reference; use git_testtools::hex_to_id; macro_rules! mktest { ($name:ident, $input:literal, $kind:path, $id:expr, $ref:expr) => { #[test] fn $name() { use std::convert::TryInto; let reference = Reference::try_from_path("HEAD".try_into().expect("valid static name"), $input).unwrap(); assert_eq!(reference.kind(), $kind); assert_eq!(reference.target.to_ref().as_id(), $id); assert_eq!(reference.target.to_ref().as_name(), $ref); } }; } mktest!( peeled, b"c5241b835b93af497cda80ce0dceb8f49800df1c\n", git_ref::Kind::Peeled, Some(hex_to_id("c5241b835b93af497cda80ce0dceb8f49800df1c").as_ref()), None ); mktest!( symbolic, b"ref: refs/heads/main\n", git_ref::Kind::Symbolic, None, Some(b"refs/heads/main".as_bstr()) ); mktest!( symbolic_more_than_one_space, b"ref: refs/foobar\n", git_ref::Kind::Symbolic, None, Some(b"refs/foobar".as_bstr()) ); }}
mod reflog {
mod packed {
use git_ref::file::ReferenceExt;
use crate::file;
#[test]
fn iter() -> crate::Result {
let store = file::store_with_packed_refs()?;
let r = store.find("main")?;
assert_eq!(r.log_iter(&store).all()?.expect("log exists").count(), 1);
assert!(r.log_exists(&store), "it exists if its readable");
Ok(())
}
#[test]
fn iter_rev() -> crate::Result {
let store = file::store_with_packed_refs()?;
let r = store.find("main")?;
assert_eq!(r.log_iter(&store).rev()?.expect("log exists").count(), 1);
Ok(())
}
}
mod loose {
use crate::file;
#[test]
fn iter() -> crate::Result {
let store = file::store()?;
let r = store.find_loose("HEAD")?;
let mut buf = Vec::new();
assert_eq!(r.log_iter(&store, &mut buf)?.expect("log exists").count(), 1);
assert!(r.log_exists(&store), "it exists if its readable");
Ok(())
}
#[test]
fn iter_rev() -> crate::Result {
let store = file::store()?;
let r = store.find_loose("HEAD")?;
let mut buf = [0u8; 256];
assert_eq!(r.log_iter_rev(&store, &mut buf)?.expect("log exists").count(), 1);
Ok(())
}
}
}
mod peel {
use git_odb::pack::Find;
use git_ref::{file::ReferenceExt, peel, Reference};
use git_testtools::hex_to_id;
use crate::{file, file::store_with_packed_refs};
#[test]
fn one_level() -> crate::Result {
let store = file::store()?;
let r = store.find_loose("HEAD")?;
assert_eq!(r.kind(), git_ref::Kind::Symbolic, "there is something to peel");
let nr = Reference::from(r).follow(&store).expect("exists").expect("no failure");
assert!(
matches!(nr.target.to_ref(), git_ref::TargetRef::Peeled(_)),
"iteration peels a single level"
);
assert!(nr.follow(&store).is_none(), "end of iteration");
assert_eq!(
nr.target.to_ref(),
git_ref::TargetRef::Peeled(&hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03")),
"we still have the peeled target"
);
Ok(())
}
#[test]
fn peel_with_packed_involvement() -> crate::Result {
let store = store_with_packed_refs()?;
let mut head: Reference = store.find_loose("HEAD")?.into();
let expected = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03");
assert_eq!(head.peel_to_id_in_place(&store, peel::none)?, expected);
assert_eq!(head.target.as_id().map(ToOwned::to_owned), Some(expected));
let mut head = store.find("dt1")?;
assert_eq!(head.peel_to_id_in_place(&store, peel::none)?, expected);
assert_eq!(head.target.into_id(), expected);
Ok(())
}
#[test]
fn peel_one_level_with_pack() -> crate::Result {
let store = store_with_packed_refs()?;
let head = store.find("dt1")?;
assert_eq!(
head.target.as_id().map(ToOwned::to_owned),
Some(hex_to_id("4c3f4cce493d7beb45012e478021b5f65295e5a3"))
);
assert_eq!(
head.kind(),
git_ref::Kind::Peeled,
"its peeled, but does have another step to peel to"
);
let peeled = head.follow(&store).expect("a peeled ref for the object")?;
assert_eq!(
peeled.target.as_id().map(ToOwned::to_owned),
Some(hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03")),
"packed refs are always peeled (at least the ones we choose to read)"
);
assert_eq!(peeled.kind(), git_ref::Kind::Peeled, "it's terminally peeled now");
assert!(peeled.follow(&store).is_none());
Ok(())
}
#[test]
fn to_id_multi_hop() -> crate::Result {
let store = file::store()?;
let mut r: Reference = store.find_loose("multi-link")?.into();
assert_eq!(r.kind(), git_ref::Kind::Symbolic, "there is something to peel");
let commit = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03");
assert_eq!(r.peel_to_id_in_place(&store, peel::none)?, commit);
assert_eq!(r.name.as_bstr(), "refs/remotes/origin/multi-link-target3");
let mut r: Reference = store.find_loose("dt1")?.into();
assert_eq!(
r.peel_to_id_in_place(&store, peel::none)?,
hex_to_id("4c3f4cce493d7beb45012e478021b5f65295e5a3"),
"points to a tag object without actual object lookup"
);
let odb = git_odb::at(store.base().join("objects"))?;
let mut r: Reference = store.find_loose("dt1")?.into();
assert_eq!(
r.peel_to_id_in_place(&store, |oid, buf| {
odb.try_find(oid, buf)
.map(|obj| obj.map(|(obj, _)| (obj.kind, obj.data)))
})?,
commit,
"points to the commit with lookup"
);
Ok(())
}
#[test]
fn to_id_cycle() -> crate::Result {
let store = file::store()?;
let mut r: Reference = store.find_loose("loop-a")?.into();
assert_eq!(r.kind(), git_ref::Kind::Symbolic, "there is something to peel");
assert_eq!(r.name.as_bstr(), "refs/loop-a");
assert!(matches!(
r.peel_to_id_in_place(&store, peel::none).unwrap_err(),
git_ref::peel::to_id::Error::Cycle { .. }
));
assert_eq!(r.name.as_bstr(), "refs/loop-a", "the ref is not changed on error");
Ok(())
}
}
mod parse {
mod invalid {
use git_ref::file::loose::Reference;
macro_rules! mktest {
($name:ident, $input:literal, $err:literal) => {
#[test]
fn $name() {
use std::convert::TryInto;
let err =
Reference::try_from_path("HEAD".try_into().expect("this is a valid name"), $input).unwrap_err();
assert_eq!(err.to_string(), $err);
}
};
}
mktest!(hex_id, b"foobar", "\"foobar\" could not be parsed");
mktest!(ref_tag, b"reff: hello", "\"reff: hello\" could not be parsed");
}
mod valid {
use git_object::bstr::ByteSlice;
use git_ref::file::loose::Reference;
use git_testtools::hex_to_id;
macro_rules! mktest {
($name:ident, $input:literal, $kind:path, $id:expr, $ref:expr) => {
#[test]
fn $name() {
use std::convert::TryInto;
let reference =
Reference::try_from_path("HEAD".try_into().expect("valid static name"), $input).unwrap();
assert_eq!(reference.kind(), $kind);
assert_eq!(reference.target.to_ref().as_id(), $id);
assert_eq!(reference.target.to_ref().as_name(), $ref);
}
};
}
mktest!(
peeled,
b"c5241b835b93af497cda80ce0dceb8f49800df1c\n",
git_ref::Kind::Peeled,
Some(hex_to_id("c5241b835b93af497cda80ce0dceb8f49800df1c").as_ref()),
None
);
mktest!(
symbolic,
b"ref: refs/heads/main\n",
git_ref::Kind::Symbolic,
None,
Some(b"refs/heads/main".as_bstr())
);
mktest!(
symbolic_more_than_one_space,
b"ref: refs/foobar\n",
git_ref::Kind::Symbolic,
None,
Some(b"refs/foobar".as_bstr())
);
}
}