Skip to main content

dsp_cli/actions/auth/
mod.rs

1//! Actions for `dsp auth { login | status | logout | set-token | token }`.
2
3pub mod login;
4pub mod logout;
5pub mod set_token;
6pub mod status;
7pub mod token;
8
9/// Trim a single trailing line terminator from a string read via `read_line`.
10///
11/// Pops one trailing `\n` if present, then pops one preceding `\r` only if it
12/// directly followed that `\n`. A bare trailing `\r` with no preceding `\n` is
13/// **not** stripped — `\r` is a legitimate character in a token or password, so
14/// we must not use `trim_end_matches` or strip it unconditionally.
15pub(crate) fn trim_line_ending(line: &mut String) {
16    if line.ends_with('\n') {
17        line.pop();
18        if line.ends_with('\r') {
19            line.pop();
20        }
21    }
22}
23
24#[cfg(test)]
25mod tests {
26    use super::trim_line_ending;
27
28    #[test]
29    fn trim_line_ending_removes_trailing_lf() {
30        let mut s = "hello\n".to_string();
31        trim_line_ending(&mut s);
32        assert_eq!(s, "hello");
33    }
34
35    #[test]
36    fn trim_line_ending_removes_trailing_crlf() {
37        let mut s = "hello\r\n".to_string();
38        trim_line_ending(&mut s);
39        assert_eq!(s, "hello");
40    }
41
42    #[test]
43    fn trim_line_ending_leaves_no_terminator_unchanged() {
44        let mut s = "hello".to_string();
45        trim_line_ending(&mut s);
46        assert_eq!(s, "hello");
47    }
48
49    #[test]
50    fn trim_line_ending_leaves_empty_string_unchanged() {
51        let mut s = String::new();
52        trim_line_ending(&mut s);
53        assert_eq!(s, "");
54    }
55
56    #[test]
57    fn trim_line_ending_does_not_strip_bare_cr_without_lf() {
58        // A bare \r (no preceding \n) must NOT be stripped — it may be a
59        // legitimate character in a token or password.
60        let mut s = "hello\r".to_string();
61        trim_line_ending(&mut s);
62        assert_eq!(s, "hello\r", "bare \\r must not be removed");
63    }
64}