use serde::de::{self, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use crate::{ControlModeResponse, HandshakeResponse, LayoutName, RmuxError, SdkWaitId};
#[path = "response/session.rs"]
mod session;
pub use session::{
CreateSessionLeaseResponse, HasSessionResponse, KillSessionResponse, ListSessionsResponse,
NewSessionResponse, ReleaseSessionLeaseResponse, RenameSessionResponse,
RenewSessionLeaseResponse,
};
#[path = "response/server.rs"]
mod server;
pub use server::{
DaemonStatusResponse, KillServerResponse, LockClientResponse, LockServerResponse,
LockSessionResponse, ServerAccessResponse, ShutdownIfIdleResponse,
};
#[path = "response/target.rs"]
mod target;
pub use target::ResolveTargetResponse;
#[path = "response/window.rs"]
mod window;
pub use window::{
KillWindowResponse, LastWindowResponse, LinkWindowResponse, ListWindowsResponse,
MoveWindowResponse, NewWindowResponse, NextWindowResponse, PreviousWindowResponse,
RenameWindowResponse, ResizeWindowResponse, RespawnWindowResponse, RotateWindowResponse,
SelectWindowResponse, SwapWindowResponse, UnlinkWindowResponse, WindowListEntry,
};
#[path = "response/pane.rs"]
mod pane;
pub use pane::{
BreakPaneResponse, DisplayPanesResponse, JoinPaneResponse, KillPaneResponse, LastPaneResponse,
ListPanesResponse, MovePaneResponse, PaneBroadcastInputFailure, PaneBroadcastInputResponse,
PaneBroadcastInputSuccess, PaneOutputCursor, PaneOutputCursorResponse, PaneOutputEvent,
PaneOutputLagNotice, PaneOutputLagResponse, PaneRecentOutput, PaneSnapshotCell,
PaneSnapshotCursor, PaneSnapshotResponse, PipePaneResponse, ResizePaneResponse,
RespawnPaneResponse, SelectPaneResponse, SendKeysResponse, SplitWindowResponse,
SubscribePaneOutputResponse, SwapPaneResponse, UnsubscribePaneOutputResponse,
};
#[path = "response/client.rs"]
mod client;
pub use client::{
AttachSessionResponse, DetachClientResponse, ListClientsResponse, RefreshClientResponse,
SuspendClientResponse, SwitchClientResponse,
};
#[path = "response/keys.rs"]
mod keys;
pub use keys::{
BindKeyResponse, ClockModeResponse, CopyModeResponse, ListKeysResponse, SendPrefixResponse,
UnbindKeyResponse,
};
#[path = "response/options.rs"]
mod options;
pub use options::{
SetEnvironmentResponse, SetHookResponse, SetOptionByNameResponse, SetOptionResponse,
ShowEnvironmentResponse, ShowHooksResponse, ShowOptionsResponse,
};
#[path = "response/web.rs"]
mod web;
pub use web::{
WebShareConfigResponse, WebShareCreatedResponse, WebShareListResponse, WebShareListener,
WebShareLookupResponse, WebShareResponse, WebShareStoppedAllResponse, WebShareStoppedResponse,
WebShareSummary,
};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Response {
NewSession(NewSessionResponse),
HasSession(HasSessionResponse),
KillSession(KillSessionResponse),
NewWindow(NewWindowResponse),
KillWindow(KillWindowResponse),
SelectWindow(SelectWindowResponse),
RenameWindow(RenameWindowResponse),
NextWindow(NextWindowResponse),
PreviousWindow(PreviousWindowResponse),
LastWindow(LastWindowResponse),
ListWindows(ListWindowsResponse),
MoveWindow(MoveWindowResponse),
SwapWindow(SwapWindowResponse),
RotateWindow(RotateWindowResponse),
SplitWindow(SplitWindowResponse),
SwapPane(SwapPaneResponse),
LastPane(LastPaneResponse),
JoinPane(JoinPaneResponse),
BreakPane(BreakPaneResponse),
KillPane(KillPaneResponse),
SelectLayout(SelectLayoutResponse),
ResizePane(ResizePaneResponse),
DisplayPanes(DisplayPanesResponse),
SelectPane(SelectPaneResponse),
SendKeys(SendKeysResponse),
AttachSession(AttachSessionResponse),
SwitchClient(SwitchClientResponse),
DetachClient(DetachClientResponse),
SetOption(SetOptionResponse),
SetEnvironment(SetEnvironmentResponse),
SetHook(SetHookResponse),
Error(ErrorResponse),
NextLayout(NextLayoutResponse),
PreviousLayout(PreviousLayoutResponse),
ShowOptions(ShowOptionsResponse),
ShowEnvironment(ShowEnvironmentResponse),
SetBuffer(SetBufferResponse),
ShowBuffer(ShowBufferResponse),
PasteBuffer(PasteBufferResponse),
ListBuffers(ListBuffersResponse),
DeleteBuffer(DeleteBufferResponse),
LoadBuffer(LoadBufferResponse),
SaveBuffer(SaveBufferResponse),
CapturePane(CapturePaneResponse),
DisplayMessage(DisplayMessageResponse),
RunShell(RunShellResponse),
IfShell(IfShellResponse),
WaitFor(WaitForResponse),
RenameSession(RenameSessionResponse),
ListSessions(ListSessionsResponse),
ListPanes(ListPanesResponse),
SourceFile(SourceFileResponse),
SetOptionByName(SetOptionByNameResponse),
ShowHooks(ShowHooksResponse),
BindKey(BindKeyResponse),
UnbindKey(UnbindKeyResponse),
ListKeys(ListKeysResponse),
SendPrefix(SendPrefixResponse),
ClearHistory(ClearHistoryResponse),
CopyMode(CopyModeResponse),
ControlMode(ControlModeResponse),
ClockMode(ClockModeResponse),
ShowMessages(ShowMessagesResponse),
KillServer(KillServerResponse),
LockServer(LockServerResponse),
LockSession(LockSessionResponse),
LockClient(LockClientResponse),
ServerAccess(ServerAccessResponse),
RefreshClient(RefreshClientResponse),
ListClients(ListClientsResponse),
SuspendClient(SuspendClientResponse),
ResizeWindow(ResizeWindowResponse),
RespawnWindow(RespawnWindowResponse),
MovePane(MovePaneResponse),
PipePane(PipePaneResponse),
RespawnPane(RespawnPaneResponse),
LinkWindow(LinkWindowResponse),
UnlinkWindow(UnlinkWindowResponse),
ResolveTarget(ResolveTargetResponse),
Handshake(HandshakeResponse),
PaneSnapshot(PaneSnapshotResponse),
SubscribePaneOutput(SubscribePaneOutputResponse),
UnsubscribePaneOutput(UnsubscribePaneOutputResponse),
PaneOutputCursor(PaneOutputCursorResponse),
PaneOutputLag(PaneOutputLagResponse),
SdkWaitForOutput(SdkWaitForOutputResponse),
CancelSdkWait(CancelSdkWaitResponse),
PaneBroadcastInput(PaneBroadcastInputResponse),
CreateSessionLease(CreateSessionLeaseResponse),
RenewSessionLease(RenewSessionLeaseResponse),
ReleaseSessionLease(ReleaseSessionLeaseResponse),
DaemonStatus(DaemonStatusResponse),
ShutdownIfIdle(ShutdownIfIdleResponse),
WebShare(WebShareResponse),
}
impl Response {
#[must_use]
pub const fn command_name(&self) -> &'static str {
match self {
Self::NewSession(_) => "new-session",
Self::HasSession(_) => "has-session",
Self::KillSession(_) => "kill-session",
Self::NewWindow(_) => "new-window",
Self::KillWindow(_) => "kill-window",
Self::SelectWindow(_) => "select-window",
Self::RenameWindow(_) => "rename-window",
Self::NextWindow(_) => "next-window",
Self::PreviousWindow(_) => "previous-window",
Self::LastWindow(_) => "last-window",
Self::ListWindows(_) => "list-windows",
Self::MoveWindow(_) => "move-window",
Self::SwapWindow(_) => "swap-window",
Self::RotateWindow(_) => "rotate-window",
Self::SplitWindow(_) => "split-window",
Self::SwapPane(_) => "swap-pane",
Self::LastPane(_) => "last-pane",
Self::JoinPane(_) => "join-pane",
Self::BreakPane(_) => "break-pane",
Self::KillPane(_) => "kill-pane",
Self::SelectLayout(_) => "select-layout",
Self::ResizePane(_) => "resize-pane",
Self::DisplayPanes(_) => "display-panes",
Self::SelectPane(_) => "select-pane",
Self::SendKeys(_) => "send-keys",
Self::AttachSession(_) => "attach-session",
Self::SwitchClient(_) => "switch-client",
Self::DetachClient(_) => "detach-client",
Self::SetOption(_) | Self::SetOptionByName(_) => "set-option",
Self::SetEnvironment(_) => "set-environment",
Self::SetHook(_) => "set-hook",
Self::Error(_) => "error",
Self::NextLayout(_) => "next-layout",
Self::PreviousLayout(_) => "previous-layout",
Self::ShowOptions(_) => "show-options",
Self::ShowEnvironment(_) => "show-environment",
Self::SetBuffer(_) => "set-buffer",
Self::ShowBuffer(_) => "show-buffer",
Self::PasteBuffer(_) => "paste-buffer",
Self::ListBuffers(_) => "list-buffers",
Self::DeleteBuffer(_) => "delete-buffer",
Self::LoadBuffer(_) => "load-buffer",
Self::SaveBuffer(_) => "save-buffer",
Self::CapturePane(_) => "capture-pane",
Self::DisplayMessage(_) => "display-message",
Self::RunShell(_) => "run-shell",
Self::IfShell(_) => "if-shell",
Self::WaitFor(_) => "wait-for",
Self::RenameSession(_) => "rename-session",
Self::ListSessions(_) => "list-sessions",
Self::ListPanes(_) => "list-panes",
Self::SourceFile(_) => "source-file",
Self::ShowHooks(_) => "show-hooks",
Self::BindKey(_) => "bind-key",
Self::UnbindKey(_) => "unbind-key",
Self::ListKeys(_) => "list-keys",
Self::SendPrefix(_) => "send-prefix",
Self::ClearHistory(_) => "clear-history",
Self::CopyMode(_) => "copy-mode",
Self::ControlMode(_) => "control-mode",
Self::ClockMode(_) => "clock-mode",
Self::ShowMessages(_) => "show-messages",
Self::KillServer(_) => "kill-server",
Self::LockServer(_) => "lock-server",
Self::LockSession(_) => "lock-session",
Self::LockClient(_) => "lock-client",
Self::ServerAccess(_) => "server-access",
Self::RefreshClient(_) => "refresh-client",
Self::ListClients(_) => "list-clients",
Self::SuspendClient(_) => "suspend-client",
Self::ResizeWindow(_) => "resize-window",
Self::RespawnWindow(_) => "respawn-window",
Self::MovePane(_) => "move-pane",
Self::PipePane(_) => "pipe-pane",
Self::RespawnPane(_) => "respawn-pane",
Self::PaneSnapshot(_) => "pane-snapshot",
Self::SubscribePaneOutput(_) => "subscribe-pane-output",
Self::UnsubscribePaneOutput(_) => "unsubscribe-pane-output",
Self::PaneOutputCursor(_) => "pane-output-cursor",
Self::PaneOutputLag(_) => "pane-output-lag",
Self::SdkWaitForOutput(_) => "sdk-wait-output",
Self::CancelSdkWait(_) => "cancel-sdk-wait",
Self::PaneBroadcastInput(_) => "send-keys",
Self::CreateSessionLease(_) => "create-session-lease",
Self::RenewSessionLease(_) => "renew-session-lease",
Self::ReleaseSessionLease(_) => "release-session-lease",
Self::LinkWindow(_) => "link-window",
Self::UnlinkWindow(_) => "unlink-window",
Self::ResolveTarget(_) => "resolve-target",
Self::Handshake(_) => "handshake",
Self::DaemonStatus(_) => "daemon-status",
Self::ShutdownIfIdle(_) => "shutdown-if-idle",
Self::WebShare(_) => "web-share",
}
}
#[must_use]
pub const fn is_error(&self) -> bool {
matches!(self, Self::Error(_))
}
#[must_use]
pub fn command_output(&self) -> Option<&CommandOutput> {
match self {
Self::NewSession(response) => response.command_output(),
Self::ListWindows(response) => Some(response.command_output()),
Self::ShowOptions(response) => Some(response.command_output()),
Self::ShowEnvironment(response) => Some(response.command_output()),
Self::ShowHooks(response) => Some(response.command_output()),
Self::ShowBuffer(response) => Some(response.command_output()),
Self::ListBuffers(response) => Some(response.command_output()),
Self::CapturePane(response) => response.command_output(),
Self::DisplayMessage(response) => response.command_output(),
Self::ResolveTarget(_) => None,
Self::RunShell(response) => response.command_output(),
Self::IfShell(response) => response.command_output(),
Self::ListSessions(response) => Some(response.command_output()),
Self::ListPanes(response) => Some(response.command_output()),
Self::SourceFile(response) => response.command_output(),
Self::SetOptionByName(_) => None,
Self::ListKeys(response) => Some(response.command_output()),
Self::ControlMode(_) => None,
Self::ClockMode(_) => None,
Self::ShowMessages(response) => Some(response.command_output()),
Self::ServerAccess(response) => Some(response.command_output()),
Self::ListClients(response) => Some(response.command_output()),
Self::BreakPane(response) => response.command_output(),
Self::Handshake(_) => None,
Self::WebShare(response) => response.command_output(),
Self::SubscribePaneOutput(_)
| Self::UnsubscribePaneOutput(_)
| Self::PaneOutputCursor(_)
| Self::PaneOutputLag(_)
| Self::SdkWaitForOutput(_)
| Self::CancelSdkWait(_)
| Self::PaneBroadcastInput(_)
| Self::CreateSessionLease(_)
| Self::RenewSessionLease(_)
| Self::ReleaseSessionLease(_)
| Self::DaemonStatus(_)
| Self::ShutdownIfIdle(_) => None,
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CommandOutput {
pub stdout: Vec<u8>,
}
impl CommandOutput {
#[must_use]
pub fn from_stdout(stdout: impl Into<Vec<u8>>) -> Self {
Self {
stdout: stdout.into(),
}
}
#[must_use]
pub fn stdout(&self) -> &[u8] {
&self.stdout
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct SelectLayoutResponse {
pub layout: LayoutName,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct NextLayoutResponse {
pub layout: LayoutName,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct PreviousLayoutResponse {
pub layout: LayoutName,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SetBufferResponse {
pub buffer_name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ShowBufferResponse {
pub output: CommandOutput,
}
impl ShowBufferResponse {
#[must_use]
pub fn command_output(&self) -> &CommandOutput {
&self.output
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PasteBufferResponse {
pub buffer_name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ListBuffersResponse {
pub output: CommandOutput,
}
impl ListBuffersResponse {
#[must_use]
pub fn command_output(&self) -> &CommandOutput {
&self.output
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DeleteBufferResponse {
pub buffer_name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LoadBufferResponse {
pub buffer_name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SaveBufferResponse {
pub buffer_name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CapturePaneResponse {
pub buffer_name: Option<String>,
pub output: Option<CommandOutput>,
}
impl CapturePaneResponse {
#[must_use]
pub fn from_buffer(buffer_name: String) -> Self {
Self {
buffer_name: Some(buffer_name),
output: None,
}
}
#[must_use]
pub fn from_output(output: CommandOutput) -> Self {
Self {
buffer_name: None,
output: Some(output),
}
}
#[must_use]
pub fn command_output(&self) -> Option<&CommandOutput> {
self.output.as_ref()
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct ClearHistoryResponse;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ShowMessagesResponse {
pub output: CommandOutput,
}
impl ShowMessagesResponse {
#[must_use]
pub const fn from_output(output: CommandOutput) -> Self {
Self { output }
}
#[must_use]
pub const fn command_output(&self) -> &CommandOutput {
&self.output
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DisplayMessageResponse {
pub output: Option<CommandOutput>,
}
impl DisplayMessageResponse {
#[must_use]
pub const fn no_output() -> Self {
Self { output: None }
}
#[must_use]
pub fn from_output(output: CommandOutput) -> Self {
Self {
output: Some(output),
}
}
#[must_use]
pub fn command_output(&self) -> Option<&CommandOutput> {
self.output.as_ref()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct RunShellResponse {
pub output: Option<CommandOutput>,
pub exit_status: Option<i32>,
}
impl RunShellResponse {
#[must_use]
pub const fn background() -> Self {
Self {
output: None,
exit_status: None,
}
}
#[must_use]
pub const fn no_output() -> Self {
Self::background()
}
#[must_use]
pub fn from_output(output: CommandOutput) -> Self {
Self {
output: Some(output),
exit_status: Some(0),
}
}
#[must_use]
pub const fn from_exit_status(exit_status: i32) -> Self {
Self {
output: None,
exit_status: Some(exit_status),
}
}
#[must_use]
pub fn from_output_and_exit_status(output: CommandOutput, exit_status: i32) -> Self {
Self {
output: Some(output),
exit_status: Some(exit_status),
}
}
#[must_use]
pub fn command_output(&self) -> Option<&CommandOutput> {
self.output.as_ref()
}
#[must_use]
pub const fn exit_status(&self) -> Option<i32> {
self.exit_status
}
}
impl<'de> Deserialize<'de> for RunShellResponse {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_struct(
"RunShellResponse",
&["output", "exit_status"],
RunShellResponseVisitor,
)
}
}
struct RunShellResponseVisitor;
impl<'de> Visitor<'de> for RunShellResponseVisitor {
type Value = RunShellResponse;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("a run-shell response")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let output = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let exit_status = compat_next_response_element(&mut seq)?;
Ok(RunShellResponse {
output,
exit_status,
})
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut output = None;
let mut exit_status = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"output" => output = Some(map.next_value()?),
"exit_status" => exit_status = Some(map.next_value()?),
_ => {
let _: de::IgnoredAny = map.next_value()?;
}
}
}
Ok(RunShellResponse {
output: output.ok_or_else(|| de::Error::missing_field("output"))?,
exit_status: exit_status.unwrap_or_default(),
})
}
}
fn compat_next_response_element<'de, A, T>(seq: &mut A) -> Result<T, A::Error>
where
A: SeqAccess<'de>,
T: Deserialize<'de> + Default,
{
match seq.next_element::<T>() {
Ok(Some(value)) => Ok(value),
Ok(None) => Ok(T::default()),
Err(error) if is_truncated_compat_sequence(&error) => Ok(T::default()),
Err(error) => Err(error),
}
}
fn is_truncated_compat_sequence(error: &impl std::fmt::Display) -> bool {
let message = error.to_string();
message.contains("UnexpectedEof") || message.contains("unexpected end of file")
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct IfShellResponse {
pub output: Option<CommandOutput>,
}
impl IfShellResponse {
#[must_use]
pub const fn no_output() -> Self {
Self { output: None }
}
#[must_use]
pub fn from_output(output: CommandOutput) -> Self {
Self {
output: Some(output),
}
}
#[must_use]
pub fn command_output(&self) -> Option<&CommandOutput> {
self.output.as_ref()
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct SourceFileResponse {
pub output: Option<CommandOutput>,
#[serde(default)]
pub exit_status: Option<i32>,
}
impl SourceFileResponse {
#[must_use]
pub const fn no_output() -> Self {
Self {
output: None,
exit_status: None,
}
}
#[must_use]
pub fn from_output(output: CommandOutput) -> Self {
Self {
output: Some(output),
exit_status: None,
}
}
#[must_use]
pub fn command_output(&self) -> Option<&CommandOutput> {
self.output.as_ref()
}
#[must_use]
pub const fn with_exit_status(mut self, exit_status: Option<i32>) -> Self {
self.exit_status = exit_status;
self
}
#[must_use]
pub const fn exit_status(&self) -> Option<i32> {
self.exit_status
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct WaitForResponse;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SdkWaitOutcome {
Matched,
Cancelled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct SdkWaitForOutputResponse {
pub wait_id: SdkWaitId,
pub outcome: SdkWaitOutcome,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct CancelSdkWaitResponse {
pub wait_id: SdkWaitId,
pub removed: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ErrorResponse {
pub error: RmuxError,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{OptionScopeSelector, SetOptionMode};
use serde::Serialize;
#[derive(Serialize)]
struct OldRunShellResponse {
output: Option<CommandOutput>,
}
#[test]
fn run_shell_response_deserializes_old_payloads_with_no_exit_status() {
let bytes = bincode::serialize(&OldRunShellResponse { output: None })
.expect("old run-shell response serializes");
let decoded: RunShellResponse =
bincode::deserialize(&bytes).expect("new run-shell response decodes old payload");
assert_eq!(decoded.command_output(), None);
assert_eq!(decoded.exit_status(), None);
}
#[test]
fn response_command_names_cover_base_aliases_and_error_tag() {
assert_eq!(
Response::HasSession(HasSessionResponse { exists: true }).command_name(),
"has-session"
);
assert_eq!(
Response::SetOptionByName(SetOptionByNameResponse {
scope: OptionScopeSelector::ServerGlobal,
name: "status".to_owned(),
mode: SetOptionMode::Replace,
})
.command_name(),
"set-option"
);
assert_eq!(
Response::KillServer(KillServerResponse).command_name(),
"kill-server"
);
assert_eq!(
Response::Error(ErrorResponse {
error: RmuxError::Server("failed".to_owned()),
})
.command_name(),
"error"
);
assert_eq!(
Response::Handshake(HandshakeResponse::current()).command_name(),
"handshake"
);
assert_eq!(
Response::SdkWaitForOutput(SdkWaitForOutputResponse {
wait_id: SdkWaitId::new(1),
outcome: SdkWaitOutcome::Matched,
})
.command_name(),
"sdk-wait-output"
);
assert_eq!(
Response::CancelSdkWait(CancelSdkWaitResponse {
wait_id: SdkWaitId::new(1),
removed: false,
})
.command_name(),
"cancel-sdk-wait"
);
assert_eq!(
Response::WaitFor(WaitForResponse).command_name(),
"wait-for"
);
}
}