Make operations for all buffer manipulations
This commit is contained in:
parent
f1b3692a35
commit
210286da48
1 changed files with 252 additions and 284 deletions
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use client::RECEIVE_TIMEOUT;
|
use client::RECEIVE_TIMEOUT;
|
||||||
use collections::BTreeMap;
|
use collections::{BTreeMap, HashSet};
|
||||||
use fs::Fs as _;
|
use fs::Fs as _;
|
||||||
use futures::StreamExt as _;
|
use futures::StreamExt as _;
|
||||||
use gpui::{executor::Deterministic, ModelHandle, TestAppContext};
|
use gpui::{executor::Deterministic, ModelHandle, TestAppContext};
|
||||||
|
@ -486,14 +486,44 @@ enum ClientOperation {
|
||||||
project_root_name: String,
|
project_root_name: String,
|
||||||
full_path: PathBuf,
|
full_path: PathBuf,
|
||||||
},
|
},
|
||||||
|
SearchProject {
|
||||||
|
project_root_name: String,
|
||||||
|
query: String,
|
||||||
|
detach: bool,
|
||||||
|
},
|
||||||
EditBuffer {
|
EditBuffer {
|
||||||
project_root_name: String,
|
project_root_name: String,
|
||||||
full_path: PathBuf,
|
full_path: PathBuf,
|
||||||
edits: Vec<(Range<usize>, Arc<str>)>,
|
edits: Vec<(Range<usize>, Arc<str>)>,
|
||||||
},
|
},
|
||||||
|
CloseBuffer {
|
||||||
|
project_root_name: String,
|
||||||
|
full_path: PathBuf,
|
||||||
|
},
|
||||||
|
SaveBuffer {
|
||||||
|
project_root_name: String,
|
||||||
|
full_path: PathBuf,
|
||||||
|
detach: bool,
|
||||||
|
},
|
||||||
|
RequestLspDataInBuffer {
|
||||||
|
project_root_name: String,
|
||||||
|
full_path: PathBuf,
|
||||||
|
offset: usize,
|
||||||
|
kind: LspRequestKind,
|
||||||
|
detach: bool,
|
||||||
|
},
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum LspRequestKind {
|
||||||
|
Rename,
|
||||||
|
Completion,
|
||||||
|
CodeAction,
|
||||||
|
Definition,
|
||||||
|
Highlights,
|
||||||
|
}
|
||||||
|
|
||||||
impl TestPlan {
|
impl TestPlan {
|
||||||
async fn next_operation(&mut self, clients: &[(Rc<TestClient>, TestAppContext)]) -> Operation {
|
async fn next_operation(&mut self, clients: &[(Rc<TestClient>, TestAppContext)]) -> Operation {
|
||||||
let operation = loop {
|
let operation = loop {
|
||||||
|
@ -679,27 +709,44 @@ impl TestPlan {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Mutate buffers
|
// Query and mutate buffers
|
||||||
60.. => {
|
60.. => {
|
||||||
let Some(project) = choose_random_project(client, &mut self.rng) else { continue };
|
let Some(project) = choose_random_project(client, &mut self.rng) else { continue };
|
||||||
let project_root_name = root_name_for_project(&project, cx);
|
let project_root_name = root_name_for_project(&project, cx);
|
||||||
|
|
||||||
match self.rng.gen_range(0..100_u32) {
|
match self.rng.gen_range(0..100_u32) {
|
||||||
// Manipulate an existing buffer
|
// Manipulate an existing buffer
|
||||||
0..=80 => {
|
0..=70 => {
|
||||||
let Some(buffer) = client
|
let Some(buffer) = client
|
||||||
.buffers_for_project(&project)
|
.buffers_for_project(&project)
|
||||||
.iter()
|
.iter()
|
||||||
.choose(&mut self.rng)
|
.choose(&mut self.rng)
|
||||||
.cloned() else { continue };
|
.cloned() else { continue };
|
||||||
|
|
||||||
|
let full_path = buffer
|
||||||
|
.read_with(cx, |buffer, cx| buffer.file().unwrap().full_path(cx));
|
||||||
|
|
||||||
match self.rng.gen_range(0..100_u32) {
|
match self.rng.gen_range(0..100_u32) {
|
||||||
0..=9 => {
|
// Close the buffer
|
||||||
let (full_path, edits) = buffer.read_with(cx, |buffer, cx| {
|
0..=15 => {
|
||||||
(
|
break ClientOperation::CloseBuffer {
|
||||||
buffer.file().unwrap().full_path(cx),
|
project_root_name,
|
||||||
buffer.get_random_edits(&mut self.rng, 3),
|
full_path,
|
||||||
)
|
};
|
||||||
|
}
|
||||||
|
// Save the buffer
|
||||||
|
16..=29 if buffer.read_with(cx, |b, _| b.is_dirty()) => {
|
||||||
|
let detach = self.rng.gen_bool(0.3);
|
||||||
|
break ClientOperation::SaveBuffer {
|
||||||
|
project_root_name,
|
||||||
|
full_path,
|
||||||
|
detach,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Edit the buffer
|
||||||
|
30..=69 => {
|
||||||
|
let edits = buffer.read_with(cx, |buffer, _| {
|
||||||
|
buffer.get_random_edits(&mut self.rng, 3)
|
||||||
});
|
});
|
||||||
break ClientOperation::EditBuffer {
|
break ClientOperation::EditBuffer {
|
||||||
project_root_name,
|
project_root_name,
|
||||||
|
@ -707,10 +754,42 @@ impl TestPlan {
|
||||||
edits,
|
edits,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => {}
|
// Make an LSP request
|
||||||
|
_ => {
|
||||||
|
let offset = buffer.read_with(cx, |buffer, _| {
|
||||||
|
buffer.clip_offset(
|
||||||
|
self.rng.gen_range(0..=buffer.len()),
|
||||||
|
language::Bias::Left,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
let detach = self.rng.gen();
|
||||||
|
break ClientOperation::RequestLspDataInBuffer {
|
||||||
|
project_root_name,
|
||||||
|
full_path,
|
||||||
|
offset,
|
||||||
|
kind: match self.rng.gen_range(0..5_u32) {
|
||||||
|
0 => LspRequestKind::Rename,
|
||||||
|
1 => LspRequestKind::Highlights,
|
||||||
|
2 => LspRequestKind::Definition,
|
||||||
|
3 => LspRequestKind::CodeAction,
|
||||||
|
4.. => LspRequestKind::Completion,
|
||||||
|
},
|
||||||
|
detach,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
71..=80 => {
|
||||||
|
let query = self.rng.gen_range('a'..='z').to_string();
|
||||||
|
let detach = self.rng.gen_bool(0.3);
|
||||||
|
break ClientOperation::SearchProject {
|
||||||
|
project_root_name,
|
||||||
|
query,
|
||||||
|
detach,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Open a buffer
|
// Open a buffer
|
||||||
81.. => {
|
81.. => {
|
||||||
let worktree = project.read_with(cx, |project, cx| {
|
let worktree = project.read_with(cx, |project, cx| {
|
||||||
|
@ -1066,21 +1145,159 @@ async fn apply_client_operation(
|
||||||
);
|
);
|
||||||
let project = project_for_root_name(client, &project_root_name, cx)
|
let project = project_for_root_name(client, &project_root_name, cx)
|
||||||
.expect("invalid project in test operation");
|
.expect("invalid project in test operation");
|
||||||
let buffer = client
|
let buffer =
|
||||||
.buffers_for_project(&project)
|
buffer_for_full_path(&*client.buffers_for_project(&project), &full_path, cx)
|
||||||
.iter()
|
.expect("invalid buffer path in test operation");
|
||||||
.find(|buffer| {
|
|
||||||
buffer.read_with(cx, |buffer, cx| {
|
|
||||||
buffer.file().unwrap().full_path(cx) == full_path
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.expect("invalid buffer path in test operation");
|
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.edit(edits, None, cx);
|
buffer.edit(edits, None, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClientOperation::CloseBuffer {
|
||||||
|
project_root_name,
|
||||||
|
full_path,
|
||||||
|
} => {
|
||||||
|
log::info!(
|
||||||
|
"{}: dropping buffer {:?} in project {}",
|
||||||
|
client.username,
|
||||||
|
full_path,
|
||||||
|
project_root_name
|
||||||
|
);
|
||||||
|
let project = project_for_root_name(client, &project_root_name, cx)
|
||||||
|
.expect("invalid project in test operation");
|
||||||
|
let buffer =
|
||||||
|
buffer_for_full_path(&*client.buffers_for_project(&project), &full_path, cx)
|
||||||
|
.expect("invalid buffer path in test operation");
|
||||||
|
cx.update(|_| {
|
||||||
|
client.buffers_for_project(&project).remove(&buffer);
|
||||||
|
drop(buffer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientOperation::SaveBuffer {
|
||||||
|
project_root_name,
|
||||||
|
full_path,
|
||||||
|
detach,
|
||||||
|
} => {
|
||||||
|
log::info!(
|
||||||
|
"{}: saving buffer {:?} in project {}{}",
|
||||||
|
client.username,
|
||||||
|
full_path,
|
||||||
|
project_root_name,
|
||||||
|
if detach { ", detaching" } else { ", awaiting" }
|
||||||
|
);
|
||||||
|
let project = project_for_root_name(client, &project_root_name, cx)
|
||||||
|
.expect("invalid project in test operation");
|
||||||
|
let buffer =
|
||||||
|
buffer_for_full_path(&*client.buffers_for_project(&project), &full_path, cx)
|
||||||
|
.expect("invalid buffer path in test operation");
|
||||||
|
let (requested_version, save) =
|
||||||
|
buffer.update(cx, |buffer, cx| (buffer.version(), buffer.save(cx)));
|
||||||
|
let save = cx.background().spawn(async move {
|
||||||
|
let (saved_version, _, _) = save
|
||||||
|
.await
|
||||||
|
.map_err(|err| anyhow!("save request failed: {:?}", err))?;
|
||||||
|
assert!(saved_version.observed_all(&requested_version));
|
||||||
|
anyhow::Ok(())
|
||||||
|
});
|
||||||
|
if detach {
|
||||||
|
log::info!("{}: detaching save request", client.username);
|
||||||
|
cx.update(|cx| save.detach_and_log_err(cx));
|
||||||
|
} else {
|
||||||
|
save.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientOperation::RequestLspDataInBuffer {
|
||||||
|
project_root_name,
|
||||||
|
full_path,
|
||||||
|
offset,
|
||||||
|
kind,
|
||||||
|
detach,
|
||||||
|
} => {
|
||||||
|
log::info!(
|
||||||
|
"{}: request LSP {:?} for buffer {:?} in project {}{}",
|
||||||
|
client.username,
|
||||||
|
kind,
|
||||||
|
full_path,
|
||||||
|
project_root_name,
|
||||||
|
if detach { ", detaching" } else { ", awaiting" }
|
||||||
|
);
|
||||||
|
|
||||||
|
let project = project_for_root_name(client, &project_root_name, cx)
|
||||||
|
.expect("invalid project in test operation");
|
||||||
|
let buffer =
|
||||||
|
buffer_for_full_path(&*client.buffers_for_project(&project), &full_path, cx)
|
||||||
|
.expect("invalid buffer path in test operation");
|
||||||
|
let request = match kind {
|
||||||
|
LspRequestKind::Rename => cx.spawn(|mut cx| async move {
|
||||||
|
project
|
||||||
|
.update(&mut cx, |p, cx| p.prepare_rename(buffer, offset, cx))
|
||||||
|
.await?;
|
||||||
|
anyhow::Ok(())
|
||||||
|
}),
|
||||||
|
LspRequestKind::Completion => cx.spawn(|mut cx| async move {
|
||||||
|
project
|
||||||
|
.update(&mut cx, |p, cx| p.completions(&buffer, offset, cx))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
LspRequestKind::CodeAction => cx.spawn(|mut cx| async move {
|
||||||
|
project
|
||||||
|
.update(&mut cx, |p, cx| p.code_actions(&buffer, offset..offset, cx))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
LspRequestKind::Definition => cx.spawn(|mut cx| async move {
|
||||||
|
project
|
||||||
|
.update(&mut cx, |p, cx| p.definition(&buffer, offset, cx))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
LspRequestKind::Highlights => cx.spawn(|mut cx| async move {
|
||||||
|
project
|
||||||
|
.update(&mut cx, |p, cx| p.document_highlights(&buffer, offset, cx))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
if detach {
|
||||||
|
request.detach();
|
||||||
|
} else {
|
||||||
|
request.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientOperation::SearchProject {
|
||||||
|
project_root_name,
|
||||||
|
query,
|
||||||
|
detach,
|
||||||
|
} => {
|
||||||
|
log::info!(
|
||||||
|
"{}: search project {} for {:?}{}",
|
||||||
|
client.username,
|
||||||
|
project_root_name,
|
||||||
|
query,
|
||||||
|
if detach { ", detaching" } else { ", awaiting" }
|
||||||
|
);
|
||||||
|
let project = project_for_root_name(client, &project_root_name, cx)
|
||||||
|
.expect("invalid project in test operation");
|
||||||
|
let search = project.update(cx, |project, cx| {
|
||||||
|
project.search(SearchQuery::text(query, false, false), cx)
|
||||||
|
});
|
||||||
|
let search = cx.background().spawn(async move {
|
||||||
|
search
|
||||||
|
.await
|
||||||
|
.map_err(|err| anyhow!("search request failed: {:?}", err))
|
||||||
|
});
|
||||||
|
if detach {
|
||||||
|
log::info!("{}: detaching save request", client.username);
|
||||||
|
cx.update(|cx| search.detach_and_log_err(cx));
|
||||||
|
} else {
|
||||||
|
search.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ClientOperation::Other => {
|
ClientOperation::Other => {
|
||||||
let choice = plan.lock().rng.gen_range(0..100);
|
let choice = plan.lock().rng.gen_range(0..100);
|
||||||
match choice {
|
match choice {
|
||||||
|
@ -1090,12 +1307,6 @@ async fn apply_client_operation(
|
||||||
{
|
{
|
||||||
randomly_mutate_worktrees(client, &plan, cx).await?;
|
randomly_mutate_worktrees(client, &plan, cx).await?;
|
||||||
}
|
}
|
||||||
60..=84
|
|
||||||
if !client.local_projects().is_empty()
|
|
||||||
|| !client.remote_projects().is_empty() =>
|
|
||||||
{
|
|
||||||
randomly_query_and_mutate_buffers(client, &plan, cx).await?;
|
|
||||||
}
|
|
||||||
_ => randomly_mutate_fs(client, &plan).await,
|
_ => randomly_mutate_fs(client, &plan).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1103,6 +1314,21 @@ async fn apply_client_operation(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn buffer_for_full_path(
|
||||||
|
buffers: &HashSet<ModelHandle<language::Buffer>>,
|
||||||
|
full_path: &PathBuf,
|
||||||
|
cx: &TestAppContext,
|
||||||
|
) -> Option<ModelHandle<language::Buffer>> {
|
||||||
|
buffers
|
||||||
|
.iter()
|
||||||
|
.find(|buffer| {
|
||||||
|
buffer.read_with(cx, |buffer, cx| {
|
||||||
|
buffer.file().unwrap().full_path(cx) == *full_path
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
|
||||||
fn project_for_root_name(
|
fn project_for_root_name(
|
||||||
client: &TestClient,
|
client: &TestClient,
|
||||||
root_name: &str,
|
root_name: &str,
|
||||||
|
@ -1246,264 +1472,6 @@ async fn randomly_mutate_worktrees(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn randomly_query_and_mutate_buffers(
|
|
||||||
client: &TestClient,
|
|
||||||
plan: &Arc<Mutex<TestPlan>>,
|
|
||||||
cx: &mut TestAppContext,
|
|
||||||
) -> Result<()> {
|
|
||||||
let project = choose_random_project(client, &mut plan.lock().rng).unwrap();
|
|
||||||
let has_buffers_for_project = !client.buffers_for_project(&project).is_empty();
|
|
||||||
let buffer = if !has_buffers_for_project || plan.lock().rng.gen() {
|
|
||||||
let Some(worktree) = project.read_with(cx, |project, cx| {
|
|
||||||
project
|
|
||||||
.worktrees(cx)
|
|
||||||
.filter(|worktree| {
|
|
||||||
let worktree = worktree.read(cx);
|
|
||||||
worktree.is_visible() && worktree.entries(false).any(|e| e.is_file())
|
|
||||||
})
|
|
||||||
.choose(&mut plan.lock().rng)
|
|
||||||
}) else {
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
let (worktree_root_name, project_path) = worktree.read_with(cx, |worktree, _| {
|
|
||||||
let entry = worktree
|
|
||||||
.entries(false)
|
|
||||||
.filter(|e| e.is_file())
|
|
||||||
.choose(&mut plan.lock().rng)
|
|
||||||
.unwrap();
|
|
||||||
(
|
|
||||||
worktree.root_name().to_string(),
|
|
||||||
(worktree.id(), entry.path.clone()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
log::info!(
|
|
||||||
"{}: opening path {:?} in worktree {} ({})",
|
|
||||||
client.username,
|
|
||||||
project_path.1,
|
|
||||||
project_path.0,
|
|
||||||
worktree_root_name,
|
|
||||||
);
|
|
||||||
let buffer = project
|
|
||||||
.update(cx, |project, cx| {
|
|
||||||
project.open_buffer(project_path.clone(), cx)
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
log::info!(
|
|
||||||
"{}: opened path {:?} in worktree {} ({}) with buffer id {}",
|
|
||||||
client.username,
|
|
||||||
project_path.1,
|
|
||||||
project_path.0,
|
|
||||||
worktree_root_name,
|
|
||||||
buffer.read_with(cx, |buffer, _| buffer.remote_id())
|
|
||||||
);
|
|
||||||
client.buffers_for_project(&project).insert(buffer.clone());
|
|
||||||
buffer
|
|
||||||
} else {
|
|
||||||
client
|
|
||||||
.buffers_for_project(&project)
|
|
||||||
.iter()
|
|
||||||
.choose(&mut plan.lock().rng)
|
|
||||||
.unwrap()
|
|
||||||
.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let choice = plan.lock().rng.gen_range(0..100);
|
|
||||||
match choice {
|
|
||||||
0..=9 => {
|
|
||||||
cx.update(|cx| {
|
|
||||||
log::info!(
|
|
||||||
"{}: dropping buffer {:?}",
|
|
||||||
client.username,
|
|
||||||
buffer.read(cx).file().unwrap().full_path(cx)
|
|
||||||
);
|
|
||||||
client.buffers_for_project(&project).remove(&buffer);
|
|
||||||
drop(buffer);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
10..=19 => {
|
|
||||||
let completions = project.update(cx, |project, cx| {
|
|
||||||
log::info!(
|
|
||||||
"{}: requesting completions for buffer {} ({:?})",
|
|
||||||
client.username,
|
|
||||||
buffer.read(cx).remote_id(),
|
|
||||||
buffer.read(cx).file().unwrap().full_path(cx)
|
|
||||||
);
|
|
||||||
let offset = plan.lock().rng.gen_range(0..=buffer.read(cx).len());
|
|
||||||
project.completions(&buffer, offset, cx)
|
|
||||||
});
|
|
||||||
let completions = cx.background().spawn(async move {
|
|
||||||
completions
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("completions request failed: {:?}", err))
|
|
||||||
});
|
|
||||||
if plan.lock().rng.gen_bool(0.3) {
|
|
||||||
log::info!("{}: detaching completions request", client.username);
|
|
||||||
cx.update(|cx| completions.detach_and_log_err(cx));
|
|
||||||
} else {
|
|
||||||
completions.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20..=29 => {
|
|
||||||
let code_actions = project.update(cx, |project, cx| {
|
|
||||||
log::info!(
|
|
||||||
"{}: requesting code actions for buffer {} ({:?})",
|
|
||||||
client.username,
|
|
||||||
buffer.read(cx).remote_id(),
|
|
||||||
buffer.read(cx).file().unwrap().full_path(cx)
|
|
||||||
);
|
|
||||||
let range = buffer.read(cx).random_byte_range(0, &mut plan.lock().rng);
|
|
||||||
project.code_actions(&buffer, range, cx)
|
|
||||||
});
|
|
||||||
let code_actions = cx.background().spawn(async move {
|
|
||||||
code_actions
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("code actions request failed: {:?}", err))
|
|
||||||
});
|
|
||||||
if plan.lock().rng.gen_bool(0.3) {
|
|
||||||
log::info!("{}: detaching code actions request", client.username);
|
|
||||||
cx.update(|cx| code_actions.detach_and_log_err(cx));
|
|
||||||
} else {
|
|
||||||
code_actions.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
30..=39 if buffer.read_with(cx, |buffer, _| buffer.is_dirty()) => {
|
|
||||||
let (requested_version, save) = buffer.update(cx, |buffer, cx| {
|
|
||||||
log::info!(
|
|
||||||
"{}: saving buffer {} ({:?})",
|
|
||||||
client.username,
|
|
||||||
buffer.remote_id(),
|
|
||||||
buffer.file().unwrap().full_path(cx)
|
|
||||||
);
|
|
||||||
(buffer.version(), buffer.save(cx))
|
|
||||||
});
|
|
||||||
let save = cx.background().spawn(async move {
|
|
||||||
let (saved_version, _, _) = save
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("save request failed: {:?}", err))?;
|
|
||||||
assert!(saved_version.observed_all(&requested_version));
|
|
||||||
Ok::<_, anyhow::Error>(())
|
|
||||||
});
|
|
||||||
if plan.lock().rng.gen_bool(0.3) {
|
|
||||||
log::info!("{}: detaching save request", client.username);
|
|
||||||
cx.update(|cx| save.detach_and_log_err(cx));
|
|
||||||
} else {
|
|
||||||
save.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
40..=44 => {
|
|
||||||
let prepare_rename = project.update(cx, |project, cx| {
|
|
||||||
log::info!(
|
|
||||||
"{}: preparing rename for buffer {} ({:?})",
|
|
||||||
client.username,
|
|
||||||
buffer.read(cx).remote_id(),
|
|
||||||
buffer.read(cx).file().unwrap().full_path(cx)
|
|
||||||
);
|
|
||||||
let offset = plan.lock().rng.gen_range(0..=buffer.read(cx).len());
|
|
||||||
project.prepare_rename(buffer, offset, cx)
|
|
||||||
});
|
|
||||||
let prepare_rename = cx.background().spawn(async move {
|
|
||||||
prepare_rename
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("prepare rename request failed: {:?}", err))
|
|
||||||
});
|
|
||||||
if plan.lock().rng.gen_bool(0.3) {
|
|
||||||
log::info!("{}: detaching prepare rename request", client.username);
|
|
||||||
cx.update(|cx| prepare_rename.detach_and_log_err(cx));
|
|
||||||
} else {
|
|
||||||
prepare_rename.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
45..=49 => {
|
|
||||||
let definitions = project.update(cx, |project, cx| {
|
|
||||||
log::info!(
|
|
||||||
"{}: requesting definitions for buffer {} ({:?})",
|
|
||||||
client.username,
|
|
||||||
buffer.read(cx).remote_id(),
|
|
||||||
buffer.read(cx).file().unwrap().full_path(cx)
|
|
||||||
);
|
|
||||||
let offset = plan.lock().rng.gen_range(0..=buffer.read(cx).len());
|
|
||||||
project.definition(&buffer, offset, cx)
|
|
||||||
});
|
|
||||||
let definitions = cx.background().spawn(async move {
|
|
||||||
definitions
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("definitions request failed: {:?}", err))
|
|
||||||
});
|
|
||||||
if plan.lock().rng.gen_bool(0.3) {
|
|
||||||
log::info!("{}: detaching definitions request", client.username);
|
|
||||||
cx.update(|cx| definitions.detach_and_log_err(cx));
|
|
||||||
} else {
|
|
||||||
let definitions = definitions.await?;
|
|
||||||
client
|
|
||||||
.buffers_for_project(&project)
|
|
||||||
.extend(definitions.into_iter().map(|loc| loc.target.buffer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
50..=54 => {
|
|
||||||
let highlights = project.update(cx, |project, cx| {
|
|
||||||
log::info!(
|
|
||||||
"{}: requesting highlights for buffer {} ({:?})",
|
|
||||||
client.username,
|
|
||||||
buffer.read(cx).remote_id(),
|
|
||||||
buffer.read(cx).file().unwrap().full_path(cx)
|
|
||||||
);
|
|
||||||
let offset = plan.lock().rng.gen_range(0..=buffer.read(cx).len());
|
|
||||||
project.document_highlights(&buffer, offset, cx)
|
|
||||||
});
|
|
||||||
let highlights = cx.background().spawn(async move {
|
|
||||||
highlights
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("highlights request failed: {:?}", err))
|
|
||||||
});
|
|
||||||
if plan.lock().rng.gen_bool(0.3) {
|
|
||||||
log::info!("{}: detaching highlights request", client.username);
|
|
||||||
cx.update(|cx| highlights.detach_and_log_err(cx));
|
|
||||||
} else {
|
|
||||||
highlights.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
55..=59 => {
|
|
||||||
let search = project.update(cx, |project, cx| {
|
|
||||||
let query = plan.lock().rng.gen_range('a'..='z');
|
|
||||||
log::info!("{}: project-wide search {:?}", client.username, query);
|
|
||||||
project.search(SearchQuery::text(query, false, false), cx)
|
|
||||||
});
|
|
||||||
let search = cx.background().spawn(async move {
|
|
||||||
search
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("search request failed: {:?}", err))
|
|
||||||
});
|
|
||||||
if plan.lock().rng.gen_bool(0.3) {
|
|
||||||
log::info!("{}: detaching search request", client.username);
|
|
||||||
cx.update(|cx| search.detach_and_log_err(cx));
|
|
||||||
} else {
|
|
||||||
let search = search.await?;
|
|
||||||
client
|
|
||||||
.buffers_for_project(&project)
|
|
||||||
.extend(search.into_keys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
buffer.update(cx, |buffer, cx| {
|
|
||||||
log::info!(
|
|
||||||
"{}: updating buffer {} ({:?})",
|
|
||||||
client.username,
|
|
||||||
buffer.remote_id(),
|
|
||||||
buffer.file().unwrap().full_path(cx)
|
|
||||||
);
|
|
||||||
if plan.lock().rng.gen_bool(0.7) {
|
|
||||||
buffer.randomly_edit(&mut plan.lock().rng, 5, cx);
|
|
||||||
} else {
|
|
||||||
buffer.randomly_undo_redo(&mut plan.lock().rng, cx);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn choose_random_project(client: &TestClient, rng: &mut StdRng) -> Option<ModelHandle<Project>> {
|
fn choose_random_project(client: &TestClient, rng: &mut StdRng) -> Option<ModelHandle<Project>> {
|
||||||
client
|
client
|
||||||
.local_projects()
|
.local_projects()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue