use rig_harness::prelude::*;
use super::super::view::TuiView;
use crate::tests::{press, scratch, type_text, typed as typed_text, view_app};
use crate::{CompletionKind, CompletionSource, InputContext};
fn open(app: &App) -> bool {
app.world().resource::<TuiView>().completion.is_some()
}
#[test]
fn a_completed_argument_does_not_open_the_list_for_the_next_word() {
let (mut app, _) = view_app();
app.add_command("model", "Choose the model", |_: In<CommandArgs>| {});
app.add_command("pair", "Two arguments", |_: In<CommandArgs>| {});
app.world_mut()
.spawn(CompletionSource::arg("model").candidate("acme/fast", ""));
app.world_mut()
.spawn(CompletionSource::arg("pair").at(1).candidate("second", ""));
type_text(&mut app, "/model acme");
assert!(open(&app));
press(&mut app, "tab");
assert_eq!(typed_text(&app), "/model acme/fast ");
assert!(!open(&app));
type_text(&mut app, " ");
assert!(!open(&app));
press(&mut app, "ctrl+c");
type_text(&mut app, "/pair ");
assert!(!open(&app));
type_text(&mut app, "first ");
assert!(open(&app));
}
#[test]
fn a_marker_source_completes_a_word_anywhere_and_follows_its_lookup() {
let (mut app, _) = view_app();
let issues = app.world_mut().spawn(CompletionSource::marker('#')).id();
type_text(&mut app, "fixes #14");
assert!(!open(&app));
let typed = app.world().resource::<InputContext>().typed();
assert_eq!(typed, Some((CompletionKind::Marker('#'), "14")));
let found = CompletionSource::marker('#')
.candidate("142", "Crash on empty input")
.candidate("7", "Unrelated");
app.world_mut().entity_mut(issues).insert(found);
app.update();
assert!(open(&app));
press(&mut app, "tab");
assert_eq!(typed_text(&app), "fixes #142 ");
app.world_mut()
.spawn(CompletionSource::marker('@').candidate("nobody", ""));
press(&mut app, "ctrl+c");
type_text(&mut app, "/mod");
let typed = app.world().resource::<InputContext>().typed();
assert_eq!(typed, Some((CompletionKind::Command, "mod")));
}
#[test]
fn at_completes_the_paths_of_the_project_root() {
let root = scratch("complete-root");
std::fs::create_dir_all(root.join("src")).ok();
std::fs::write(root.join("src").join("only_in_root.rs"), "").ok();
let (mut app, _) = view_app();
app.insert_resource(ProjectRoot(root.clone()));
type_text(&mut app, "@only_in");
let started = std::time::Instant::now();
let items = |app: &App| {
let completion = app.world().resource::<TuiView>().completion.as_ref();
let items = completion.into_iter().flat_map(|open| &open.items);
items.map(|item| item.text.clone()).collect::<Vec<_>>()
};
while items(&app).is_empty() && started.elapsed() < std::time::Duration::from_secs(10) {
app.update();
std::thread::sleep(std::time::Duration::from_millis(5));
}
assert_eq!(items(&app), ["src/only_in_root.rs"]);
std::fs::remove_dir_all(&root).ok();
}
#[test]
fn a_file_made_while_at_is_typed_is_listed_without_waiting() {
use super::FileIndex;
use std::time::{Duration, Instant};
let root = scratch("complete-watch");
std::fs::create_dir_all(root.join("src")).ok();
std::fs::write(root.join("src").join("a.rs"), "").ok();
let (mut app, _) = view_app();
app.add_plugins(rig_harness::watch::WatchPlugin)
.insert_resource(ProjectRoot(root.clone()));
let items = |app: &App| {
let completion = app.world().resource::<TuiView>().completion.as_ref();
let items = completion.into_iter().flat_map(|open| &open.items);
items.map(|item| item.text.clone()).collect::<Vec<_>>()
};
let run_until = |app: &mut App, done: &dyn Fn(&App) -> bool| {
let started = Instant::now();
while !done(app) && started.elapsed() < Duration::from_secs(10) {
app.update();
std::thread::sleep(Duration::from_millis(5));
}
};
type_text(&mut app, "@b_new");
let walked = |app: &App| {
let index = app.world().resource::<FileIndex>();
index.paths.iter().any(|path| path == "src/a.rs")
};
run_until(&mut app, &walked);
let settle = Instant::now();
run_until(&mut app, &|_| settle.elapsed() > Duration::from_millis(300));
assert!(items(&app).is_empty());
std::fs::write(root.join("src").join("b_new.rs"), "").ok();
run_until(&mut app, &|app| !items(app).is_empty());
assert_eq!(items(&app), ["src/b_new.rs"]);
std::fs::remove_dir_all(&root).ok();
}