Skip to content

Commit ae6944e

Browse files
committed
[tree-diff] The first proper test with an API I like
1 parent 633cba7 commit ae6944e

File tree

3 files changed

+132
-76
lines changed

3 files changed

+132
-76
lines changed

git-diff/src/lib.rs

+61-12
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ pub mod visit {
7474
}
7575

7676
#[derive(Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)]
77-
pub enum PathComponentMode {
77+
pub enum PathComponentUpdateMode {
7878
Replace,
7979
Push,
8080
}
8181

8282
#[derive(Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)]
8383
pub struct PathComponent<'a> {
84-
pub component: &'a BStr,
84+
pub name: &'a BStr,
8585
/// An ID referring uniquely to the path built thus far. Used to keep track of source paths
8686
/// in case of [renames][Change::Rename] and [copies][Change::Copy].
8787
pub id: usize,
@@ -94,9 +94,9 @@ pub mod visit {
9494
}
9595

9696
pub trait Record {
97-
fn update_path_component(&mut self, component: PathComponent<'_>, mode: PathComponentMode);
97+
fn update_path_component(&mut self, component: PathComponent<'_>, mode: PathComponentUpdateMode);
9898
fn pop_path_component(&mut self);
99-
fn record(change: Change) -> Action;
99+
fn record(&mut self, change: Change) -> Action;
100100
}
101101

102102
#[cfg(test)]
@@ -117,25 +117,74 @@ pub mod visit {
117117

118118
pub mod recorder {
119119
use crate::visit::record;
120+
use git_hash::ObjectId;
121+
use git_object::{
122+
bstr::{BStr, BString, ByteSlice, ByteVec},
123+
tree,
124+
};
125+
use std::{ops::Deref, path::PathBuf};
126+
127+
#[derive(Clone, Debug, PartialEq, Eq)]
128+
pub enum Change {
129+
Addition {
130+
mode: tree::Mode,
131+
oid: ObjectId,
132+
path: PathBuf,
133+
},
134+
}
120135

121-
#[derive(Clone, Default)]
122-
pub struct Recorder;
136+
pub type Changes = Vec<Change>;
137+
138+
#[derive(Clone, Debug, Default)]
139+
pub struct Recorder {
140+
current_component: BString,
141+
pub records: Vec<Change>,
142+
}
143+
144+
impl Recorder {
145+
fn pop_element(&mut self) {
146+
if let Some(pos) = self.current_component.rfind_byte(b'/') {
147+
self.current_component.resize(pos, 0);
148+
}
149+
}
150+
151+
fn push_element(&mut self, name: &BStr) {
152+
self.current_component.push(b'/');
153+
self.current_component.push_str(name);
154+
}
155+
}
123156

124157
impl record::Record for Recorder {
125158
fn update_path_component(
126159
&mut self,
127-
_component: record::PathComponent<'_>,
128-
_mode: record::PathComponentMode,
160+
component: record::PathComponent<'_>,
161+
mode: record::PathComponentUpdateMode,
129162
) {
130-
todo!()
163+
use record::PathComponentUpdateMode::*;
164+
match mode {
165+
Push => self.push_element(component.name),
166+
Replace => {
167+
self.pop_element();
168+
self.push_element(component.name);
169+
}
170+
}
131171
}
132172

133173
fn pop_path_component(&mut self) {
134-
todo!()
174+
self.pop_element();
135175
}
136176

137-
fn record(_change: record::Change) -> record::Action {
138-
todo!()
177+
fn record(&mut self, change: record::Change) -> record::Action {
178+
use record::Change::*;
179+
self.records.push(match change {
180+
Addition { mode, oid } => Change::Addition {
181+
mode,
182+
oid,
183+
path: self.current_component.deref().clone().into_path_buf_lossy(),
184+
},
185+
_ => todo!("record other kinds of changes"),
186+
});
187+
record::Action::Continue
139188
}
140189
}
141190
}

git-diff/tests/diff.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
pub type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error>>;
22

3-
mod tree;
3+
pub fn hex_to_id(hex: &str) -> git_hash::ObjectId {
4+
git_hash::ObjectId::from_hex(hex.as_bytes()).expect("40 bytes hex")
5+
}
6+
7+
mod visit;

git-diff/tests/visit/mod.rs

+66-63
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,73 @@
1-
mod with_tree {
2-
use crate::hex_to_id;
3-
use git_diff::visit::recorder;
4-
use git_odb::{pack, Locate};
1+
mod changes {
2+
mod to_obtain_tree {
3+
use crate::hex_to_id;
4+
use git_diff::visit::recorder;
5+
use git_odb::{pack, Locate};
56

6-
const FIRST_COMMIT: &str = "055df97e18cd537da3cb16bcbdf1733fdcdfb430";
7+
const FIRST_COMMIT: &str = "055df97e18cd537da3cb16bcbdf1733fdcdfb430";
78

8-
fn diff_at(commit_id: &str) -> crate::Result<recorder::Changes> {
9-
let db = git_odb::linked::Db::at(
10-
test_tools::scripted_fixture_repo_read_only("make_diff_repo.sh")?
11-
.join(".git")
12-
.join("objects"),
13-
)?;
14-
let commit_id = git_hash::ObjectId::from_hex(commit_id.as_bytes())?;
15-
let mut buf = Vec::new();
16-
let (main_tree_id, parent_commit_id) = {
17-
let commit = db
18-
.locate(commit_id, &mut buf, &mut pack::cache::Never)?
19-
.expect("start commit to be present")
9+
fn diff_at(commit_id: &str) -> crate::Result<recorder::Changes> {
10+
let db = git_odb::linked::Db::at(
11+
test_tools::scripted_fixture_repo_read_only("make_diff_repo.sh")?
12+
.join(".git")
13+
.join("objects"),
14+
)?;
15+
let commit_id = git_hash::ObjectId::from_hex(commit_id.as_bytes())?;
16+
let mut buf = Vec::new();
17+
let (main_tree_id, parent_commit_id) = {
18+
let commit = db
19+
.locate(commit_id, &mut buf, &mut pack::cache::Never)?
20+
.expect("start commit to be present")
21+
.decode()?
22+
.into_commit()
23+
.expect("id is actually a commit");
24+
25+
(commit.tree(), {
26+
let p = commit.parents().next();
27+
p
28+
})
29+
};
30+
let main_tree = db
31+
.locate(main_tree_id, &mut buf, &mut pack::cache::Never)?
32+
.expect("main tree present")
2033
.decode()?
21-
.into_commit()
22-
.expect("id is actually a commit");
34+
.into_tree()
35+
.expect("id to be a tree");
36+
let mut buf2 = Vec::new();
37+
let previous_tree: Option<_> = {
38+
parent_commit_id
39+
.and_then(|id| db.locate(id, &mut buf2, &mut pack::cache::Never).ok().flatten())
40+
.and_then(|c| c.decode().ok())
41+
.and_then(|c| c.into_commit())
42+
.map(|c| c.tree())
43+
.and_then(|tree| db.locate(tree, &mut buf2, &mut pack::cache::Never).ok().flatten())
44+
.and_then(|tree| tree.decode().ok())
45+
.and_then(|tree| tree.into_tree())
46+
};
2347

24-
(commit.tree(), {
25-
let p = commit.parents().next();
26-
p
27-
})
28-
};
29-
let main_tree = db
30-
.locate(main_tree_id, &mut buf, &mut pack::cache::Never)?
31-
.expect("main tree present")
32-
.decode()?
33-
.into_tree()
34-
.expect("id to be a tree");
35-
let mut buf2 = Vec::new();
36-
let previous_tree: Option<_> = {
37-
parent_commit_id
38-
.and_then(|id| db.locate(id, &mut buf2, &mut pack::cache::Never).ok().flatten())
39-
.and_then(|c| c.decode().ok())
40-
.and_then(|c| c.into_commit())
41-
.map(|c| c.tree())
42-
.and_then(|tree| db.locate(tree, &mut buf2, &mut pack::cache::Never).ok().flatten())
43-
.and_then(|tree| tree.decode().ok())
44-
.and_then(|tree| tree.into_tree())
45-
};
48+
let mut recorder = git_diff::visit::Recorder::default();
49+
git_diff::visit::Changes::from(previous_tree.as_ref()).to_obtain_tree(
50+
&main_tree,
51+
&mut git_diff::visit::State::default(),
52+
|_oid, _buf| todo!("Actual lookup in db"),
53+
&mut recorder,
54+
)?;
55+
Ok(recorder.records)
56+
}
4657

47-
let mut recorder = git_diff::visit::Recorder::default();
48-
git_diff::visit::Changes::from(previous_tree.as_ref()).to_obtain_tree(
49-
&main_tree,
50-
&mut git_diff::visit::State::default(),
51-
|_oid, _buf| todo!("Actual lookup in db"),
52-
&mut recorder,
53-
)?;
54-
Ok(recorder.records)
55-
}
56-
#[test]
57-
#[should_panic]
58-
fn file_added() {
59-
// :000000 100644 0000000000000000000000000000000000000000 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 A f
60-
assert_eq!(
61-
diff_at(FIRST_COMMIT).unwrap(),
62-
vec![recorder::Change::Addition {
63-
mode: git_object::tree::Mode::Tree,
64-
oid: hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"),
65-
path: "f".into()
66-
}]
67-
);
68-
todo!("detect an added file in the root tree")
58+
#[test]
59+
#[should_panic]
60+
fn file_added() {
61+
// :000000 100644 0000000000000000000000000000000000000000 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 A f
62+
assert_eq!(
63+
diff_at(FIRST_COMMIT).unwrap(),
64+
vec![recorder::Change::Addition {
65+
mode: git_object::tree::Mode::Tree,
66+
oid: hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"),
67+
path: "f".into()
68+
}]
69+
);
70+
todo!("detect an added file in the root tree")
71+
}
6972
}
7073
}

0 commit comments

Comments
 (0)