Another batch of tests

This commit is contained in:
Piotr Osiewicz 2023-12-01 18:43:44 +01:00
parent 4c4ec221af
commit 53f3f960d2
3 changed files with 1064 additions and 1072 deletions

View file

@ -2401,346 +2401,346 @@ pub mod tests {
});
}
#[gpui::test(iterations = 10)]
async fn test_multiple_excerpts_large_multibuffer(cx: &mut gpui::TestAppContext) {
init_test(cx, |settings| {
settings.defaults.inlay_hints = Some(InlayHintSettings {
enabled: true,
show_type_hints: true,
show_parameter_hints: true,
show_other_hints: true,
})
});
// #[gpui::test(iterations = 10)]
// async fn test_multiple_excerpts_large_multibuffer(cx: &mut gpui::TestAppContext) {
// init_test(cx, |settings| {
// settings.defaults.inlay_hints = Some(InlayHintSettings {
// enabled: true,
// show_type_hints: true,
// show_parameter_hints: true,
// show_other_hints: true,
// })
// });
let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
..Default::default()
},
Some(tree_sitter_rust::language()),
);
let mut fake_servers = language
.set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
capabilities: lsp::ServerCapabilities {
inlay_hint_provider: Some(lsp::OneOf::Left(true)),
..Default::default()
},
..Default::default()
}))
.await;
let language = Arc::new(language);
let fs = FakeFs::new(cx.background_executor.clone());
fs.insert_tree(
"/a",
json!({
"main.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|i| format!("let i = {i};\n")).collect::<Vec<_>>().join("")),
"other.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|j| format!("let j = {j};\n")).collect::<Vec<_>>().join("")),
}),
)
.await;
let project = Project::test(fs, ["/a".as_ref()], cx).await;
project.update(cx, |project, _| {
project.languages().add(Arc::clone(&language))
});
let worktree_id = project.update(cx, |project, cx| {
project.worktrees().next().unwrap().read(cx).id()
});
// let mut language = Language::new(
// LanguageConfig {
// name: "Rust".into(),
// path_suffixes: vec!["rs".to_string()],
// ..Default::default()
// },
// Some(tree_sitter_rust::language()),
// );
// let mut fake_servers = language
// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
// capabilities: lsp::ServerCapabilities {
// inlay_hint_provider: Some(lsp::OneOf::Left(true)),
// ..Default::default()
// },
// ..Default::default()
// }))
// .await;
// let language = Arc::new(language);
// let fs = FakeFs::new(cx.background_executor.clone());
// fs.insert_tree(
// "/a",
// json!({
// "main.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|i| format!("let i = {i};\n")).collect::<Vec<_>>().join("")),
// "other.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|j| format!("let j = {j};\n")).collect::<Vec<_>>().join("")),
// }),
// )
// .await;
// let project = Project::test(fs, ["/a".as_ref()], cx).await;
// project.update(cx, |project, _| {
// project.languages().add(Arc::clone(&language))
// });
// let worktree_id = project.update(cx, |project, cx| {
// project.worktrees().next().unwrap().read(cx).id()
// });
let buffer_1 = project
.update(cx, |project, cx| {
project.open_buffer((worktree_id, "main.rs"), cx)
})
.await
.unwrap();
let buffer_2 = project
.update(cx, |project, cx| {
project.open_buffer((worktree_id, "other.rs"), cx)
})
.await
.unwrap();
let multibuffer = cx.build_model(|cx| {
let mut multibuffer = MultiBuffer::new(0);
multibuffer.push_excerpts(
buffer_1.clone(),
[
ExcerptRange {
context: Point::new(0, 0)..Point::new(2, 0),
primary: None,
},
ExcerptRange {
context: Point::new(4, 0)..Point::new(11, 0),
primary: None,
},
ExcerptRange {
context: Point::new(22, 0)..Point::new(33, 0),
primary: None,
},
ExcerptRange {
context: Point::new(44, 0)..Point::new(55, 0),
primary: None,
},
ExcerptRange {
context: Point::new(56, 0)..Point::new(66, 0),
primary: None,
},
ExcerptRange {
context: Point::new(67, 0)..Point::new(77, 0),
primary: None,
},
],
cx,
);
multibuffer.push_excerpts(
buffer_2.clone(),
[
ExcerptRange {
context: Point::new(0, 1)..Point::new(2, 1),
primary: None,
},
ExcerptRange {
context: Point::new(4, 1)..Point::new(11, 1),
primary: None,
},
ExcerptRange {
context: Point::new(22, 1)..Point::new(33, 1),
primary: None,
},
ExcerptRange {
context: Point::new(44, 1)..Point::new(55, 1),
primary: None,
},
ExcerptRange {
context: Point::new(56, 1)..Point::new(66, 1),
primary: None,
},
ExcerptRange {
context: Point::new(67, 1)..Point::new(77, 1),
primary: None,
},
],
cx,
);
multibuffer
});
// let buffer_1 = project
// .update(cx, |project, cx| {
// project.open_buffer((worktree_id, "main.rs"), cx)
// })
// .await
// .unwrap();
// let buffer_2 = project
// .update(cx, |project, cx| {
// project.open_buffer((worktree_id, "other.rs"), cx)
// })
// .await
// .unwrap();
// let multibuffer = cx.build_model(|cx| {
// let mut multibuffer = MultiBuffer::new(0);
// multibuffer.push_excerpts(
// buffer_1.clone(),
// [
// ExcerptRange {
// context: Point::new(0, 0)..Point::new(2, 0),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(4, 0)..Point::new(11, 0),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(22, 0)..Point::new(33, 0),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(44, 0)..Point::new(55, 0),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(56, 0)..Point::new(66, 0),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(67, 0)..Point::new(77, 0),
// primary: None,
// },
// ],
// cx,
// );
// multibuffer.push_excerpts(
// buffer_2.clone(),
// [
// ExcerptRange {
// context: Point::new(0, 1)..Point::new(2, 1),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(4, 1)..Point::new(11, 1),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(22, 1)..Point::new(33, 1),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(44, 1)..Point::new(55, 1),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(56, 1)..Point::new(66, 1),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(67, 1)..Point::new(77, 1),
// primary: None,
// },
// ],
// cx,
// );
// multibuffer
// });
cx.executor().run_until_parked();
let editor =
cx.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx));
let editor_edited = Arc::new(AtomicBool::new(false));
let fake_server = fake_servers.next().await.unwrap();
let closure_editor_edited = Arc::clone(&editor_edited);
fake_server
.handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
let task_editor_edited = Arc::clone(&closure_editor_edited);
async move {
let hint_text = if params.text_document.uri
== lsp::Url::from_file_path("/a/main.rs").unwrap()
{
"main hint"
} else if params.text_document.uri
== lsp::Url::from_file_path("/a/other.rs").unwrap()
{
"other hint"
} else {
panic!("unexpected uri: {:?}", params.text_document.uri);
};
// cx.executor().run_until_parked();
// let editor =
// cx.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx));
// let editor_edited = Arc::new(AtomicBool::new(false));
// let fake_server = fake_servers.next().await.unwrap();
// let closure_editor_edited = Arc::clone(&editor_edited);
// fake_server
// .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
// let task_editor_edited = Arc::clone(&closure_editor_edited);
// async move {
// let hint_text = if params.text_document.uri
// == lsp::Url::from_file_path("/a/main.rs").unwrap()
// {
// "main hint"
// } else if params.text_document.uri
// == lsp::Url::from_file_path("/a/other.rs").unwrap()
// {
// "other hint"
// } else {
// panic!("unexpected uri: {:?}", params.text_document.uri);
// };
// one hint per excerpt
let positions = [
lsp::Position::new(0, 2),
lsp::Position::new(4, 2),
lsp::Position::new(22, 2),
lsp::Position::new(44, 2),
lsp::Position::new(56, 2),
lsp::Position::new(67, 2),
];
let out_of_range_hint = lsp::InlayHint {
position: lsp::Position::new(
params.range.start.line + 99,
params.range.start.character + 99,
),
label: lsp::InlayHintLabel::String(
"out of excerpt range, should be ignored".to_string(),
),
kind: None,
text_edits: None,
tooltip: None,
padding_left: None,
padding_right: None,
data: None,
};
// // one hint per excerpt
// let positions = [
// lsp::Position::new(0, 2),
// lsp::Position::new(4, 2),
// lsp::Position::new(22, 2),
// lsp::Position::new(44, 2),
// lsp::Position::new(56, 2),
// lsp::Position::new(67, 2),
// ];
// let out_of_range_hint = lsp::InlayHint {
// position: lsp::Position::new(
// params.range.start.line + 99,
// params.range.start.character + 99,
// ),
// label: lsp::InlayHintLabel::String(
// "out of excerpt range, should be ignored".to_string(),
// ),
// kind: None,
// text_edits: None,
// tooltip: None,
// padding_left: None,
// padding_right: None,
// data: None,
// };
let edited = task_editor_edited.load(Ordering::Acquire);
Ok(Some(
std::iter::once(out_of_range_hint)
.chain(positions.into_iter().enumerate().map(|(i, position)| {
lsp::InlayHint {
position,
label: lsp::InlayHintLabel::String(format!(
"{hint_text}{} #{i}",
if edited { "(edited)" } else { "" },
)),
kind: None,
text_edits: None,
tooltip: None,
padding_left: None,
padding_right: None,
data: None,
}
}))
.collect(),
))
}
})
.next()
.await;
cx.executor().run_until_parked();
// let edited = task_editor_edited.load(Ordering::Acquire);
// Ok(Some(
// std::iter::once(out_of_range_hint)
// .chain(positions.into_iter().enumerate().map(|(i, position)| {
// lsp::InlayHint {
// position,
// label: lsp::InlayHintLabel::String(format!(
// "{hint_text}{} #{i}",
// if edited { "(edited)" } else { "" },
// )),
// kind: None,
// text_edits: None,
// tooltip: None,
// padding_left: None,
// padding_right: None,
// data: None,
// }
// }))
// .collect(),
// ))
// }
// })
// .next()
// .await;
// cx.executor().run_until_parked();
editor.update(cx, |editor, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
"main hint #2".to_string(),
"main hint #3".to_string(),
// todo!() there used to be no these hints, but new gpui2 presumably scrolls a bit farther
// (or renders less?) note that tests below pass
"main hint #4".to_string(),
"main hint #5".to_string(),
];
assert_eq!(
expected_hints,
cached_hint_labels(editor),
"When scroll is at the edge of a multibuffer, its visible excerpts only should be queried for inlay hints"
);
assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(), "Every visible excerpt hints should bump the verison");
});
// editor.update(cx, |editor, cx| {
// let expected_hints = vec![
// "main hint #0".to_string(),
// "main hint #1".to_string(),
// "main hint #2".to_string(),
// "main hint #3".to_string(),
// // todo!() there used to be no these hints, but new gpui2 presumably scrolls a bit farther
// // (or renders less?) note that tests below pass
// "main hint #4".to_string(),
// "main hint #5".to_string(),
// ];
// assert_eq!(
// expected_hints,
// cached_hint_labels(editor),
// "When scroll is at the edge of a multibuffer, its visible excerpts only should be queried for inlay hints"
// );
// assert_eq!(expected_hints, visible_hint_labels(editor, cx));
// assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(), "Every visible excerpt hints should bump the verison");
// });
editor.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
});
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
s.select_ranges([Point::new(22, 0)..Point::new(22, 0)])
});
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
s.select_ranges([Point::new(50, 0)..Point::new(50, 0)])
});
});
cx.executor().run_until_parked();
editor.update(cx, |editor, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
"main hint #2".to_string(),
"main hint #3".to_string(),
"main hint #4".to_string(),
"main hint #5".to_string(),
"other hint #0".to_string(),
"other hint #1".to_string(),
"other hint #2".to_string(),
];
assert_eq!(expected_hints, cached_hint_labels(editor),
"With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits");
assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(),
"Due to every excerpt having one hint, we update cache per new excerpt scrolled");
});
// editor.update(cx, |editor, cx| {
// editor.change_selections(Some(Autoscroll::Next), cx, |s| {
// s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
// });
// editor.change_selections(Some(Autoscroll::Next), cx, |s| {
// s.select_ranges([Point::new(22, 0)..Point::new(22, 0)])
// });
// editor.change_selections(Some(Autoscroll::Next), cx, |s| {
// s.select_ranges([Point::new(50, 0)..Point::new(50, 0)])
// });
// });
// cx.executor().run_until_parked();
// editor.update(cx, |editor, cx| {
// let expected_hints = vec![
// "main hint #0".to_string(),
// "main hint #1".to_string(),
// "main hint #2".to_string(),
// "main hint #3".to_string(),
// "main hint #4".to_string(),
// "main hint #5".to_string(),
// "other hint #0".to_string(),
// "other hint #1".to_string(),
// "other hint #2".to_string(),
// ];
// assert_eq!(expected_hints, cached_hint_labels(editor),
// "With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits");
// assert_eq!(expected_hints, visible_hint_labels(editor, cx));
// assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(),
// "Due to every excerpt having one hint, we update cache per new excerpt scrolled");
// });
editor.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
s.select_ranges([Point::new(100, 0)..Point::new(100, 0)])
});
});
cx.executor().advance_clock(Duration::from_millis(
INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
));
cx.executor().run_until_parked();
let last_scroll_update_version = editor.update(cx, |editor, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
"main hint #2".to_string(),
"main hint #3".to_string(),
"main hint #4".to_string(),
"main hint #5".to_string(),
"other hint #0".to_string(),
"other hint #1".to_string(),
"other hint #2".to_string(),
"other hint #3".to_string(),
"other hint #4".to_string(),
"other hint #5".to_string(),
];
assert_eq!(expected_hints, cached_hint_labels(editor),
"After multibuffer was scrolled to the end, all hints for all excerpts should be fetched");
assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, expected_hints.len());
expected_hints.len()
}).unwrap();
// editor.update(cx, |editor, cx| {
// editor.change_selections(Some(Autoscroll::Next), cx, |s| {
// s.select_ranges([Point::new(100, 0)..Point::new(100, 0)])
// });
// });
// cx.executor().advance_clock(Duration::from_millis(
// INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
// ));
// cx.executor().run_until_parked();
// let last_scroll_update_version = editor.update(cx, |editor, cx| {
// let expected_hints = vec![
// "main hint #0".to_string(),
// "main hint #1".to_string(),
// "main hint #2".to_string(),
// "main hint #3".to_string(),
// "main hint #4".to_string(),
// "main hint #5".to_string(),
// "other hint #0".to_string(),
// "other hint #1".to_string(),
// "other hint #2".to_string(),
// "other hint #3".to_string(),
// "other hint #4".to_string(),
// "other hint #5".to_string(),
// ];
// assert_eq!(expected_hints, cached_hint_labels(editor),
// "After multibuffer was scrolled to the end, all hints for all excerpts should be fetched");
// assert_eq!(expected_hints, visible_hint_labels(editor, cx));
// assert_eq!(editor.inlay_hint_cache().version, expected_hints.len());
// expected_hints.len()
// }).unwrap();
editor.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
});
});
cx.executor().run_until_parked();
editor.update(cx, |editor, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
"main hint #2".to_string(),
"main hint #3".to_string(),
"main hint #4".to_string(),
"main hint #5".to_string(),
"other hint #0".to_string(),
"other hint #1".to_string(),
"other hint #2".to_string(),
"other hint #3".to_string(),
"other hint #4".to_string(),
"other hint #5".to_string(),
];
assert_eq!(expected_hints, cached_hint_labels(editor),
"After multibuffer was scrolled to the end, further scrolls up should not bring more hints");
assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, last_scroll_update_version, "No updates should happen during scrolling already scolled buffer");
});
// editor.update(cx, |editor, cx| {
// editor.change_selections(Some(Autoscroll::Next), cx, |s| {
// s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
// });
// });
// cx.executor().run_until_parked();
// editor.update(cx, |editor, cx| {
// let expected_hints = vec![
// "main hint #0".to_string(),
// "main hint #1".to_string(),
// "main hint #2".to_string(),
// "main hint #3".to_string(),
// "main hint #4".to_string(),
// "main hint #5".to_string(),
// "other hint #0".to_string(),
// "other hint #1".to_string(),
// "other hint #2".to_string(),
// "other hint #3".to_string(),
// "other hint #4".to_string(),
// "other hint #5".to_string(),
// ];
// assert_eq!(expected_hints, cached_hint_labels(editor),
// "After multibuffer was scrolled to the end, further scrolls up should not bring more hints");
// assert_eq!(expected_hints, visible_hint_labels(editor, cx));
// assert_eq!(editor.inlay_hint_cache().version, last_scroll_update_version, "No updates should happen during scrolling already scolled buffer");
// });
editor_edited.store(true, Ordering::Release);
editor.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| {
s.select_ranges([Point::new(56, 0)..Point::new(56, 0)])
});
editor.handle_input("++++more text++++", cx);
});
cx.executor().run_until_parked();
editor.update(cx, |editor, cx| {
let expected_hints = vec![
"main hint(edited) #0".to_string(),
"main hint(edited) #1".to_string(),
"main hint(edited) #2".to_string(),
"main hint(edited) #3".to_string(),
"main hint(edited) #4".to_string(),
"main hint(edited) #5".to_string(),
"other hint(edited) #0".to_string(),
"other hint(edited) #1".to_string(),
];
assert_eq!(
expected_hints,
cached_hint_labels(editor),
"After multibuffer edit, editor gets scolled back to the last selection; \
all hints should be invalidated and requeried for all of its visible excerpts"
);
assert_eq!(expected_hints, visible_hint_labels(editor, cx));
// editor_edited.store(true, Ordering::Release);
// editor.update(cx, |editor, cx| {
// editor.change_selections(None, cx, |s| {
// s.select_ranges([Point::new(56, 0)..Point::new(56, 0)])
// });
// editor.handle_input("++++more text++++", cx);
// });
// cx.executor().run_until_parked();
// editor.update(cx, |editor, cx| {
// let expected_hints = vec![
// "main hint(edited) #0".to_string(),
// "main hint(edited) #1".to_string(),
// "main hint(edited) #2".to_string(),
// "main hint(edited) #3".to_string(),
// "main hint(edited) #4".to_string(),
// "main hint(edited) #5".to_string(),
// "other hint(edited) #0".to_string(),
// "other hint(edited) #1".to_string(),
// ];
// assert_eq!(
// expected_hints,
// cached_hint_labels(editor),
// "After multibuffer edit, editor gets scolled back to the last selection; \
// all hints should be invalidated and requeried for all of its visible excerpts"
// );
// assert_eq!(expected_hints, visible_hint_labels(editor, cx));
let current_cache_version = editor.inlay_hint_cache().version;
let minimum_expected_version = last_scroll_update_version + expected_hints.len();
assert!(
current_cache_version == minimum_expected_version || current_cache_version == minimum_expected_version + 1,
"Due to every excerpt having one hint, cache should update per new excerpt received + 1 potential sporadic update"
);
});
}
// let current_cache_version = editor.inlay_hint_cache().version;
// let minimum_expected_version = last_scroll_update_version + expected_hints.len();
// assert!(
// current_cache_version == minimum_expected_version || current_cache_version == minimum_expected_version + 1,
// "Due to every excerpt having one hint, cache should update per new excerpt received + 1 potential sporadic update"
// );
// });
// }
#[gpui::test]
async fn test_excerpts_removed(cx: &mut gpui::TestAppContext) {