• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

unrenamed / chatd / 9973933170

17 Jul 2024 12:10PM UTC coverage: 32.813% (+16.6%) from 16.215%
9973933170

push

github

unrenamed
test: input validator

820 of 2499 relevant lines covered (32.81%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.5
/src/server/session_workflow/input_validator.rs
1
use async_trait::async_trait;
2
use std::io::Write;
3

4
use super::handler::{into_next, WorkflowHandler};
5
use super::WorkflowContext;
6

7
use crate::auth::Auth;
8
use crate::chat::{message, ChatRoom};
9
use crate::terminal::{CloseHandle, Terminal};
10

11
const INPUT_MAX_LEN: usize = 1024;
12

13
#[derive(Default)]
14
pub struct InputValidator<H>
15
where
16
    H: Clone + Write + CloseHandle + Send,
17
{
18
    next: Option<Box<dyn WorkflowHandler<H>>>,
19
}
20

21
impl<H> InputValidator<H>
22
where
23
    H: Clone + Write + CloseHandle + Send,
24
{
25
    pub fn new(next: impl WorkflowHandler<H> + 'static) -> Self {
1✔
26
        Self {
27
            next: into_next(next),
1✔
28
        }
29
    }
30
}
31

32
#[async_trait]
33
impl<H> WorkflowHandler<H> for InputValidator<H>
34
where
35
    H: Clone + Write + CloseHandle + Send,
36
{
37
    #[allow(unused_variables)]
38
    async fn handle(
39
        &mut self,
40
        context: &mut WorkflowContext,
41
        terminal: &mut Terminal<H>,
42
        room: &mut ChatRoom,
43
        auth: &mut Auth,
44
    ) -> anyhow::Result<()> {
45
        let input_str = terminal.input.to_string();
2✔
46
        if input_str.trim().is_empty() {
2✔
47
            self.next = None;
8✔
48
            return Ok(());
4✔
49
        }
50

51
        if input_str.len() > INPUT_MAX_LEN {
2✔
52
            let message = message::Error::new(
53
                context.user.clone().into(),
×
54
                "message dropped. Input is too long".to_string(),
×
55
            );
56
            room.send_message(message.into()).await?;
×
57
            self.next = None;
×
58
            return Ok(());
×
59
        }
60

61
        context.command_str = Some(input_str);
2✔
62
        Ok(())
1✔
63
    }
64

65
    fn next(&mut self) -> &mut Option<Box<dyn WorkflowHandler<H>>> {
1✔
66
        &mut self.next
×
67
    }
68
}
69

70
#[cfg(test)]
71
mod should {
72
    use crate::chat::User;
73
    use crate::server::session_workflow::input_rate_checker::InputRateChecker;
74
    use mockall::mock;
75

76
    use super::*;
77

78
    mock! {
79
        pub Handle {}
80

81
        impl Write for Handle {
82
            fn write(&mut self, buf: &[u8]) -> std::io::Result<usize>;
83
            fn flush(&mut self) -> std::io::Result<()>;
84
        }
85

86
        impl Clone for Handle {
87
            fn clone(&self) -> Self;
88
        }
89

90
        impl CloseHandle for Handle {
91
            fn close(&mut self) {}
92
        }
93
    }
94

95
    macro_rules! setup {
96
        () => {{
97
            let user = User::default();
98
            let auth = Auth::default();
99
            let terminal = Terminal::new(MockHandle::new());
100
            let room = ChatRoom::new("Hello Chatters!");
101
            let context = WorkflowContext::new(user);
102
            (auth, terminal, room, context)
103
        }};
104
    }
105

106
    #[tokio::test]
107
    async fn return_ok() {
108
        let (mut auth, mut terminal, mut room, mut context) = setup!();
109
        let checker: InputRateChecker<MockHandle> = InputRateChecker::default();
110
        let mut parser = InputValidator::new(checker);
111

112
        assert!(parser
113
            .handle(&mut context, &mut terminal, &mut room, &mut auth)
114
            .await
115
            .is_ok());
116
    }
117

118
    #[tokio::test]
119
    async fn return_next_handler() {
120
        let checker: InputRateChecker<MockHandle> = InputRateChecker::default();
121
        let mut parser = InputValidator::new(checker);
122
        assert!(parser.next().is_some());
123
    }
124

125
    #[tokio::test]
126
    async fn unset_next_handler_when_input_is_empty() {
127
        let (mut auth, mut terminal, mut room, mut context) = setup!();
128
        let checker: InputRateChecker<MockHandle> = InputRateChecker::default();
129
        let mut parser = InputValidator::new(checker);
130

131
        terminal.input.clear();
132

133
        let _ = parser
134
            .handle(&mut context, &mut terminal, &mut room, &mut auth)
135
            .await;
136
        assert!(parser.next().is_none());
137
    }
138

139
    #[tokio::test]
140
    async fn unset_next_handler_when_input_is_whitespace_only() {
141
        let (mut auth, mut terminal, mut room, mut context) = setup!();
142
        let checker: InputRateChecker<MockHandle> = InputRateChecker::default();
143
        let mut parser = InputValidator::new(checker);
144

145
        terminal.input.clear();
146
        terminal.input.insert_before_cursor(b"     ");
147

148
        let _ = parser
149
            .handle(&mut context, &mut terminal, &mut room, &mut auth)
150
            .await;
151
        assert!(parser.next().is_none());
152
    }
153

154
    #[tokio::test]
155
    async fn unset_next_handler_when_input_is_too_long() {
156
        let (mut auth, mut terminal, mut room, mut context) = setup!();
157
        let checker: InputRateChecker<MockHandle> = InputRateChecker::default();
158
        let mut parser = InputValidator::new(checker);
159

160
        terminal.input.clear();
161
        terminal
162
            .input
163
            .insert_before_cursor("".repeat(1025).as_bytes());
164

165
        let _ = parser
166
            .handle(&mut context, &mut terminal, &mut room, &mut auth)
167
            .await;
168
        assert!(parser.next().is_none());
169
    }
170

171
    #[tokio::test]
172
    async fn add_command_to_context_when_input_is_valid() {
173
        let (mut auth, mut terminal, mut room, mut context) = setup!();
174
        let checker: InputRateChecker<MockHandle> = InputRateChecker::default();
175
        let mut parser = InputValidator::new(checker);
176

177
        terminal.input.clear();
178
        terminal.input.insert_before_cursor(b"/help");
179

180
        let _ = parser
181
            .handle(&mut context, &mut terminal, &mut room, &mut auth)
182
            .await;
183

184
        assert_eq!(context.command_str, Some("/help".into()));
185
        assert!(parser.next().is_some());
186
    }
187
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc