1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
-
+
+
+
+
-
-
+
+
-
+
-
+
+
-
+
-
+
+
|
use smtp2tg::utils::{
validate,
RE_CLOSING,
RE_DOMAIN,
};
use std::{
borrow::Cow,
mem::discriminant,
};
use stacked_errors::Result;
use stacked_errors::{
Result,
ensure_eq,
};
#[test]
fn test_validate_escaping_behavior () -> Result<()> {
let cases: &[(&str, Cow<str>)] = &[
// `validate` escapes HTML special characters.
("<p>Some <b>valid</b> HTML</p>", Cow::Owned("<p>Some <b>valid</b> HTML</p>".into())),
// Empty input is returned unchanged.
("", Cow::Borrowed("")),
// Whitespace-only input needs no escaping.
(" \t\n", Cow::Borrowed(" \t\n")),
// `validate` returns `Cow<'a, str>` borrowed from its input lifetime `'a`.
// These two cases exercise both branches of that `Cow` to make sure the
// explicit lifetime introduced on `validate` still lets callers observe a
// zero-copy borrow when no escaping is required.
("plain text without special html characters", Cow::Borrowed("plain text without special html characters")),
("5 > 3 & 2 < 4", Cow::Owned("5 > 3 & 2 < 4".into())),
];
for (input, expected) in cases {
let result = validate(input)?;
assert_eq!(&result, expected, "unexpected output for input {input:?}");
assert_eq!(discriminant(&result), discriminant(expected), "wrong Cow variant for input {input:?}");
ensure_eq!(&result, expected, format!("unexpected output for input {input:?}"));
ensure_eq!(discriminant(&result), discriminant(expected), format!("wrong Cow variant for input {input:?}"));
}
Ok(())
}
#[test]
fn test_validate_closing_tag_behavior () {
fn test_validate_closing_tag_behavior () -> Result<()> {
let cases = [
("</ pre >", true),
("</\tcode\t>", true),
("</b>", false),
("</Code>", true),
("</code>", true),
("</code>\t", true),
("</code>\t>", true),
("</div>", false), // Not a pre/code tag
("</PRE>", true),
("</pre>", true),
("</pre>\n", true),
("<p>Some <b>valid</b> HTML</p></code><a href='http://somewere.com'>Link injection!</a>", true),
("<pre>", false),
];
for (input, expected) in cases {
assert_eq!(RE_CLOSING.is_match(input), expected, "unexpected match result for {input:?}");
ensure_eq!(RE_CLOSING.is_match(input), expected, format!("unexpected match result for {input:?}"));
}
Ok(())
}
#[test]
fn test_regex_domain_behavior() {
fn test_regex_domain_behavior() -> Result<()> {
let cases = [
("", false),
("-example.com", false),
(".example.com", false),
("123.456", true),
("EXAMPLE.COM", false),
("a", true),
("a.b", true),
("example-.com", false),
("example..com", false),
("example.com", true),
("example.com.", false),
("invalid@domain.com", false),
("my-host.example.com", true),
("sub.example.co.uk", true),
];
for (input, expected) in cases {
assert_eq!(RE_DOMAIN.is_match(input), expected, "unexpected match result for {input:?}");
ensure_eq!(RE_DOMAIN.is_match(input), expected, format!("unexpected match result for {input:?}"));
}
Ok(())
}
|