|
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 |
| - |
9 | 1 | use crate::{
|
10 | 2 | file::{
|
11 | 3 | store_writable,
|
12 | 4 | transaction::prepare_and_commit::{committer, empty_store},
|
13 | 5 | },
|
14 | 6 | hex_to_id,
|
15 | 7 | };
|
| 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 | +}; |
16 | 17 |
|
17 | 18 | #[test]
|
18 | 19 | fn delete_a_ref_which_is_gone_succeeds() -> crate::Result {
|
@@ -208,6 +209,97 @@ fn delete_reflog_only_of_symbolic_with_deref() -> crate::Result {
|
208 | 209 | Ok(())
|
209 | 210 | }
|
210 | 211 |
|
| 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 | + |
211 | 303 | #[test]
|
212 | 304 | /// Based on https://github.com/git/git/blob/master/refs/files-backend.c#L514:L515
|
213 | 305 | fn delete_broken_ref_that_must_exist_fails_as_it_is_no_valid_ref() -> crate::Result {
|
|
0 commit comments