use crate::resp::{ClientReplyMode, CommandKind};
pub(crate) struct ReplyMode {
on: bool,
skip_next: bool,
}
impl ReplyMode {
pub(crate) fn new() -> Self {
Self {
on: true,
skip_next: false,
}
}
pub(crate) fn admit(&mut self, kind: CommandKind) -> bool {
match kind {
CommandKind::ClientReply(ClientReplyMode::On) | CommandKind::Reset => {
self.on = true;
self.skip_next = false;
}
CommandKind::ClientReply(ClientReplyMode::Off) => {
self.on = false;
self.skip_next = false;
}
CommandKind::ClientReply(ClientReplyMode::Skip) => {
self.skip_next = true;
return false;
}
_ => (),
}
if !self.on {
return false;
}
if self.skip_next {
self.skip_next = false;
return false;
}
true
}
pub(crate) fn restore(&mut self, on: bool) {
self.on = on;
self.skip_next = false;
}
pub(crate) fn forget_pending_skip(&mut self) {
self.skip_next = false;
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::resp::StateSlot;
const PLAIN: CommandKind = CommandKind::Other;
const ON: CommandKind = CommandKind::ClientReply(ClientReplyMode::On);
const OFF: CommandKind = CommandKind::ClientReply(ClientReplyMode::Off);
const SKIP: CommandKind = CommandKind::ClientReply(ClientReplyMode::Skip);
#[test]
fn a_new_connection_answers() {
let mut mode = ReplyMode::new();
assert!(mode.admit(PLAIN));
assert!(mode.admit(PLAIN));
}
#[test]
fn off_silences_itself_and_everything_after_it() {
let mut mode = ReplyMode::new();
assert!(!mode.admit(OFF));
assert!(!mode.admit(PLAIN));
assert!(!mode.admit(PLAIN));
}
#[test]
fn on_is_answered_and_reopens_the_connection() {
let mut mode = ReplyMode::new();
mode.admit(OFF);
assert!(mode.admit(ON));
assert!(mode.admit(PLAIN));
}
#[test]
fn skip_silences_itself_and_the_next_command_only() {
let mut mode = ReplyMode::new();
assert!(!mode.admit(SKIP));
assert!(!mode.admit(PLAIN));
assert!(mode.admit(PLAIN));
}
#[test]
fn two_skips_in_a_row_silence_one_command_each() {
let mut mode = ReplyMode::new();
assert!(!mode.admit(SKIP));
assert!(!mode.admit(PLAIN));
assert!(!mode.admit(SKIP));
assert!(!mode.admit(PLAIN));
assert!(mode.admit(PLAIN));
}
#[test]
fn a_pending_skip_does_not_outlive_off_and_on() {
let mut mode = ReplyMode::new();
mode.admit(SKIP);
mode.admit(OFF);
assert!(mode.admit(ON));
assert!(mode.admit(PLAIN));
}
#[test]
fn reset_answers_and_restores_the_default_mode() {
let mut mode = ReplyMode::new();
mode.admit(OFF);
mode.admit(SKIP);
assert!(mode.admit(CommandKind::Reset));
assert!(mode.admit(PLAIN));
}
#[test]
fn connection_state_commands_are_answered_like_any_other() {
let mut mode = ReplyMode::new();
assert!(mode.admit(CommandKind::ConnectionState(StateSlot::Select)));
}
#[test]
fn a_remade_connection_adopts_its_restored_mode() {
let mut mode = ReplyMode::new();
mode.admit(SKIP);
mode.restore(false);
assert!(!mode.admit(PLAIN));
mode.restore(true);
assert!(mode.admit(PLAIN));
}
#[test]
fn forgetting_a_pending_skip_leaves_off_alone() {
let mut mode = ReplyMode::new();
mode.admit(OFF);
mode.admit(SKIP);
mode.forget_pending_skip();
assert!(!mode.admit(PLAIN));
}
}