use {
super::*,
crate::session::SessionState,
reovim_driver_command::Command,
reovim_kernel::api::v1::{CommandId, ModuleId},
};
fn make_session_with_name_index() -> Arc<Session> {
struct WriteCmd;
#[cfg_attr(coverage_nightly, coverage(off))]
impl Command for WriteCmd {
fn id(&self) -> CommandId {
CommandId::new(ModuleId::new("commands"), "write")
}
fn description(&self) -> &'static str {
"Write buffer"
}
fn names(&self) -> &[&'static str] {
&["w", "write"]
}
}
struct QuitCmd;
#[cfg_attr(coverage_nightly, coverage(off))]
impl Command for QuitCmd {
fn id(&self) -> CommandId {
CommandId::new(ModuleId::new("commands"), "quit")
}
fn description(&self) -> &'static str {
"Quit editor"
}
fn names(&self) -> &[&'static str] {
&["q", "quit"]
}
}
let mut index = CommandNameIndex::new();
let write: Arc<dyn Command> = Arc::new(WriteCmd);
let quit: Arc<dyn Command> = Arc::new(QuitCmd);
index.insert("w".to_string(), write.id(), Arc::clone(&write));
index.insert("write".to_string(), write.id(), write);
index.insert("q".to_string(), quit.id(), Arc::clone(&quit));
index.insert("quit".to_string(), quit.id(), quit);
let state = SessionState::default();
state.app.kernel.services.register(Arc::new(index));
Arc::new(Session::from_state(SessionId::new("test"), state))
}
fn make_sessions_with(session: &Arc<Session>) -> Arc<SessionRegistry> {
let sessions = Arc::new(SessionRegistry::new());
sessions.insert(session);
sessions
}
#[test]
fn test_command_service_impl_new() {
let sessions = Arc::new(SessionRegistry::new());
let session_id = SessionId::new("test");
let service = CommandServiceImpl::new(sessions, session_id);
assert!(service.get_session().is_err());
}
#[test]
fn test_command_service_impl_no_session() {
let sessions = Arc::new(SessionRegistry::new());
let session_id = SessionId::new("nonexistent");
let service = CommandServiceImpl::new(sessions, session_id);
let result = service.get_session();
assert!(result.is_err());
assert_eq!(result.err().unwrap().code(), tonic::Code::NotFound);
}
#[tokio::test]
async fn test_search_commands_user_only() {
let session = make_session_with_name_index();
let sessions = make_sessions_with(&session);
let service = CommandServiceImpl::new(sessions, SessionId::new("test"));
let request = Request::new(SearchCommandsRequest {
prefix: "w".to_string(),
source: CommandSource::User.into(),
});
let response = service.search_commands(request).await.unwrap().into_inner();
assert_eq!(response.user_commands.len(), 1);
assert_eq!(response.user_commands[0].id, "write");
assert!(response.keybinding_commands.is_empty());
}
#[tokio::test]
async fn test_search_commands_keybinding_only() {
let session = make_session_with_name_index();
let sessions = make_sessions_with(&session);
let service = CommandServiceImpl::new(sessions, SessionId::new("test"));
let request = Request::new(SearchCommandsRequest {
prefix: "w".to_string(),
source: CommandSource::Keybinding.into(),
});
let response = service.search_commands(request).await.unwrap().into_inner();
assert!(response.user_commands.is_empty());
assert!(response.keybinding_commands.is_empty());
}
#[tokio::test]
async fn test_search_commands_all() {
let session = make_session_with_name_index();
let sessions = make_sessions_with(&session);
let service = CommandServiceImpl::new(sessions, SessionId::new("test"));
let request = Request::new(SearchCommandsRequest {
prefix: String::new(),
source: CommandSource::All.into(),
});
let response = service.search_commands(request).await.unwrap().into_inner();
assert_eq!(response.user_commands.len(), 2);
}
#[tokio::test]
async fn test_search_commands_no_session() {
let sessions = Arc::new(SessionRegistry::new());
let service = CommandServiceImpl::new(sessions, SessionId::new("test"));
let request = Request::new(SearchCommandsRequest {
prefix: "w".to_string(),
source: CommandSource::All.into(),
});
let result = service.search_commands(request).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound);
}
#[tokio::test]
async fn test_search_commands_keybinding_with_snapshot() {
use {
crate::CommandQuerySnapshot,
reovim_driver_command::{ArgSpec, CommandHandler, CommandResult},
reovim_driver_session::SessionRuntime,
};
struct MoveDown;
#[cfg_attr(coverage_nightly, coverage(off))]
impl Command for MoveDown {
fn id(&self) -> CommandId {
CommandId::new(ModuleId::new("test"), "move-down")
}
fn description(&self) -> &'static str {
"Move cursor down"
}
fn args(&self) -> Vec<ArgSpec> {
vec![]
}
fn names(&self) -> &[&'static str] {
&["move-down"]
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl CommandHandler for MoveDown {
fn execute(
&self,
_runtime: &mut SessionRuntime<'_>,
_args: &reovim_driver_command::CommandContext,
) -> CommandResult {
CommandResult::Success
}
}
let mut cmd_registry = crate::CommandRegistry::new();
cmd_registry.register(Arc::new(MoveDown));
let snapshot = CommandQuerySnapshot::from_registry(&cmd_registry);
let state = SessionState::default();
state.app.kernel.services.register(Arc::new(snapshot));
let session = Arc::new(Session::from_state(SessionId::new("test"), state));
let sessions = make_sessions_with(&session);
let service = CommandServiceImpl::new(sessions, SessionId::new("test"));
let request = Request::new(SearchCommandsRequest {
prefix: "move".to_string(),
source: CommandSource::Keybinding.into(),
});
let response = service.search_commands(request).await.unwrap().into_inner();
assert_eq!(response.keybinding_commands.len(), 1);
assert_eq!(response.keybinding_commands[0].id, "test:move-down");
assert_eq!(response.keybinding_commands[0].names, vec!["move-down"]);
assert_eq!(response.keybinding_commands[0].description, "Move cursor down");
}
#[tokio::test]
async fn test_complete_args_found() {
struct ColorschemeCmd;
#[cfg_attr(coverage_nightly, coverage(off))]
impl Command for ColorschemeCmd {
fn id(&self) -> CommandId {
CommandId::new(ModuleId::new("commands"), "colorscheme")
}
fn description(&self) -> &'static str {
"Set colorscheme"
}
fn names(&self) -> &[&'static str] {
&["colorscheme"]
}
fn complete(&self, partial: &str) -> Vec<String> {
vec![format!("{partial}-dark"), format!("{partial}-light")]
}
}
let mut index = CommandNameIndex::new();
let cmd: Arc<dyn Command> = Arc::new(ColorschemeCmd);
index.insert("colorscheme".to_string(), cmd.id(), cmd);
let state = SessionState::default();
state.app.kernel.services.register(Arc::new(index));
let session = Arc::new(Session::from_state(SessionId::new("test"), state));
let sessions = make_sessions_with(&session);
let service = CommandServiceImpl::new(sessions, SessionId::new("test"));
let request = Request::new(CompleteArgsRequest {
command: "colorscheme".to_string(),
partial: "gru".to_string(),
});
let response = service.complete_args(request).await.unwrap().into_inner();
assert_eq!(response.completions.len(), 2);
assert_eq!(response.completions[0], "gru-dark");
assert_eq!(response.completions[1], "gru-light");
}
#[tokio::test]
async fn test_complete_args_not_found() {
let session = make_session_with_name_index();
let sessions = make_sessions_with(&session);
let service = CommandServiceImpl::new(sessions, SessionId::new("test"));
let request = Request::new(CompleteArgsRequest {
command: "nonexistent".to_string(),
partial: String::new(),
});
let response = service.complete_args(request).await.unwrap().into_inner();
assert!(response.completions.is_empty());
}
#[tokio::test]
async fn test_complete_args_no_session() {
let sessions = Arc::new(SessionRegistry::new());
let service = CommandServiceImpl::new(sessions, SessionId::new("test"));
let request = Request::new(CompleteArgsRequest {
command: "w".to_string(),
partial: String::new(),
});
let result = service.complete_args(request).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound);
}