| @@ -1,10 +1,12 @@ |
| 1 | mod lookup_ref_delta_objects { | 1 | mod lookup_ref_delta_objects { |
| | 2 | use crate::pack::hex_to_id; |
| 2 | use git_hash::ObjectId; | 3 | use git_hash::ObjectId; |
| 3 | use git_pack::data::{self, entry::Header, input, LookupRefDeltaObjectsIter}; | 4 | use git_pack::data::{self, entry::Header, input, LookupRefDeltaObjectsIter}; |
| 4 | | 5 | |
| 5 | const D_A: &[u8] = b"a"; | 6 | const D_A: &[u8] = b"a"; |
| 6 | const D_B: &[u8] = b"bb"; | 7 | const D_B: &[u8] = b"bb"; |
| 7 | const D_C: &[u8] = b"ccc"; | 8 | const D_C: &[u8] = b"ccc"; |
| | 9 | const D_D: &[u8] = b"dddd"; |
| 8 | | 10 | |
| 9 | fn base() -> Header { | 11 | fn base() -> Header { |
| 10 | Header::Blob | 12 | Header::Blob |
| @@ -63,21 +65,25 @@ mod lookup_ref_delta_objects { · 52 unmodified lines |
| 63 | | 65 | |
| 64 | #[test] | 66 | #[test] |
| 65 | fn ref_deltas_have_their_base_injected_if_not_done_before_and_all_future_entries_are_offset() { | 67 | fn ref_deltas_have_their_base_injected_if_not_done_before_and_all_future_entries_are_offset() { |
| 66 | let first = entry(base(), D_C); | 68 | let first_id = hex_to_id("0000000000000000000000000000000000000001"); |
| 67 | let mut inserted = entry(base(), D_B); | 69 | let second_id = hex_to_id("0000000000000000000000000000000000000002"); |
| | 70 | let first = entry(delta_ref(first_id), D_A); |
| | 71 | |
| | 72 | let inserted_data = D_D; |
| | 73 | let mut inserted = entry(base(), inserted_data); |
| 68 | let mut last_entry = entry(base(), D_C); | 74 | let mut last_entry = entry(base(), D_C); |
| 69 | // todo: let's have an ofs delta point at the altered entry, maybe even last_entry | 75 | // todo: let's have an ofs delta point at the altered entry, maybe even last_entry |
| 70 | let input = compute_offsets(vec![ | 76 | let input = compute_offsets(vec![ |
| 71 | first.clone(), | 77 | first.clone(), |
| 72 | entry(delta_ref(ObjectId::null_sha1()), D_A), | 78 | entry(delta_ref(second_id), D_B), |
| 73 | last_entry.clone(), | 79 | last_entry.clone(), |
| 74 | ]); | 80 | ]); |
| 75 | | 81 | |
| 76 | let mut calls = 0; | 82 | let mut calls = 0; |
| 77 | let actual = LookupRefDeltaObjectsIter::new(into_results_iter(input), |_oid, buf| { | 83 | let actual = LookupRefDeltaObjectsIter::new(into_results_iter(input), |_oid, buf| { |
| 78 | calls += 1; | 84 | calls += 1; |
| 79 | buf.resize(D_B.len(), 0); | 85 | buf.resize(inserted_data.len(), 0); |
| 80 | buf.copy_from_slice(&D_B); | 86 | buf.copy_from_slice(inserted_data); |
| 81 | Some(data::Object { | 87 | Some(data::Object { |
| 82 | kind: git_object::Kind::Blob, | 88 | kind: git_object::Kind::Blob, |
| 83 | data: buf.as_slice(), | 89 | data: buf.as_slice(), |
| @@ -87,28 +93,43 @@ mod lookup_ref_delta_objects { · 3 unmodified lines |
| 87 | .collect::<Result<Vec<_>, _>>() | 93 | .collect::<Result<Vec<_>, _>>() |
| 88 | .unwrap(); | 94 | .unwrap(); |
| 89 | | 95 | |
| 90 | assert_eq!(calls, 1, "there is only one object to replace"); | 96 | assert_eq!(calls, 2, "there is only two objects to replace"); |
| 91 | assert_eq!(actual.len(), 4, "one object was inserted"); | 97 | assert_eq!(actual.len(), 5, "two object was inserted"); |
| 92 | assert_eq!(&actual[0], &first, "first object is unchanged"); | 98 | |
| | 99 | assert_eq!(&actual[0], &inserted, "first object is inserted one"); |
| | 100 | |
| | 101 | let altered = &actual[1]; |
| | 102 | assert_eq!( |
| | 103 | extract_delta_offset(&altered.header), |
| | 104 | inserted.bytes_in_pack(), |
| | 105 | "former first entry is now an offset delta pointing at the item before" |
| | 106 | ); |
| | 107 | assert_eq!( |
| | 108 | altered.pack_offset, |
| | 109 | inserted.bytes_in_pack(), |
| | 110 | "the pack offset was adjusted to accommodate for the inserted object" |
| | 111 | ); |
| 93 | | 112 | |
| 94 | inserted.pack_offset += first.bytes_in_pack(); | 113 | inserted.pack_offset = inserted.bytes_in_pack() + altered.bytes_in_pack(); |
| 95 | assert_eq!(&actual[1], &inserted, "second object is the inserted one"); | 114 | assert_eq!(&actual[2], &inserted, "third object is a newly inserted one, too"); |
| 96 | | 115 | |
| 97 | let altered = &actual[2]; | 116 | let first_altered_len = altered.bytes_in_pack(); |
| | 117 | let altered = &actual[3]; |
| 98 | assert_eq!( | 118 | assert_eq!( |
| 99 | extract_delta_offset(&altered.header), | 119 | extract_delta_offset(&altered.header), |
| 100 | inserted.bytes_in_pack(), | 120 | inserted.bytes_in_pack(), |
| 101 | "former second entry is now an offset delta pointing at the item before" | 121 | "former second entry is now an offset delta pointing at the inserted item before" |
| 102 | ); | 122 | ); |
| 103 | assert_eq!( | 123 | assert_eq!( |
| 104 | altered.pack_offset, | 124 | altered.pack_offset, |
| 105 | first.bytes_in_pack() + inserted.bytes_in_pack(), | 125 | inserted.bytes_in_pack() + first_altered_len + inserted.bytes_in_pack(), |
| 106 | "the pack offset was adjusted to accommodate for the first and inserted object" | 126 | "the pack offset was adjusted to accommodate for preceding objects" |
| 107 | ); | 127 | ); |
| 108 | | 128 | |
| 109 | last_entry.pack_offset = first.bytes_in_pack() + inserted.bytes_in_pack() + altered.bytes_in_pack(); | 129 | last_entry.pack_offset = |
| | 130 | inserted.bytes_in_pack() + first_altered_len + inserted.bytes_in_pack() + altered.bytes_in_pack(); |
| 110 | assert_eq!( | 131 | assert_eq!( |
| 111 | &actual[3], &last_entry, | 132 | &actual[4], &last_entry, |
| 112 | "the last entry was offset and is otherwise unchanged" | 133 | "the last entry was offset and is otherwise unchanged" |
| 113 | ); | 134 | ); |
| 114 | } | 135 | } |