Skip to content

Commit e25ccbf

Browse files
committed
validate what happens if a rename is emulated, particularly in relation to directory creation.
1 parent f4e630f commit e25ccbf

File tree

1 file changed

+100
-8
lines changed
  • gix-ref/tests/refs/file/transaction/prepare_and_commit

1 file changed

+100
-8
lines changed

gix-ref/tests/refs/file/transaction/prepare_and_commit/delete.rs

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
use gix_date::parse::TimeBuf;
2-
use gix_lock::acquire::Fail;
3-
use gix_ref::{
4-
file::ReferenceExt,
5-
transaction::{Change, PreviousValue, RefEdit, RefLog},
6-
Reference, Target,
7-
};
8-
91
use crate::{
102
file::{
113
store_writable,
124
transaction::prepare_and_commit::{committer, empty_store},
135
},
146
hex_to_id,
157
};
8+
use gix_date::parse::TimeBuf;
9+
use gix_lock::acquire::Fail;
10+
use gix_ref::file::transaction::prepare::Error;
11+
use gix_ref::transaction::LogChange;
12+
use gix_ref::{
13+
file::ReferenceExt,
14+
transaction::{Change, PreviousValue, RefEdit, RefLog},
15+
FullName, Reference, Target,
16+
};
1617

1718
#[test]
1819
fn delete_a_ref_which_is_gone_succeeds() -> crate::Result {
@@ -208,6 +209,97 @@ fn delete_reflog_only_of_symbolic_with_deref() -> crate::Result {
208209
Ok(())
209210
}
210211

212+
#[test]
213+
fn rename_a_to_a_slash_b_in_one_transaction() -> crate::Result {
214+
let (_keep, store) = store_writable("make_repo_for_reflog.sh")?;
215+
let old = store.find_loose("old")?;
216+
217+
let new_name: FullName = "refs/heads/old/new".try_into()?;
218+
let err = store
219+
.transaction()
220+
.prepare(
221+
[
222+
RefEdit {
223+
change: Change::Delete {
224+
expected: PreviousValue::MustExist,
225+
log: RefLog::AndReference,
226+
},
227+
name: old.name.clone(),
228+
deref: true,
229+
},
230+
RefEdit {
231+
change: Change::Update {
232+
expected: PreviousValue::MustNotExist,
233+
log: LogChange::default(),
234+
new: old.target.clone(),
235+
},
236+
name: new_name.clone(),
237+
deref: true,
238+
},
239+
],
240+
Fail::Immediately,
241+
Fail::Immediately,
242+
)
243+
.unwrap_err();
244+
245+
match err {
246+
#[cfg(unix)]
247+
Error::Io(err) => {
248+
assert_eq!(
249+
err.kind(),
250+
std::io::ErrorKind::NotADirectory,
251+
"For now this isn't supported in the same transaction."
252+
);
253+
}
254+
#[cfg(windows)]
255+
Error::LockAcquire { .. } => {
256+
// It's bad that the error differs on Windows, but then again, doing this kind of pseudo-db on a filesystem
257+
// probably is never going to be great, so let's wait for ref-tables.
258+
}
259+
err => unreachable!("unexpected error variant: {err:?}"),
260+
}
261+
262+
let edits = store
263+
.transaction()
264+
.prepare(
265+
[RefEdit {
266+
change: Change::Delete {
267+
expected: PreviousValue::MustExist,
268+
log: RefLog::AndReference,
269+
},
270+
name: old.name,
271+
deref: true,
272+
}],
273+
Fail::Immediately,
274+
Fail::Immediately,
275+
)?
276+
.commit(committer().to_ref(&mut TimeBuf::default()))?;
277+
assert_eq!(edits.len(), 1, "First delete to make space");
278+
279+
let edits = store
280+
.transaction()
281+
.prepare(
282+
[RefEdit {
283+
change: Change::Update {
284+
expected: PreviousValue::MustNotExist,
285+
log: LogChange::default(),
286+
new: old.target,
287+
},
288+
name: new_name.clone(),
289+
deref: true,
290+
}],
291+
Fail::Immediately,
292+
Fail::Immediately,
293+
)?
294+
.commit(committer().to_ref(&mut TimeBuf::default()))?;
295+
assert_eq!(edits.len(), 1, "Then create the new ref in place of the old");
296+
assert!(
297+
store.try_find_loose(new_name.as_ref())?.is_some(),
298+
"must have created the new reference"
299+
);
300+
Ok(())
301+
}
302+
211303
#[test]
212304
/// Based on https://github.com/git/git/blob/master/refs/files-backend.c#L514:L515
213305
fn delete_broken_ref_that_must_exist_fails_as_it_is_no_valid_ref() -> crate::Result {

0 commit comments

Comments
 (0)