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