mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-26 18:41:10 +00:00
Add buffer management test to Copilot
This commit is contained in:
parent
4d207981ae
commit
4151bd39da
3 changed files with 230 additions and 1 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -1341,14 +1341,17 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-compression",
|
"async-compression",
|
||||||
"async-tar",
|
"async-tar",
|
||||||
|
"clock",
|
||||||
"collections",
|
"collections",
|
||||||
"context_menu",
|
"context_menu",
|
||||||
|
"fs",
|
||||||
"futures 0.3.25",
|
"futures 0.3.25",
|
||||||
"gpui",
|
"gpui",
|
||||||
"language",
|
"language",
|
||||||
"log",
|
"log",
|
||||||
"lsp",
|
"lsp",
|
||||||
"node_runtime",
|
"node_runtime",
|
||||||
|
"rpc",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"settings",
|
"settings",
|
||||||
|
|
|
@ -38,10 +38,13 @@ smol = "1.2.5"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
clock = { path = "../clock" }
|
||||||
collections = { path = "../collections", features = ["test-support"] }
|
collections = { path = "../collections", features = ["test-support"] }
|
||||||
|
fs = { path = "../fs", features = ["test-support"] }
|
||||||
gpui = { path = "../gpui", features = ["test-support"] }
|
gpui = { path = "../gpui", features = ["test-support"] }
|
||||||
language = { path = "../language", features = ["test-support"] }
|
language = { path = "../language", features = ["test-support"] }
|
||||||
settings = { path = "../settings", features = ["test-support"] }
|
|
||||||
lsp = { path = "../lsp", features = ["test-support"] }
|
lsp = { path = "../lsp", features = ["test-support"] }
|
||||||
|
rpc = { path = "../rpc", features = ["test-support"] }
|
||||||
|
settings = { path = "../settings", features = ["test-support"] }
|
||||||
util = { path = "../util", features = ["test-support"] }
|
util = { path = "../util", features = ["test-support"] }
|
||||||
workspace = { path = "../workspace", features = ["test-support"] }
|
workspace = { path = "../workspace", features = ["test-support"] }
|
||||||
|
|
|
@ -945,3 +945,226 @@ async fn get_copilot_lsp(http: Arc<dyn HttpClient>) -> anyhow::Result<PathBuf> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use gpui::{executor::Deterministic, TestAppContext};
|
||||||
|
|
||||||
|
#[gpui::test(iterations = 10)]
|
||||||
|
async fn test_buffer_management(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) {
|
||||||
|
deterministic.forbid_parking();
|
||||||
|
let (copilot, mut lsp) = Copilot::fake(cx);
|
||||||
|
|
||||||
|
let buffer_1 = cx.add_model(|cx| Buffer::new(0, "Hello", cx));
|
||||||
|
let buffer_1_uri: lsp::Url = format!("buffer://{}", buffer_1.id()).parse().unwrap();
|
||||||
|
copilot.update(cx, |copilot, cx| copilot.register_buffer(&buffer_1, cx));
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidOpenTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentItem::new(
|
||||||
|
buffer_1_uri.clone(),
|
||||||
|
"plaintext".into(),
|
||||||
|
0,
|
||||||
|
"Hello".into()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let buffer_2 = cx.add_model(|cx| Buffer::new(0, "Goodbye", cx));
|
||||||
|
let buffer_2_uri: lsp::Url = format!("buffer://{}", buffer_2.id()).parse().unwrap();
|
||||||
|
copilot.update(cx, |copilot, cx| copilot.register_buffer(&buffer_2, cx));
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidOpenTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentItem::new(
|
||||||
|
buffer_2_uri.clone(),
|
||||||
|
"plaintext".into(),
|
||||||
|
0,
|
||||||
|
"Goodbye".into()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
buffer_1.update(cx, |buffer, cx| buffer.edit([(5..5, " world")], None, cx));
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidChangeTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidChangeTextDocumentParams {
|
||||||
|
text_document: lsp::VersionedTextDocumentIdentifier::new(buffer_1_uri.clone(), 1),
|
||||||
|
content_changes: vec![lsp::TextDocumentContentChangeEvent {
|
||||||
|
range: Some(lsp::Range::new(
|
||||||
|
lsp::Position::new(0, 5),
|
||||||
|
lsp::Position::new(0, 5)
|
||||||
|
)),
|
||||||
|
range_length: None,
|
||||||
|
text: " world".into(),
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure updates to the file are reflected in the LSP.
|
||||||
|
buffer_1
|
||||||
|
.update(cx, |buffer, cx| {
|
||||||
|
buffer.file_updated(
|
||||||
|
Arc::new(File {
|
||||||
|
abs_path: "/root/child/buffer-1".into(),
|
||||||
|
path: Path::new("child/buffer-1").into(),
|
||||||
|
}),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidCloseTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidCloseTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentIdentifier::new(buffer_1_uri),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let buffer_1_uri = lsp::Url::from_file_path("/root/child/buffer-1").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidOpenTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentItem::new(
|
||||||
|
buffer_1_uri.clone(),
|
||||||
|
"plaintext".into(),
|
||||||
|
1,
|
||||||
|
"Hello world".into()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure all previously-registered buffers are closed when signing out.
|
||||||
|
lsp.handle_request::<request::SignOut, _, _>(|_, _| async {
|
||||||
|
Ok(request::SignOutResult {})
|
||||||
|
});
|
||||||
|
copilot
|
||||||
|
.update(cx, |copilot, cx| copilot.sign_out(cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidCloseTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidCloseTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentIdentifier::new(buffer_2_uri.clone()),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidCloseTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidCloseTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentIdentifier::new(buffer_1_uri.clone()),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure all previously-registered buffers are re-opened when signing in.
|
||||||
|
lsp.handle_request::<request::SignInInitiate, _, _>(|_, _| async {
|
||||||
|
Ok(request::SignInInitiateResult::AlreadySignedIn {
|
||||||
|
user: "user-1".into(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
copilot
|
||||||
|
.update(cx, |copilot, cx| copilot.sign_in(cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidOpenTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentItem::new(
|
||||||
|
buffer_2_uri.clone(),
|
||||||
|
"plaintext".into(),
|
||||||
|
0,
|
||||||
|
"Goodbye".into()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidOpenTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentItem::new(
|
||||||
|
buffer_1_uri.clone(),
|
||||||
|
"plaintext".into(),
|
||||||
|
0,
|
||||||
|
"Hello world".into()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dropping a buffer causes it to be closed on the LSP side as well.
|
||||||
|
cx.update(|_| drop(buffer_2));
|
||||||
|
assert_eq!(
|
||||||
|
lsp.receive_notification::<lsp::notification::DidCloseTextDocument>()
|
||||||
|
.await,
|
||||||
|
lsp::DidCloseTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentIdentifier::new(buffer_2_uri),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct File {
|
||||||
|
abs_path: PathBuf,
|
||||||
|
path: Arc<Path>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl language::File for File {
|
||||||
|
fn as_local(&self) -> Option<&dyn language::LocalFile> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mtime(&self) -> std::time::SystemTime {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> &Arc<Path> {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full_path(&self, _: &AppContext) -> PathBuf {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_name<'a>(&'a self, _: &'a AppContext) -> &'a std::ffi::OsStr {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_deleted(&self) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_proto(&self) -> rpc::proto::File {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl language::LocalFile for File {
|
||||||
|
fn abs_path(&self, _: &AppContext) -> PathBuf {
|
||||||
|
self.abs_path.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(&self, _: &AppContext) -> Task<Result<String>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn buffer_reloaded(
|
||||||
|
&self,
|
||||||
|
_: u64,
|
||||||
|
_: &clock::Global,
|
||||||
|
_: language::RopeFingerprint,
|
||||||
|
_: ::fs::LineEnding,
|
||||||
|
_: std::time::SystemTime,
|
||||||
|
_: &mut AppContext,
|
||||||
|
) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue