Restore project diff test (#21606)

Restores a basic project diff test

Release Notes:

- N/A

---------

Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
Kirill Bulatov 2024-12-05 21:48:33 +02:00 committed by GitHub
parent 787c75cbda
commit 1efd165ead
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 141 additions and 112 deletions

View file

@ -55,6 +55,7 @@ struct ProjectDiffEditor {
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
#[derive(Debug)]
struct Changes { struct Changes {
_status: GitFileStatus, _status: GitFileStatus,
buffer: Model<Buffer>, buffer: Model<Buffer>,
@ -235,15 +236,16 @@ impl ProjectDiffEditor {
let mut change_sets = Vec::new(); let mut change_sets = Vec::new();
for (status, entry_id, entry_path, open_task) in open_tasks { for (status, entry_id, entry_path, open_task) in open_tasks {
let (_, opened_model) = open_task.await.with_context(|| { let (_, opened_model) = open_task.await.with_context(|| {
format!("loading buffer {} for git diff", entry_path.path.display()) format!("loading buffer {:?} for git diff", entry_path.path)
})?; })?;
let buffer = match opened_model.downcast::<Buffer>() { let buffer = match opened_model.downcast::<Buffer>() {
Ok(buffer) => buffer, Ok(buffer) => buffer,
Err(_model) => anyhow::bail!( Err(_model) => anyhow::bail!(
"Could not load {} as a buffer for git diff", "Could not load {:?} as a buffer for git diff",
entry_path.path.display() entry_path.path
), ),
}; };
let change_set = project let change_set = project
.update(&mut cx, |project, cx| { .update(&mut cx, |project, cx| {
project.open_unstaged_changes(buffer.clone(), cx) project.open_unstaged_changes(buffer.clone(), cx)
@ -1089,13 +1091,16 @@ impl Render for ProjectDiffEditor {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
// use std::{ops::Deref as _, path::Path, sync::Arc}; use gpui::{SemanticVersion, TestAppContext, VisualTestContext};
use project::buffer_store::BufferChangeSet;
use serde_json::json;
use settings::SettingsStore;
use std::{
ops::Deref as _,
path::{Path, PathBuf},
};
// use fs::RealFs; use super::*;
// use gpui::{SemanticVersion, TestAppContext, VisualTestContext};
// use settings::SettingsStore;
// use super::*;
// TODO finish // TODO finish
// #[gpui::test] // #[gpui::test]
@ -1111,114 +1116,131 @@ mod tests {
// // Apply randomized changes to the project: select a random file, random change and apply to buffers // // Apply randomized changes to the project: select a random file, random change and apply to buffers
// } // }
// #[gpui::test] #[gpui::test(iterations = 30)]
// async fn simple_edit_test(cx: &mut TestAppContext) { async fn simple_edit_test(cx: &mut TestAppContext) {
// cx.executor().allow_parking(); cx.executor().allow_parking();
// init_test(cx); init_test(cx);
// let dir = tempfile::tempdir().unwrap(); let fs = fs::FakeFs::new(cx.executor().clone());
// let dst = dir.path(); fs.insert_tree(
"/root",
json!({
".git": {},
"file_a": "This is file_a",
"file_b": "This is file_b",
}),
)
.await;
// std::fs::write(dst.join("file_a"), "This is file_a").unwrap(); let project = Project::test(fs.clone(), [Path::new("/root")], cx).await;
// std::fs::write(dst.join("file_b"), "This is file_b").unwrap(); let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx);
// run_git(dst, &["init"]); let file_a_editor = workspace
// run_git(dst, &["add", "*"]); .update(cx, |workspace, cx| {
// run_git(dst, &["commit", "-m", "Initial commit"]); let file_a_editor =
workspace.open_abs_path(PathBuf::from("/root/file_a"), true, cx);
ProjectDiffEditor::deploy(workspace, &Deploy, cx);
file_a_editor
})
.unwrap()
.await
.expect("did not open an item at all")
.downcast::<Editor>()
.expect("did not open an editor for file_a");
let project_diff_editor = workspace
.update(cx, |workspace, cx| {
workspace
.active_pane()
.read(cx)
.items()
.find_map(|item| item.downcast::<ProjectDiffEditor>())
})
.unwrap()
.expect("did not find a ProjectDiffEditor");
project_diff_editor.update(cx, |project_diff_editor, cx| {
assert!(
project_diff_editor.editor.read(cx).text(cx).is_empty(),
"Should have no changes after opening the diff on no git changes"
);
});
// let project = Project::test(Arc::new(RealFs::default()), [dst], cx).await; let old_text = file_a_editor.update(cx, |editor, cx| editor.text(cx));
// let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let change = "an edit after git add";
// let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx); file_a_editor
.update(cx, |file_a_editor, cx| {
file_a_editor.insert(change, cx);
file_a_editor.save(false, project.clone(), cx)
})
.await
.expect("failed to save a file");
file_a_editor.update(cx, |file_a_editor, cx| {
let change_set = cx.new_model(|cx| {
BufferChangeSet::new_with_base_text(
old_text.clone(),
file_a_editor
.buffer()
.read(cx)
.as_singleton()
.unwrap()
.read(cx)
.text_snapshot(),
cx,
)
});
file_a_editor
.diff_map
.add_change_set(change_set.clone(), cx);
project.update(cx, |project, cx| {
project.buffer_store().update(cx, |buffer_store, cx| {
buffer_store.set_change_set(
file_a_editor
.buffer()
.read(cx)
.as_singleton()
.unwrap()
.read(cx)
.remote_id(),
change_set,
);
});
});
});
fs.set_status_for_repo_via_git_operation(
Path::new("/root/.git"),
&[(Path::new("file_a"), GitFileStatus::Modified)],
);
cx.executor()
.advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(100));
cx.run_until_parked();
// let file_a_editor = workspace project_diff_editor.update(cx, |project_diff_editor, cx| {
// .update(cx, |workspace, cx| { assert_eq!(
// let file_a_editor = workspace.open_abs_path(dst.join("file_a"), true, cx); // TODO assert it better: extract added text (based on the background changes) and deleted text (based on the deleted blocks added)
// ProjectDiffEditor::deploy(workspace, &Deploy, cx); project_diff_editor.editor.read(cx).text(cx),
// file_a_editor format!("{change}{old_text}"),
// }) "Should have a new change shown in the beginning, and the old text shown as deleted text afterwards"
// .unwrap() );
// .await });
// .expect("did not open an item at all") }
// .downcast::<Editor>()
// .expect("did not open an editor for file_a");
// let project_diff_editor = workspace fn init_test(cx: &mut gpui::TestAppContext) {
// .update(cx, |workspace, cx| { if std::env::var("RUST_LOG").is_ok() {
// workspace env_logger::try_init().ok();
// .active_pane() }
// .read(cx)
// .items()
// .find_map(|item| item.downcast::<ProjectDiffEditor>())
// })
// .unwrap()
// .expect("did not find a ProjectDiffEditor");
// project_diff_editor.update(cx, |project_diff_editor, cx| {
// assert!(
// project_diff_editor.editor.read(cx).text(cx).is_empty(),
// "Should have no changes after opening the diff on no git changes"
// );
// });
// let old_text = file_a_editor.update(cx, |editor, cx| editor.text(cx)); cx.update(|cx| {
// let change = "an edit after git add"; assets::Assets.load_test_fonts(cx);
// file_a_editor let settings_store = SettingsStore::test(cx);
// .update(cx, |file_a_editor, cx| { cx.set_global(settings_store);
// file_a_editor.insert(change, cx); theme::init(theme::LoadThemes::JustBase, cx);
// file_a_editor.save(false, project.clone(), cx) release_channel::init(SemanticVersion::default(), cx);
// }) client::init_settings(cx);
// .await language::init(cx);
// .expect("failed to save a file"); Project::init_settings(cx);
// cx.executor().advance_clock(Duration::from_secs(1)); workspace::init_settings(cx);
// cx.run_until_parked(); crate::init(cx);
cx.set_staff(true);
// // TODO does not work on Linux for some reason, returning a blank line });
// // hence disable the last check for now, and do some fiddling to avoid the warnings. }
// #[cfg(target_os = "linux")]
// {
// if true {
// return;
// }
// }
// project_diff_editor.update(cx, |project_diff_editor, cx| {
// // TODO assert it better: extract added text (based on the background changes) and deleted text (based on the deleted blocks added)
// assert_eq!(
// project_diff_editor.editor.read(cx).text(cx),
// format!("{change}{old_text}"),
// "Should have a new change shown in the beginning, and the old text shown as deleted text afterwards"
// );
// });
// }
// fn run_git(path: &Path, args: &[&str]) -> String {
// let output = std::process::Command::new("git")
// .args(args)
// .current_dir(path)
// .output()
// .expect("git commit failed");
// format!(
// "Stdout: {}; stderr: {}",
// String::from_utf8(output.stdout).unwrap(),
// String::from_utf8(output.stderr).unwrap()
// )
// }
// fn init_test(cx: &mut gpui::TestAppContext) {
// if std::env::var("RUST_LOG").is_ok() {
// env_logger::try_init().ok();
// }
// cx.update(|cx| {
// assets::Assets.load_test_fonts(cx);
// let settings_store = SettingsStore::test(cx);
// cx.set_global(settings_store);
// theme::init(theme::LoadThemes::JustBase, cx);
// release_channel::init(SemanticVersion::default(), cx);
// client::init_settings(cx);
// language::init(cx);
// Project::init_settings(cx);
// workspace::init_settings(cx);
// crate::init(cx);
// });
// }
} }

View file

@ -49,6 +49,7 @@ struct SharedBuffer {
unstaged_changes: Option<Model<BufferChangeSet>>, unstaged_changes: Option<Model<BufferChangeSet>>,
} }
#[derive(Debug)]
pub struct BufferChangeSet { pub struct BufferChangeSet {
pub buffer_id: BufferId, pub buffer_id: BufferId,
pub base_text: Option<Model<Buffer>>, pub base_text: Option<Model<Buffer>>,
@ -1045,6 +1046,12 @@ impl BufferStore {
.spawn(async move { task.await.map_err(|e| anyhow!("{e}")) }) .spawn(async move { task.await.map_err(|e| anyhow!("{e}")) })
} }
#[cfg(any(test, feature = "test-support"))]
pub fn set_change_set(&mut self, buffer_id: BufferId, change_set: Model<BufferChangeSet>) {
self.loading_change_sets
.insert(buffer_id, Task::ready(Ok(change_set)).shared());
}
pub async fn open_unstaged_changes_internal( pub async fn open_unstaged_changes_internal(
this: WeakModel<Self>, this: WeakModel<Self>,
text: Result<Option<String>>, text: Result<Option<String>>,