Skip to content

Commit 91b85f6

Browse files
committed
Testing :D
1 parent a6a757e commit 91b85f6

File tree

5 files changed

+521
-3
lines changed

5 files changed

+521
-3
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/but-cherry-apply/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,10 @@ gitbutler-stack.workspace = true
2121
gitbutler-workspace.workspace = true
2222
gitbutler-project.workspace = true
2323
serde.workspace = true
24+
25+
[dev-dependencies]
26+
gix-testtools.workspace = true
27+
gitbutler-testsupport.workspace = true
28+
gitbutler-oxidize.workspace = true
29+
insta.workspace = true
30+
serde_json = "1.0.145"

crates/but-cherry-apply/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use gitbutler_workspace::branch_trees::{WorkspaceState, update_uncommited_change
3535
use gix::{ObjectId, Repository};
3636
use serde::Serialize;
3737

38-
#[derive(Debug, Clone, Serialize)]
38+
#[derive(Debug, Clone, Serialize, PartialEq)]
3939
#[serde(tag = "type", content = "subject", rename_all = "camelCase")]
4040
pub enum CherryApplyStatus {
4141
CausesWorkspaceConflict,
@@ -157,8 +157,6 @@ fn cherry_pick_conflicts(repo: &Repository, from: ObjectId, onto: ObjectId) -> R
157157
.object()?
158158
.into_commit();
159159

160-
dbg!(&from, &onto, &base);
161-
162160
Ok(!repo.merges_cleanly(
163161
base.tree_id()?.detach(),
164162
from.tree_id()?.detach(),
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
/// Tests for cherry-apply functionality
2+
mod util {
3+
use but_cherry_apply::{CherryApplyStatus, cherry_apply, cherry_apply_status};
4+
use gitbutler_command_context::CommandContext;
5+
use gitbutler_stack::VirtualBranchesHandle;
6+
use gix_testtools::tempfile::TempDir;
7+
8+
pub fn test_ctx(name: &str) -> anyhow::Result<TestContext> {
9+
let (ctx, tmpdir) = gitbutler_testsupport::writable::fixture("cherry_apply.sh", name)?;
10+
let handle = VirtualBranchesHandle::new(ctx.project().gb_dir());
11+
12+
Ok(TestContext {
13+
ctx,
14+
handle,
15+
_tmpdir: tmpdir,
16+
})
17+
}
18+
19+
pub struct TestContext {
20+
pub ctx: CommandContext,
21+
pub handle: VirtualBranchesHandle,
22+
pub _tmpdir: TempDir,
23+
}
24+
25+
impl TestContext {
26+
pub fn get_status(&self, commit_id: gix::ObjectId) -> anyhow::Result<CherryApplyStatus> {
27+
cherry_apply_status(
28+
&self.ctx,
29+
self.ctx
30+
.project()
31+
.exclusive_worktree_access()
32+
.read_permission(),
33+
commit_id,
34+
)
35+
}
36+
37+
pub fn apply(
38+
&self,
39+
commit_id: gix::ObjectId,
40+
target_stack: but_workspace::StackId,
41+
) -> anyhow::Result<()> {
42+
cherry_apply(
43+
&self.ctx,
44+
self.ctx
45+
.project()
46+
.exclusive_worktree_access()
47+
.write_permission(),
48+
commit_id,
49+
target_stack,
50+
)
51+
}
52+
}
53+
}
54+
55+
use but_cherry_apply::CherryApplyStatus;
56+
use but_graph::VirtualBranchesTomlMetadata;
57+
use but_workspace::stack_details_v3;
58+
59+
mod clean_to_both {
60+
use super::*;
61+
use util::test_ctx;
62+
63+
#[test]
64+
fn status_is_applicable_to_any_stack() -> anyhow::Result<()> {
65+
let test_ctx = test_ctx("clean-to-both")?;
66+
67+
let repo = test_ctx.ctx.gix_repo()?;
68+
let commit_id = repo
69+
.rev_parse_single("refs/gitbutler/clean-commit")?
70+
.detach();
71+
72+
let status = test_ctx.get_status(commit_id)?;
73+
74+
assert_eq!(status, CherryApplyStatus::ApplicableToAnyStack);
75+
76+
Ok(())
77+
}
78+
79+
#[test]
80+
fn can_apply_to_foo_stack() -> anyhow::Result<()> {
81+
let test_ctx = test_ctx("clean-to-both")?;
82+
83+
let repo = test_ctx.ctx.gix_repo()?;
84+
let commit_id = repo
85+
.rev_parse_single("refs/gitbutler/clean-commit")?
86+
.detach();
87+
88+
let foo_id = test_ctx
89+
.handle
90+
.list_stacks_in_workspace()?
91+
.iter()
92+
.find(|s| s.name == "foo")
93+
.unwrap()
94+
.id;
95+
96+
// Apply should succeed
97+
test_ctx.apply(commit_id, foo_id)?;
98+
99+
// Verify the commit is now in the foo stack by checking for its message
100+
let meta = VirtualBranchesTomlMetadata::from_path(
101+
test_ctx
102+
.ctx
103+
.project()
104+
.gb_dir()
105+
.join("virtual_branches.toml"),
106+
)?;
107+
let details = stack_details_v3(Some(foo_id), &repo, &meta)?;
108+
109+
let has_commit = details
110+
.branch_details
111+
.iter()
112+
.flat_map(|branch| &branch.commits)
113+
.any(|commit| {
114+
commit
115+
.message
116+
.to_string()
117+
.contains("Add clean change to shared.txt")
118+
});
119+
120+
assert!(
121+
has_commit,
122+
"Expected to find cherry-picked commit in foo stack"
123+
);
124+
125+
Ok(())
126+
}
127+
128+
#[test]
129+
fn can_apply_to_bar_stack() -> anyhow::Result<()> {
130+
let test_ctx = test_ctx("clean-to-both")?;
131+
132+
let repo = test_ctx.ctx.gix_repo()?;
133+
let commit_id = repo
134+
.rev_parse_single("refs/gitbutler/clean-commit")?
135+
.detach();
136+
137+
let bar_id = test_ctx
138+
.handle
139+
.list_stacks_in_workspace()?
140+
.iter()
141+
.find(|s| s.name == "bar")
142+
.unwrap()
143+
.id;
144+
145+
// Apply should succeed
146+
test_ctx.apply(commit_id, bar_id)?;
147+
148+
// Verify the commit is now in the bar stack by checking for its message
149+
let meta = VirtualBranchesTomlMetadata::from_path(
150+
test_ctx
151+
.ctx
152+
.project()
153+
.gb_dir()
154+
.join("virtual_branches.toml"),
155+
)?;
156+
let details = stack_details_v3(Some(bar_id), &repo, &meta)?;
157+
158+
let has_commit = details
159+
.branch_details
160+
.iter()
161+
.flat_map(|branch| &branch.commits)
162+
.any(|commit| {
163+
commit
164+
.message
165+
.to_string()
166+
.contains("Add clean change to shared.txt")
167+
});
168+
169+
assert!(
170+
has_commit,
171+
"Expected to find cherry-picked commit in bar stack"
172+
);
173+
174+
Ok(())
175+
}
176+
}
177+
178+
mod conflicts_with_bar {
179+
use super::*;
180+
use util::test_ctx;
181+
182+
#[test]
183+
fn status_is_locked_to_bar() -> anyhow::Result<()> {
184+
let test_ctx = test_ctx("conflicts-with-bar")?;
185+
186+
let repo = test_ctx.ctx.gix_repo()?;
187+
let commit_id = repo
188+
.rev_parse_single("refs/gitbutler/bar-conflict")?
189+
.detach();
190+
191+
let status = test_ctx.get_status(commit_id)?;
192+
193+
let bar_id = test_ctx
194+
.handle
195+
.list_stacks_in_workspace()?
196+
.iter()
197+
.find(|s| s.name == "bar")
198+
.unwrap()
199+
.id;
200+
201+
assert_eq!(status, CherryApplyStatus::LockedToStack(bar_id));
202+
203+
Ok(())
204+
}
205+
206+
#[test]
207+
fn can_only_apply_to_bar_stack() -> anyhow::Result<()> {
208+
let test_ctx = test_ctx("conflicts-with-bar")?;
209+
210+
let repo = test_ctx.ctx.gix_repo()?;
211+
let commit_id = repo
212+
.rev_parse_single("refs/gitbutler/bar-conflict")?
213+
.detach();
214+
215+
let bar_id = test_ctx
216+
.handle
217+
.list_stacks_in_workspace()?
218+
.iter()
219+
.find(|s| s.name == "bar")
220+
.unwrap()
221+
.id;
222+
223+
// Apply to bar should succeed
224+
test_ctx.apply(commit_id, bar_id)?;
225+
226+
// Verify the commit is now in the bar stack by checking for its message
227+
let meta = VirtualBranchesTomlMetadata::from_path(
228+
test_ctx
229+
.ctx
230+
.project()
231+
.gb_dir()
232+
.join("virtual_branches.toml"),
233+
)?;
234+
let details = stack_details_v3(Some(bar_id), &repo, &meta)?;
235+
236+
let has_commit = details
237+
.branch_details
238+
.iter()
239+
.flat_map(|branch| &branch.commits)
240+
.any(|commit| {
241+
commit
242+
.message
243+
.to_string()
244+
.contains("Conflicting change to bar.txt")
245+
});
246+
247+
assert!(
248+
has_commit,
249+
"Expected to find cherry-picked commit in bar stack"
250+
);
251+
252+
Ok(())
253+
}
254+
}
255+
256+
mod conflicts_with_both {
257+
use super::*;
258+
use util::test_ctx;
259+
260+
#[test]
261+
fn status_is_causes_workspace_conflict() -> anyhow::Result<()> {
262+
let test_ctx = test_ctx("conflicts-with-both")?;
263+
264+
let repo = test_ctx.ctx.gix_repo()?;
265+
let commit_id = repo
266+
.rev_parse_single("refs/gitbutler/both-conflict")?
267+
.detach();
268+
269+
let status = test_ctx.get_status(commit_id)?;
270+
271+
assert_eq!(status, CherryApplyStatus::CausesWorkspaceConflict);
272+
273+
Ok(())
274+
}
275+
276+
#[test]
277+
fn cannot_apply_to_foo_stack() -> anyhow::Result<()> {
278+
let test_ctx = test_ctx("conflicts-with-both")?;
279+
280+
let repo = test_ctx.ctx.gix_repo()?;
281+
let commit_id = repo
282+
.rev_parse_single("refs/gitbutler/both-conflict")?
283+
.detach();
284+
285+
let foo_id = test_ctx
286+
.handle
287+
.list_stacks_in_workspace()?
288+
.iter()
289+
.find(|s| s.name == "foo")
290+
.unwrap()
291+
.id;
292+
293+
// Apply should fail
294+
let result = test_ctx.apply(commit_id, foo_id);
295+
assert!(result.is_err());
296+
assert!(
297+
result
298+
.unwrap_err()
299+
.to_string()
300+
.contains("causes workspace conflicts")
301+
);
302+
303+
Ok(())
304+
}
305+
306+
#[test]
307+
fn cannot_apply_to_bar_stack() -> anyhow::Result<()> {
308+
let test_ctx = test_ctx("conflicts-with-both")?;
309+
310+
let repo = test_ctx.ctx.gix_repo()?;
311+
let commit_id = repo
312+
.rev_parse_single("refs/gitbutler/both-conflict")?
313+
.detach();
314+
315+
let bar_id = test_ctx
316+
.handle
317+
.list_stacks_in_workspace()?
318+
.iter()
319+
.find(|s| s.name == "bar")
320+
.unwrap()
321+
.id;
322+
323+
// Apply should fail
324+
let result = test_ctx.apply(commit_id, bar_id);
325+
assert!(result.is_err());
326+
assert!(
327+
result
328+
.unwrap_err()
329+
.to_string()
330+
.contains("causes workspace conflicts")
331+
);
332+
333+
Ok(())
334+
}
335+
}
336+
337+
mod no_stacks {
338+
use super::*;
339+
use util::test_ctx;
340+
341+
#[test]
342+
fn status_is_no_stacks() -> anyhow::Result<()> {
343+
let test_ctx = test_ctx("no-stacks")?;
344+
345+
let repo = test_ctx.ctx.gix_repo()?;
346+
let commit_id = repo
347+
.rev_parse_single("refs/gitbutler/no-stacks-commit")?
348+
.detach();
349+
350+
let status = test_ctx.get_status(commit_id)?;
351+
352+
assert_eq!(status, CherryApplyStatus::NoStacks);
353+
354+
Ok(())
355+
}
356+
}

0 commit comments

Comments
 (0)