commit d756babec5110b22456f56daf3348d610ebd96ed
parent 5b809542b209411b55ce924d058dd9cc4e97d207
Author: Zack Newman <zack@philomathiclife.com>
Date: Mon, 13 Jul 2026 11:53:21 -0600
bump msrv. new lints. move unit tests to own file
Diffstat:
| M | Cargo.toml | | | 12 | ++++++++---- |
| M | src/char_set.rs | | | 332 | ++++--------------------------------------------------------------------------- |
| A | src/char_set/tests.rs | | | 231 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | src/dom.rs | | | 341 | +------------------------------------------------------------------------------ |
| A | src/dom/tests.rs | | | 357 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | src/serde.rs | | | 51 | +++------------------------------------------------ |
| A | src/serde/tests.rs | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
7 files changed, 664 insertions(+), 705 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0"
name = "ascii_domain"
readme = "README.md"
repository = "https://git.philomathiclife.com/repos/ascii_domain/"
-rust-version = "1.93.1"
-version = "0.6.9"
+rust-version = "1.97.0"
+version = "0.6.10"
[lints.rust]
deprecated-safe = { level = "deny", priority = -1 }
@@ -28,12 +28,14 @@ unused = { level = "deny", priority = -1 }
warnings = { level = "deny", priority = -1 }
ambiguous-negative-literals = { level = "deny", priority = -1 }
closure-returning-async-block = { level = "deny", priority = -1 }
+dead-code-pub-in-binary = { level = "deny", priority = -1 }
deprecated-in-future = { level = "deny", priority = -1 }
+#deprecated-llvm-intrinsic = { level = "deny", priority = -1 }
deref-into-dyn-supertrait = { level = "deny", priority = -1 }
ffi-unwind-calls = { level = "deny", priority = -1 }
#fuzzy-provenance-casts = { level = "deny", priority = -1 }
impl-trait-redundant-captures = { level = "deny", priority = -1 }
-linker-messages = { level = "deny", priority = -1 }
+linker-info = { level = "deny", priority = -1 }
#lossy-provenance-casts = { level = "deny", priority = -1 }
macro-use-extern-crate = { level = "deny", priority = -1 }
meta-variable-misuse = { level = "deny", priority = -1 }
@@ -79,10 +81,12 @@ arbitrary_source_item_ordering = "allow"
blanket_clippy_restriction_lints = "allow"
exhaustive_enums = "allow"
implicit_return = "allow"
+inline_trait_bounds = "allow"
min_ident_chars = "allow"
missing_trait_methods = "allow"
question_mark_used = "allow"
return_and_then = "allow"
+self_named_module_files = "allow"
single_char_lifetime_names = "allow"
unseparated_literal_suffix = "allow"
@@ -109,7 +113,7 @@ targets = [
serde = { version = "1.0.228", default-features = false, features = ["alloc"], optional = true }
[dev-dependencies]
-serde_json = { version = "1.0.149", default-features = false, features = ["alloc"] }
+serde_json = { version = "1.0.150", default-features = false, features = ["alloc"] }
### FEATURES #################################################################
diff --git a/src/char_set.rs b/src/char_set.rs
@@ -1,3 +1,6 @@
+#[cfg(test)]
+/// Unit tests.
+mod tests;
use core::{
error::Error,
fmt::{self, Display, Formatter},
@@ -191,29 +194,14 @@ impl<T: AsMut<[u8]>> AllowedAscii<T> {
/// That is to say printable ASCII excluding space (i.e., 32), dot (i.e. 46), and backslash (i.e., 92).
/// This returns all `u8`s inclusively between 33 and 126 except 46 and 92.
pub const PRINTABLE_ASCII: AllowedAscii<[u8; 92]> = AllowedAscii {
- allowed: [
- b'!', b'"', b'#', b'$', b'%', b'&', b'\'', b'(', b')', b'*', b'+', b',', b'-', b'/', b'0',
- b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
- b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N',
- b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'[', b']', b'^',
- b'_', b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm',
- b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', b'{', b'|',
- b'}', b'~',
- ],
+ allowed: *b"!\"#$%&'()*+,-/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",
};
/// ASCII allowed in [RFC 5322 `atext`](https://www.rfc-editor.org/rfc/rfc5322#section-3.2.3).
/// This contains the following `u8`s:
///
/// 33, 35–39, 42–43, 45, 47–57, 61, 63, 65–90, and 94–126.
pub const RFC5322_ATEXT: AllowedAscii<[u8; 81]> = AllowedAscii {
- allowed: [
- b'!', b'#', b'$', b'%', b'&', b'\'', b'*', b'+', b'-', b'/', b'0', b'1', b'2', b'3', b'4',
- b'5', b'6', b'7', b'8', b'9', b'=', b'?', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H',
- b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
- b'X', b'Y', b'Z', b'^', b'_', b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i',
- b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x',
- b'y', b'z', b'{', b'|', b'}', b'~',
- ],
+ allowed: *b"!#$%&'*+-/0123456789=?ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~",
};
/// ASCII allowed in a domain by [Firefox](https://www.mozilla.org/en-US/firefox/)
/// as of 2023-09-03T20:50+00:00.
@@ -221,103 +209,57 @@ pub const RFC5322_ATEXT: AllowedAscii<[u8; 81]> = AllowedAscii {
///
/// 33, 36, 38–41, 43–45, 48–57, 59, 61, 65–90, 95–123, and 125–126.
pub const ASCII_FIREFOX: AllowedAscii<[u8; 78]> = AllowedAscii {
- allowed: [
- b'!', b'$', b'&', b'\'', b'(', b')', b'+', b',', b'-', b'0', b'1', b'2', b'3', b'4', b'5',
- b'6', b'7', b'8', b'9', b';', b'=', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I',
- b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X',
- b'Y', b'Z', b'_', b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k',
- b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z',
- b'{', b'}', b'~',
- ],
+ allowed: *b"!$&'()+,-0123456789;=ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz{}~",
};
/// ASCII hyphen, digits, and letters.
/// This contains 45 and all `u8`s inclusively between 48 and 57, 65 and 90, and 97 and 122.
pub const ASCII_HYPHEN_DIGITS_LETTERS: AllowedAscii<[u8; 63]> = AllowedAscii {
- allowed: [
- b'-', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D',
- b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S',
- b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h',
- b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
- b'x', b'y', b'z',
- ],
+ allowed: *b"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
};
/// ASCII digits and letters.
/// This contains all `u8`s inclusively between 48 and 57, 65 and 90, and 97 and 122.
pub const ASCII_DIGITS_LETTERS: AllowedAscii<[u8; 62]> = AllowedAscii {
- allowed: [
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E',
- b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T',
- b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i',
- b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x',
- b'y', b'z',
- ],
+ allowed: *b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
};
/// ASCII letters.
/// This contains all `u8`s inclusively between 65 and 90 and 97 and 122.
pub const ASCII_LETTERS: AllowedAscii<[u8; 52]> = AllowedAscii {
- allowed: [
- b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
- b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd',
- b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's',
- b't', b'u', b'v', b'w', b'x', b'y', b'z',
- ],
+ allowed: *b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
};
/// ASCII hyphen, digits, and uppercase letters.
/// This contains 45 and all `u8`s inclusively between 48 and 57 and 65 and 90.
pub const ASCII_HYPHEN_DIGITS_UPPERCASE: AllowedAscii<[u8; 37]> = AllowedAscii {
- allowed: [
- b'-', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D',
- b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S',
- b'T', b'U', b'V', b'W', b'X', b'Y', b'Z',
- ],
+ allowed: *b"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
};
/// ASCII hyphen, digits, and lowercase letters.
/// This contains 45 and all `u8`s inclusively between 48 and 57 and 97 and 122.
pub const ASCII_HYPHEN_DIGITS_LOWERCASE: AllowedAscii<[u8; 37]> = AllowedAscii {
- allowed: [
- b'-', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd',
- b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's',
- b't', b'u', b'v', b'w', b'x', b'y', b'z',
- ],
+ allowed: *b"-0123456789abcdefghijklmnopqrstuvwxyz",
};
/// ASCII digits and uppercase letters.
/// This contains all `u8`s inclusively between 48 and 57 and 65 and 90.
pub const ASCII_DIGITS_UPPERCASE: AllowedAscii<[u8; 36]> = AllowedAscii {
- allowed: [
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E',
- b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T',
- b'U', b'V', b'W', b'X', b'Y', b'Z',
- ],
+ allowed: *b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
};
/// ASCII digits and lowercase letters.
/// This contains all `u8`s inclusively between 48 and 57 and 97 and 122.
pub const ASCII_DIGITS_LOWERCASE: AllowedAscii<[u8; 36]> = AllowedAscii {
- allowed: [
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e',
- b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't',
- b'u', b'v', b'w', b'x', b'y', b'z',
- ],
+ allowed: *b"0123456789abcdefghijklmnopqrstuvwxyz",
};
/// ASCII uppercase letters.
/// This contains all `u8`s inclusively between 65 and 90.
pub const ASCII_UPPERCASE: AllowedAscii<[u8; 26]> = AllowedAscii {
- allowed: [
- b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
- b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z',
- ],
+ allowed: *b"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
};
/// ASCII lowercase letters.
/// This contains all `u8`s inclusively between 97 and 122.
pub const ASCII_LOWERCASE: AllowedAscii<[u8; 26]> = AllowedAscii {
- allowed: [
- b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
- b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z',
- ],
+ allowed: *b"abcdefghijklmnopqrstuvwxyz",
};
/// ASCII digits.
/// This contains all `u8`s inclusively between 48 and 57.
pub const ASCII_DIGITS: AllowedAscii<[u8; 10]> = AllowedAscii {
- allowed: [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9'],
+ allowed: *b"0123456789",
};
/// ASCII that is not a [forbidden domain code point](https://url.spec.whatwg.org/#forbidden-domain-code-point).
///
@@ -325,245 +267,5 @@ pub const ASCII_DIGITS: AllowedAscii<[u8; 10]> = AllowedAscii {
///
/// 33, 34, 36, 38–45, 48–57, 59, 61, 65–90, 95–123, and 125–126.
pub const WHATWG_VALID_DOMAIN_CODE_POINTS: AllowedAscii<[u8; 80]> = AllowedAscii {
- allowed: [
- b'!', b'"', b'$', b'&', b'\'', b'(', b')', b'*', b'+', b',', b'-', b'0', b'1', b'2', b'3',
- b'4', b'5', b'6', b'7', b'8', b'9', b';', b'=', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
- b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V',
- b'W', b'X', b'Y', b'Z', b'_', b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i',
- b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x',
- b'y', b'z', b'{', b'}', b'~',
- ],
+ allowed: *b"!\"$&'()*+,-0123456789;=ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz{}~",
};
-#[cfg(test)]
-mod tests {
- extern crate alloc;
- use crate::char_set::{
- ASCII_DIGITS, ASCII_DIGITS_LETTERS, ASCII_DIGITS_LOWERCASE, ASCII_DIGITS_UPPERCASE,
- ASCII_FIREFOX, ASCII_HYPHEN_DIGITS_LETTERS, ASCII_HYPHEN_DIGITS_LOWERCASE,
- ASCII_HYPHEN_DIGITS_UPPERCASE, ASCII_LETTERS, ASCII_LOWERCASE, ASCII_UPPERCASE,
- AllowedAscii, AsciiErr, PRINTABLE_ASCII, RFC5322_ATEXT, WHATWG_VALID_DOMAIN_CODE_POINTS,
- };
- use alloc::{borrow::ToOwned as _, vec::Vec};
- #[test]
- fn try_from() {
- // Empty is allowed.
- assert_eq!(
- AllowedAscii::try_from_unique_ascii([]),
- Ok(AllowedAscii { allowed: [] })
- );
- // Duplicates are not allowed.
- assert_eq!(
- AllowedAscii::try_from_unique_ascii(b"aba".to_owned()),
- Err(AsciiErr::Duplicate(b'a'))
- );
- // `b'.'` is not allowed.
- assert_eq!(
- AllowedAscii::try_from_unique_ascii(b"a.c".to_owned()),
- Err(AsciiErr::Contains46)
- );
- // At most 127 bytes are allowed.
- assert_eq!(
- AllowedAscii::try_from_unique_ascii([0; 128]),
- Err(AsciiErr::CountTooLarge(128))
- );
- let mut all_ascii = (0..b'.').collect::<Vec<u8>>();
- let next = b'.' + 1;
- all_ascii.extend(next..=127);
- assert_eq!(
- AllowedAscii::try_from_unique_ascii(all_ascii.clone()),
- Ok(AllowedAscii { allowed: all_ascii })
- );
- // Only ASCII is allowed.
- assert_eq!(
- AllowedAscii::try_from_unique_ascii([255]),
- Err(AsciiErr::InvalidByte(255))
- );
- assert!(
- AllowedAscii::try_from_unique_ascii(b"abcdef".to_owned()).is_ok_and(|bytes| bytes
- .contains(b'a')
- && bytes.contains(b'b')
- && bytes.contains(b'c')
- && bytes.contains(b'd')
- && bytes.contains(b'e')
- && bytes.contains(b'f'))
- );
- }
- #[expect(
- clippy::cognitive_complexity,
- clippy::too_many_lines,
- reason = "want to test a lot of things"
- )]
- #[test]
- fn consts() {
- let letters = ASCII_LETTERS;
- assert!(letters.len() == 52);
- for i in b'A'..=b'Z' {
- assert!(letters.contains(i));
- }
- for i in b'a'..=b'z' {
- assert!(letters.contains(i));
- }
- let digits = ASCII_DIGITS;
- assert!(digits.len() == 10);
- for i in b'0'..=b'9' {
- assert!(digits.contains(i));
- }
- let lower = ASCII_LOWERCASE;
- assert!(lower.len() == 26);
- for i in b'a'..=b'z' {
- assert!(lower.contains(i));
- }
- let upper = ASCII_UPPERCASE;
- assert!(upper.len() == 26);
- for i in b'A'..=b'Z' {
- assert!(upper.contains(i));
- }
- let dig_let = ASCII_DIGITS_LETTERS;
- assert!(dig_let.len() == 62);
- for i in b'a'..=b'z' {
- assert!(dig_let.contains(i));
- }
- for i in b'0'..=b'9' {
- assert!(dig_let.contains(i));
- }
- for i in b'A'..=b'Z' {
- assert!(dig_let.contains(i));
- }
- let dig_lower = ASCII_DIGITS_LOWERCASE;
- assert!(dig_lower.len() == 36);
- for i in b'a'..=b'z' {
- assert!(dig_lower.contains(i));
- }
- for i in b'0'..=b'9' {
- assert!(dig_lower.contains(i));
- }
- let dig_upper = ASCII_DIGITS_UPPERCASE;
- assert!(dig_upper.len() == 36);
- for i in b'A'..=b'Z' {
- assert!(dig_upper.contains(i));
- }
- for i in b'0'..=b'9' {
- assert!(dig_upper.contains(i));
- }
- let ffox = ASCII_FIREFOX;
- assert!(ffox.len() == 78);
- for i in b'A'..=b'Z' {
- assert!(ffox.contains(i));
- }
- for i in b'a'..=b'z' {
- assert!(ffox.contains(i));
- }
- for i in b'0'..=b'9' {
- assert!(ffox.contains(i));
- }
- assert!(ffox.contains(b'!'));
- assert!(ffox.contains(b'$'));
- assert!(ffox.contains(b'&'));
- assert!(ffox.contains(b'\''));
- assert!(ffox.contains(b'('));
- assert!(ffox.contains(b')'));
- assert!(ffox.contains(b'+'));
- assert!(ffox.contains(b','));
- assert!(ffox.contains(b'-'));
- assert!(ffox.contains(b';'));
- assert!(ffox.contains(b'='));
- assert!(ffox.contains(b'_'));
- assert!(ffox.contains(b'`'));
- assert!(ffox.contains(b'{'));
- assert!(ffox.contains(b'}'));
- assert!(ffox.contains(b'~'));
- assert!(ASCII_HYPHEN_DIGITS_LETTERS.len() == 63);
- assert!(ASCII_HYPHEN_DIGITS_LETTERS.contains(b'-'));
- for i in b'A'..=b'Z' {
- assert!(ASCII_HYPHEN_DIGITS_LETTERS.contains(i));
- }
- for i in b'a'..=b'z' {
- assert!(ASCII_HYPHEN_DIGITS_LETTERS.contains(i));
- }
- for i in b'0'..=b'9' {
- assert!(ASCII_HYPHEN_DIGITS_LETTERS.contains(i));
- }
- let hyp_lower = ASCII_HYPHEN_DIGITS_LOWERCASE;
- assert!(hyp_lower.len() == 37);
- assert!(hyp_lower.contains(b'-'));
- for i in b'a'..=b'z' {
- assert!(hyp_lower.contains(i));
- }
- for i in b'0'..=b'9' {
- assert!(hyp_lower.contains(i));
- }
- let hyp_upper = ASCII_HYPHEN_DIGITS_UPPERCASE;
- assert!(hyp_upper.len() == 37);
- assert!(hyp_upper.contains(b'-'));
- for i in b'A'..=b'Z' {
- assert!(hyp_upper.contains(i));
- }
- for i in b'0'..=b'9' {
- assert!(hyp_upper.contains(i));
- }
- let printable = PRINTABLE_ASCII;
- assert!(printable.len() == 92);
- let stop = b'.' - 1;
- for i in 33..=stop {
- assert!(printable.contains(i));
- }
- let stop2 = b'\\' - 1;
- for i in stop + 2..=stop2 {
- assert!(printable.contains(i));
- }
- for i in stop2 + 2..=b'~' {
- assert!(printable.contains(i));
- }
- let rfc = RFC5322_ATEXT;
- assert!(rfc.len() == 81);
- for i in b'A'..=b'Z' {
- assert!(rfc.contains(i));
- }
- for i in b'a'..=b'z' {
- assert!(rfc.contains(i));
- }
- for i in b'0'..=b'9' {
- assert!(rfc.contains(i));
- }
- assert!(rfc.contains(b'!'));
- assert!(rfc.contains(b'#'));
- assert!(rfc.contains(b'$'));
- assert!(rfc.contains(b'%'));
- assert!(rfc.contains(b'&'));
- assert!(rfc.contains(b'\''));
- assert!(rfc.contains(b'*'));
- assert!(rfc.contains(b'+'));
- assert!(rfc.contains(b'-'));
- assert!(rfc.contains(b'/'));
- assert!(rfc.contains(b'='));
- assert!(rfc.contains(b'?'));
- assert!(rfc.contains(b'^'));
- assert!(rfc.contains(b'_'));
- assert!(rfc.contains(b'`'));
- assert!(rfc.contains(b'{'));
- assert!(rfc.contains(b'|'));
- assert!(rfc.contains(b'}'));
- assert!(rfc.contains(b'~'));
- let whatwg = WHATWG_VALID_DOMAIN_CODE_POINTS;
- for i in 0..=0x1f {
- assert!(!whatwg.contains(i));
- }
- assert!(!whatwg.contains(b'\x20'));
- assert!(!whatwg.contains(b'#'));
- assert!(!whatwg.contains(b'/'));
- assert!(!whatwg.contains(b':'));
- assert!(!whatwg.contains(b'<'));
- assert!(!whatwg.contains(b'>'));
- assert!(!whatwg.contains(b'?'));
- assert!(!whatwg.contains(b'@'));
- assert!(!whatwg.contains(b'['));
- assert!(!whatwg.contains(b'\\'));
- assert!(!whatwg.contains(b']'));
- assert!(!whatwg.contains(b'^'));
- assert!(!whatwg.contains(b'|'));
- assert!(!whatwg.contains(b'%'));
- assert!(!whatwg.contains(b'\x7f'));
- assert!(!whatwg.contains(b'.'));
- assert!(whatwg.len() == 128 - 32 - 16);
- }
-}
diff --git a/src/char_set/tests.rs b/src/char_set/tests.rs
@@ -0,0 +1,231 @@
+extern crate alloc;
+use super::{
+ ASCII_DIGITS, ASCII_DIGITS_LETTERS, ASCII_DIGITS_LOWERCASE, ASCII_DIGITS_UPPERCASE,
+ ASCII_FIREFOX, ASCII_HYPHEN_DIGITS_LETTERS, ASCII_HYPHEN_DIGITS_LOWERCASE,
+ ASCII_HYPHEN_DIGITS_UPPERCASE, ASCII_LETTERS, ASCII_LOWERCASE, ASCII_UPPERCASE, AllowedAscii,
+ AsciiErr, PRINTABLE_ASCII, RFC5322_ATEXT, WHATWG_VALID_DOMAIN_CODE_POINTS,
+};
+use alloc::{borrow::ToOwned as _, vec::Vec};
+#[test]
+fn try_from() {
+ // Empty is allowed.
+ assert_eq!(
+ AllowedAscii::try_from_unique_ascii([]),
+ Ok(AllowedAscii { allowed: [] })
+ );
+ // Duplicates are not allowed.
+ assert_eq!(
+ AllowedAscii::try_from_unique_ascii(b"aba".to_owned()),
+ Err(AsciiErr::Duplicate(b'a'))
+ );
+ // `b'.'` is not allowed.
+ assert_eq!(
+ AllowedAscii::try_from_unique_ascii(b"a.c".to_owned()),
+ Err(AsciiErr::Contains46)
+ );
+ // At most 127 bytes are allowed.
+ assert_eq!(
+ AllowedAscii::try_from_unique_ascii([0; 128]),
+ Err(AsciiErr::CountTooLarge(128))
+ );
+ let mut all_ascii = (0..b'.').collect::<Vec<u8>>();
+ let next = b'.' + 1;
+ all_ascii.extend(next..=127);
+ assert_eq!(
+ AllowedAscii::try_from_unique_ascii(all_ascii.clone()),
+ Ok(AllowedAscii { allowed: all_ascii })
+ );
+ // Only ASCII is allowed.
+ assert_eq!(
+ AllowedAscii::try_from_unique_ascii([255]),
+ Err(AsciiErr::InvalidByte(255))
+ );
+ assert!(
+ AllowedAscii::try_from_unique_ascii(b"abcdef".to_owned()).is_ok_and(|bytes| bytes
+ .as_inner()
+ .contains(&b'a')
+ && bytes.contains(b'b')
+ && bytes.contains(b'c')
+ && bytes.contains(b'd')
+ && bytes.contains(b'e')
+ && bytes.contains(b'f'))
+ );
+}
+#[expect(
+ clippy::cognitive_complexity,
+ clippy::too_many_lines,
+ reason = "want to test a lot of things"
+)]
+#[test]
+fn consts() {
+ let letters = ASCII_LETTERS;
+ assert_eq!(letters.len(), 52);
+ for i in b'A'..=b'Z' {
+ assert!(letters.contains(i));
+ }
+ for i in b'a'..=b'z' {
+ assert!(letters.contains(i));
+ }
+ let digits = ASCII_DIGITS;
+ assert_eq!(digits.len(), 10);
+ for i in b'0'..=b'9' {
+ assert!(digits.contains(i));
+ }
+ let lower = ASCII_LOWERCASE;
+ assert_eq!(lower.len(), 26);
+ for i in b'a'..=b'z' {
+ assert!(lower.contains(i));
+ }
+ let upper = ASCII_UPPERCASE;
+ assert_eq!(upper.len(), 26);
+ for i in b'A'..=b'Z' {
+ assert!(upper.contains(i));
+ }
+ let dig_let = ASCII_DIGITS_LETTERS;
+ assert_eq!(dig_let.len(), 62);
+ for i in b'a'..=b'z' {
+ assert!(dig_let.contains(i));
+ }
+ for i in b'0'..=b'9' {
+ assert!(dig_let.contains(i));
+ }
+ for i in b'A'..=b'Z' {
+ assert!(dig_let.contains(i));
+ }
+ let dig_lower = ASCII_DIGITS_LOWERCASE;
+ assert_eq!(dig_lower.len(), 36);
+ for i in b'a'..=b'z' {
+ assert!(dig_lower.contains(i));
+ }
+ for i in b'0'..=b'9' {
+ assert!(dig_lower.contains(i));
+ }
+ let dig_upper = ASCII_DIGITS_UPPERCASE;
+ assert_eq!(dig_upper.len(), 36);
+ for i in b'A'..=b'Z' {
+ assert!(dig_upper.contains(i));
+ }
+ for i in b'0'..=b'9' {
+ assert!(dig_upper.contains(i));
+ }
+ let ffox = ASCII_FIREFOX;
+ assert_eq!(ffox.len(), 78);
+ for i in b'A'..=b'Z' {
+ assert!(ffox.contains(i));
+ }
+ for i in b'a'..=b'z' {
+ assert!(ffox.contains(i));
+ }
+ for i in b'0'..=b'9' {
+ assert!(ffox.contains(i));
+ }
+ assert!(ffox.contains(b'!'));
+ assert!(ffox.contains(b'$'));
+ assert!(ffox.contains(b'&'));
+ assert!(ffox.contains(b'\''));
+ assert!(ffox.contains(b'('));
+ assert!(ffox.contains(b')'));
+ assert!(ffox.contains(b'+'));
+ assert!(ffox.contains(b','));
+ assert!(ffox.contains(b'-'));
+ assert!(ffox.contains(b';'));
+ assert!(ffox.contains(b'='));
+ assert!(ffox.contains(b'_'));
+ assert!(ffox.contains(b'`'));
+ assert!(ffox.contains(b'{'));
+ assert!(ffox.contains(b'}'));
+ assert!(ffox.contains(b'~'));
+ assert_eq!(ASCII_HYPHEN_DIGITS_LETTERS.len(), 63);
+ assert!(ASCII_HYPHEN_DIGITS_LETTERS.contains(b'-'));
+ for i in b'A'..=b'Z' {
+ assert!(ASCII_HYPHEN_DIGITS_LETTERS.contains(i));
+ }
+ for i in b'a'..=b'z' {
+ assert!(ASCII_HYPHEN_DIGITS_LETTERS.contains(i));
+ }
+ for i in b'0'..=b'9' {
+ assert!(ASCII_HYPHEN_DIGITS_LETTERS.contains(i));
+ }
+ let hyp_lower = ASCII_HYPHEN_DIGITS_LOWERCASE;
+ assert_eq!(hyp_lower.len(), 37);
+ assert!(hyp_lower.contains(b'-'));
+ for i in b'a'..=b'z' {
+ assert!(hyp_lower.contains(i));
+ }
+ for i in b'0'..=b'9' {
+ assert!(hyp_lower.contains(i));
+ }
+ let hyp_upper = ASCII_HYPHEN_DIGITS_UPPERCASE;
+ assert_eq!(hyp_upper.len(), 37);
+ assert!(hyp_upper.contains(b'-'));
+ for i in b'A'..=b'Z' {
+ assert!(hyp_upper.contains(i));
+ }
+ for i in b'0'..=b'9' {
+ assert!(hyp_upper.contains(i));
+ }
+ let printable = PRINTABLE_ASCII;
+ assert_eq!(printable.len(), 92);
+ let stop = b'.' - 1;
+ for i in 33..=stop {
+ assert!(printable.contains(i));
+ }
+ let stop2 = b'\\' - 1;
+ for i in stop + 2..=stop2 {
+ assert!(printable.contains(i));
+ }
+ for i in stop2 + 2..=b'~' {
+ assert!(printable.contains(i));
+ }
+ let rfc = RFC5322_ATEXT;
+ assert_eq!(rfc.len(), 81);
+ for i in b'A'..=b'Z' {
+ assert!(rfc.contains(i));
+ }
+ for i in b'a'..=b'z' {
+ assert!(rfc.contains(i));
+ }
+ for i in b'0'..=b'9' {
+ assert!(rfc.contains(i));
+ }
+ assert!(rfc.contains(b'!'));
+ assert!(rfc.contains(b'#'));
+ assert!(rfc.contains(b'$'));
+ assert!(rfc.contains(b'%'));
+ assert!(rfc.contains(b'&'));
+ assert!(rfc.contains(b'\''));
+ assert!(rfc.contains(b'*'));
+ assert!(rfc.contains(b'+'));
+ assert!(rfc.contains(b'-'));
+ assert!(rfc.contains(b'/'));
+ assert!(rfc.contains(b'='));
+ assert!(rfc.contains(b'?'));
+ assert!(rfc.contains(b'^'));
+ assert!(rfc.contains(b'_'));
+ assert!(rfc.contains(b'`'));
+ assert!(rfc.contains(b'{'));
+ assert!(rfc.contains(b'|'));
+ assert!(rfc.contains(b'}'));
+ assert!(rfc.contains(b'~'));
+ let whatwg = WHATWG_VALID_DOMAIN_CODE_POINTS;
+ for i in 0..=0x1f {
+ assert!(!whatwg.contains(i));
+ }
+ assert!(!whatwg.contains(b'\x20'));
+ assert!(!whatwg.contains(b'#'));
+ assert!(!whatwg.contains(b'/'));
+ assert!(!whatwg.contains(b':'));
+ assert!(!whatwg.contains(b'<'));
+ assert!(!whatwg.contains(b'>'));
+ assert!(!whatwg.contains(b'?'));
+ assert!(!whatwg.contains(b'@'));
+ assert!(!whatwg.contains(b'['));
+ assert!(!whatwg.contains(b'\\'));
+ assert!(!whatwg.contains(b']'));
+ assert!(!whatwg.contains(b'^'));
+ assert!(!whatwg.contains(b'|'));
+ assert!(!whatwg.contains(b'%'));
+ assert!(!whatwg.contains(b'\x7f'));
+ assert!(!whatwg.contains(b'.'));
+ assert_eq!(whatwg.len(), 128 - 32 - 16);
+}
diff --git a/src/dom.rs b/src/dom.rs
@@ -1,4 +1,7 @@
extern crate alloc;
+#[cfg(test)]
+/// Unit tests.
+mod tests;
use crate::char_set::{ASCII_HYPHEN_DIGITS_LETTERS, AllowedAscii};
use alloc::{string::String, vec::Vec};
use core::{
@@ -1505,341 +1508,3 @@ impl<'a> IntoIterator for Rfc1123Domain<&'a [u8]> {
}
}
}
-#[cfg(test)]
-mod tests {
- extern crate alloc;
- use super::{Domain, DomainErr, Rfc1123Domain, Rfc1123Err};
- use crate::char_set::{ASCII_FIREFOX, ASCII_HYPHEN_DIGITS_LETTERS, AllowedAscii};
- use alloc::borrow::ToOwned as _;
- use core::cmp::Ordering;
- use serde_json as _;
- #[test]
- fn dom_parse() {
- let allowed_ascii = ASCII_FIREFOX;
- // Test empty is error.
- assert!(
- Domain::try_from_bytes("", &allowed_ascii)
- .map_or_else(|e| e == DomainErr::Empty, |_| false)
- );
- // Test root domain.
- assert!(
- Domain::try_from_bytes(".", &allowed_ascii)
- .map_or_else(|e| e == DomainErr::RootDomain, |_| false)
- );
- // Test empty label is error.
- assert!(
- Domain::try_from_bytes("a..com", &allowed_ascii)
- .map_or_else(|e| e == DomainErr::EmptyLabel, |_| false)
- );
- assert!(
- Domain::try_from_bytes("a..", &allowed_ascii)
- .map_or_else(|e| e == DomainErr::EmptyLabel, |_| false)
- );
- assert!(
- Domain::try_from_bytes("..", &allowed_ascii)
- .map_or_else(|e| e == DomainErr::EmptyLabel, |_| false)
- );
- // Test label too long.
- let val = "www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com";
- // 4 + 64 + 4
- assert!(val.len() == 72);
- assert!(
- Domain::try_from_bytes(val, &allowed_ascii)
- .map_or_else(|e| e == DomainErr::LabelLenExceeds63, |_| false)
- );
- assert!(
- Domain::try_from_bytes(
- "www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
- &allowed_ascii
- )
- .is_ok_and(|d| d.len().get() == 71)
- );
- // Test domain too long.
- assert!(Domain::try_from_bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", &allowed_ascii).is_err_and(|e| e == DomainErr::LenExceeds253(254)));
- assert!(Domain::try_from_bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", &allowed_ascii).is_ok_and(|d| d.len().get() == 253 ));
- // Test max labels.
- assert!(Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a", &allowed_ascii).is_err_and(|e| e == DomainErr::LenExceeds253(255)));
- assert!(Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a", &allowed_ascii).is_ok_and(|d| d.iter().count() == 127 && d.len().get() == 253));
- assert!(Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.", &allowed_ascii).is_ok_and(|d| d.iter().count() == 127 && d.len().get() == 253));
- // Test removal of trailing '.'.
- assert!(Domain::try_from_bytes("com.", &allowed_ascii).is_ok_and(|d| d.as_str() == "com"));
- // Test single label.
- assert!(Domain::try_from_bytes("c", &allowed_ascii).is_ok_and(|d| d.as_str() == "c"));
- // Test case-insensitivity.
- assert!(
- Domain::try_from_bytes("wwW.ExAMple.COm", &allowed_ascii).is_ok_and(|d| {
- Domain::try_from_bytes("www.example.com", &allowed_ascii)
- .is_ok_and(|d2| d == d2 && d.cmp(&d2) == Ordering::Equal)
- })
- );
- assert!(
- Domain::try_from_bytes("ww_W.com", &allowed_ascii).is_ok_and(|d| {
- Domain::try_from_bytes("Ww_w.com", &allowed_ascii)
- .is_ok_and(|d2| d == d2 && d.cmp(&d2) == Ordering::Equal)
- })
- );
- // Test valid bytes
- let mut input;
- let mut counter = 0u8;
- for i in 0..=127 {
- input = [i];
- match i {
- b'!'
- | b'$'
- | b'&'..=b')'
- | b'+'..=b'-'
- | b'0'..=b'9'
- | b';'
- | b'='
- | b'A'..=b'Z'
- | b'_'..=b'{'
- | b'}'..=b'~' => {
- counter += 1;
- assert!(
- Domain::try_from_bytes(input, &allowed_ascii)
- .is_ok_and(|d| d.value.len() == 1 && d.value == input)
- );
- }
- b'.' => {
- let input2 = b"a.";
- assert!(
- Domain::try_from_bytes(input2, &allowed_ascii)
- .is_ok_and(|d| d.len().get() == 1 && d.value == input2)
- );
- }
- _ => assert!(
- Domain::try_from_bytes(input, &allowed_ascii)
- .is_err_and(|e| e == DomainErr::InvalidByte(i))
- ),
- }
- }
- assert!(counter == 78);
- }
- #[test]
- fn dom_iter() {
- let allowed_ascii = ASCII_FIREFOX;
- assert!(
- Domain::try_from_bytes("www.example.com", &allowed_ascii).is_ok_and(|d| {
- let mut iter = d.iter();
- let Some(l) = iter.next() else {
- return false;
- };
- if l.value != "com" {
- return false;
- }
- let Some(l2) = iter.next() else { return false };
- if l2.value != "example" {
- return false;
- }
- let Some(l3) = iter.next() else {
- return false;
- };
- if l3.value != "www" {
- return false;
- }
- iter.next().is_none()
- })
- );
- assert!(
- Domain::try_from_bytes("www.example.com", &allowed_ascii).is_ok_and(|d| {
- let mut iter = d.iter();
- let Some(l) = iter.next_back() else {
- return false;
- };
- if l.value != "www" {
- return false;
- }
- let Some(l2) = iter.next_back() else {
- return false;
- };
- if l2.value != "example" {
- return false;
- }
- let Some(l3) = iter.next_back() else {
- return false;
- };
- if l3.value != "com" {
- return false;
- }
- iter.next_back().is_none()
- })
- );
- assert!(
- Domain::try_from_bytes("www.example.com", &allowed_ascii).is_ok_and(|d| {
- let mut iter = d.iter();
- let Some(l) = iter.next_back() else {
- return false;
- };
- if l.value != "www" {
- return false;
- }
- let Some(l2) = iter.next() else { return false };
- if l2.value != "com" {
- return false;
- }
- let Some(l3) = iter.next_back() else {
- return false;
- };
- if l3.value != "example" {
- return false;
- }
- iter.next().is_none() && iter.next_back().is_none()
- })
- );
- }
- #[test]
- fn rfc1123() {
- assert!(
- Domain::try_from_bytes("example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
- .is_ok_and(|rfc_dom| rfc_dom.as_str() == "example.com"))
- );
- assert!(
- AllowedAscii::try_from_unique_ascii(b"exampl!co".to_owned()).is_ok_and(|ascii| {
- Domain::try_from_bytes("exampl!e.com", &ascii).is_ok_and(|dom| {
- Rfc1123Domain::try_from(dom)
- .is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::InvalidByte(b'!')))
- })
- })
- );
- assert!(
- Domain::try_from_bytes("example-.com", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
- .is_err_and(|e| e == Rfc1123Err::LabelEndsWithAHyphen))
- );
- assert!(
- Domain::try_from_bytes("-example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
- .is_err_and(|e| e == Rfc1123Err::LabelStartsWithAHyphen))
- );
- assert!(
- Domain::try_from_bytes("example.c1m", &ASCII_HYPHEN_DIGITS_LETTERS).is_ok_and(|dom| {
- Rfc1123Domain::try_from(dom).is_err_and(|e| e == Rfc1123Err::InvalidTld)
- })
- );
- assert!(
- Domain::try_from_bytes("example.commm", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
- .is_ok_and(|rfc| rfc.is_literal_interpretation()))
- );
- assert!(
- Domain::try_from_bytes("example.xn--abc", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
- .is_ok_and(|rfc| !rfc.is_literal_interpretation()))
- );
- assert!(
- Domain::try_from_bytes("example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
- .is_ok_and(|rfc| rfc.is_strict_interpretation()))
- );
- assert!(
- Domain::try_from_bytes("example.comm", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
- .is_ok_and(|rfc| !rfc.is_strict_interpretation()))
- );
- }
- #[test]
- fn tld() {
- assert!(
- Domain::try_from_bytes("example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| dom.tld().as_str() == "com",)
- );
- }
- #[expect(clippy::cognitive_complexity, reason = "want to test many things")]
- #[test]
- fn rfc1123_parse() {
- // Test empty is error.
- assert!(
- Rfc1123Domain::try_from_bytes("")
- .is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::Empty))
- );
- // Test root domain.
- assert!(
- Rfc1123Domain::try_from_bytes(".")
- .is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::RootDomain))
- );
- // Test empty label is error.
- assert!(
- Rfc1123Domain::try_from_bytes("a..com")
- .is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::EmptyLabel))
- );
- assert!(
- Rfc1123Domain::try_from_bytes("a..")
- .is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::EmptyLabel))
- );
- assert!(
- Rfc1123Domain::try_from_bytes("..")
- .is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::EmptyLabel))
- );
- // Test label too long.
- let val = "www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com";
- // 4 + 64 + 4
- assert!(val.len() == 72);
- assert!(
- Rfc1123Domain::try_from_bytes(val)
- .is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::LabelLenExceeds63),)
- );
- assert!(
- Rfc1123Domain::try_from_bytes(
- "www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
- )
- .is_ok_and(|d| d.len().get() == 71)
- );
- // Test domain too long.
- assert!(Rfc1123Domain::try_from_bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::LenExceeds253(254))));
- assert!(Rfc1123Domain::try_from_bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").is_ok_and(|d| d.len().get() == 253 ));
- // Test max labels.
- assert!(Rfc1123Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::LenExceeds253(255))));
- assert!(Rfc1123Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").is_ok_and(|d| d.iter().count() == 127 && d.len().get() == 253));
- assert!(Rfc1123Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.").is_ok_and(|d| d.iter().count() == 127 && d.len().get() == 253));
- // Test removal of trailing '.'.
- assert!(Rfc1123Domain::try_from_bytes("com.").is_ok_and(|d| d.as_str() == "com"));
- // Test single label.
- assert!(Rfc1123Domain::try_from_bytes("c").is_ok_and(|d| d.as_str() == "c"));
- // Test ends with hyphen.
- assert!(
- Rfc1123Domain::try_from_bytes("-")
- .map_or_else(|err| err == Rfc1123Err::LabelEndsWithAHyphen, |_| false)
- );
- assert!(
- Rfc1123Domain::try_from_bytes("-.")
- .map_or_else(|err| err == Rfc1123Err::LabelEndsWithAHyphen, |_| false)
- );
- assert!(
- Rfc1123Domain::try_from_bytes("a.com.-")
- .map_or_else(|err| err == Rfc1123Err::LabelEndsWithAHyphen, |_| false)
- );
- assert!(
- Rfc1123Domain::try_from_bytes("a.com-")
- .map_or_else(|err| err == Rfc1123Err::LabelEndsWithAHyphen, |_| false)
- );
- assert!(
- Rfc1123Domain::try_from_bytes("a-.com")
- .map_or_else(|err| err == Rfc1123Err::LabelEndsWithAHyphen, |_| false)
- );
- // Test starts with hyphen.
- assert!(
- Rfc1123Domain::try_from_bytes("a.-com")
- .map_or_else(|err| err == Rfc1123Err::LabelStartsWithAHyphen, |_| false)
- );
- assert!(
- Rfc1123Domain::try_from_bytes("-a.com")
- .map_or_else(|err| err == Rfc1123Err::LabelStartsWithAHyphen, |_| false)
- );
- // Test case-insensitivity.
- assert!(
- Rfc1123Domain::try_from_bytes("wwW.ExAMple.COm").is_ok_and(|d| {
- Rfc1123Domain::try_from_bytes("www.example.com")
- .is_ok_and(|d2| d == d2 && d.cmp(&d2) == Ordering::Equal)
- })
- );
- assert!(Rfc1123Domain::try_from_bytes("ww-W.com").is_ok_and(|d| {
- Rfc1123Domain::try_from_bytes("Ww-w.com")
- .is_ok_and(|d2| d == d2 && d.cmp(&d2) == Ordering::Equal)
- }));
- assert!(
- Rfc1123Domain::try_from_bytes("1.1.1.1")
- .map_or_else(|err| err == Rfc1123Err::InvalidTld, |_| false)
- );
- }
-}
diff --git a/src/dom/tests.rs b/src/dom/tests.rs
@@ -0,0 +1,357 @@
+extern crate alloc;
+use super::{Domain, DomainErr, Rfc1123Domain, Rfc1123Err};
+use crate::char_set::{ASCII_FIREFOX, ASCII_HYPHEN_DIGITS_LETTERS, AllowedAscii};
+use alloc::borrow::ToOwned as _;
+use core::cmp::Ordering;
+use serde_json as _;
+#[test]
+fn dom_parse() {
+ let allowed_ascii = ASCII_FIREFOX;
+ // Test empty is error.
+ assert_eq!(
+ Domain::try_from_bytes("", &allowed_ascii),
+ Err(DomainErr::Empty)
+ );
+ // Test root domain.
+ assert_eq!(
+ Domain::try_from_bytes(".", &allowed_ascii),
+ Err(DomainErr::RootDomain)
+ );
+ // Test empty label is error.
+ assert_eq!(
+ Domain::try_from_bytes("a..com", &allowed_ascii),
+ Err(DomainErr::EmptyLabel)
+ );
+ assert_eq!(
+ Domain::try_from_bytes("a..", &allowed_ascii),
+ Err(DomainErr::EmptyLabel)
+ );
+ assert_eq!(
+ Domain::try_from_bytes("..", &allowed_ascii),
+ Err(DomainErr::EmptyLabel)
+ );
+ // Test label too long.
+ let val = "www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com";
+ // 4 + 64 + 4
+ assert_eq!(val.len(), 72);
+ assert_eq!(
+ Domain::try_from_bytes(val, &allowed_ascii),
+ Err(DomainErr::LabelLenExceeds63)
+ );
+ assert!(
+ Domain::try_from_bytes(
+ "www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
+ &allowed_ascii
+ )
+ .is_ok_and(|d| d.len().get() == 71)
+ );
+ // Test domain too long.
+ assert_eq!(
+ Domain::try_from_bytes(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ &allowed_ascii
+ ),
+ Err(DomainErr::LenExceeds253(254))
+ );
+ assert!(Domain::try_from_bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", &allowed_ascii).is_ok_and(|d| d.len().get() == 253 ));
+ // Test max labels.
+ assert_eq!(
+ Domain::try_from_bytes(
+ "a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a",
+ &allowed_ascii
+ ),
+ Err(DomainErr::LenExceeds253(255))
+ );
+ assert!(Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a", &allowed_ascii).is_ok_and(|d| d.iter().count() == 127 && d.len().get() == 253));
+ assert!(Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.", &allowed_ascii).is_ok_and(|d| d.iter().count() == 127 && d.len().get() == 253));
+ // Test removal of trailing '.'.
+ assert!(Domain::try_from_bytes("com.", &allowed_ascii).is_ok_and(|d| d.as_str() == "com"));
+ // Test single label.
+ assert!(Domain::try_from_bytes("c", &allowed_ascii).is_ok_and(|d| d.as_str() == "c"));
+ // Test case-insensitivity.
+ assert!(
+ Domain::try_from_bytes("wwW.ExAMple.COm", &allowed_ascii).is_ok_and(|d| {
+ Domain::try_from_bytes("www.example.com", &allowed_ascii)
+ .is_ok_and(|d2| d == d2 && d.cmp(&d2) == Ordering::Equal)
+ })
+ );
+ assert!(
+ Domain::try_from_bytes("ww_W.com", &allowed_ascii).is_ok_and(|d| {
+ Domain::try_from_bytes("Ww_w.com", &allowed_ascii)
+ .is_ok_and(|d2| d == d2 && d.cmp(&d2) == Ordering::Equal)
+ })
+ );
+ // Test valid bytes
+ let mut input;
+ let mut counter = 0u8;
+ for i in 0..=127 {
+ input = [i];
+ match i {
+ b'!'
+ | b'$'
+ | b'&'..=b')'
+ | b'+'..=b'-'
+ | b'0'..=b'9'
+ | b';'
+ | b'='
+ | b'A'..=b'Z'
+ | b'_'..=b'{'
+ | b'}'..=b'~' => {
+ counter += 1;
+ assert!(
+ Domain::try_from_bytes(input, &allowed_ascii)
+ .is_ok_and(|d| d.value.len() == 1 && d.value == input)
+ );
+ }
+ b'.' => {
+ let input2 = b"a.";
+ assert!(
+ Domain::try_from_bytes(input2, &allowed_ascii)
+ .is_ok_and(|d| d.len().get() == 1 && d.value == input2)
+ );
+ }
+ _ => assert_eq!(
+ Domain::try_from_bytes(input, &allowed_ascii),
+ Err(DomainErr::InvalidByte(i))
+ ),
+ }
+ }
+ assert_eq!(counter, 78);
+}
+#[test]
+fn dom_iter() {
+ let allowed_ascii = ASCII_FIREFOX;
+ assert!(
+ Domain::try_from_bytes("www.example.com", &allowed_ascii).is_ok_and(|d| {
+ let mut iter = d.iter();
+ let Some(l) = iter.next() else {
+ return false;
+ };
+ if l.value != "com" {
+ return false;
+ }
+ let Some(l2) = iter.next() else { return false };
+ if l2.value != "example" {
+ return false;
+ }
+ let Some(l3) = iter.next() else {
+ return false;
+ };
+ if l3.value != "www" {
+ return false;
+ }
+ iter.next().is_none()
+ })
+ );
+ assert!(
+ Domain::try_from_bytes("www.example.com", &allowed_ascii).is_ok_and(|d| {
+ let mut iter = d.iter();
+ let Some(l) = iter.next_back() else {
+ return false;
+ };
+ if l.value != "www" {
+ return false;
+ }
+ let Some(l2) = iter.next_back() else {
+ return false;
+ };
+ if l2.value != "example" {
+ return false;
+ }
+ let Some(l3) = iter.next_back() else {
+ return false;
+ };
+ if l3.value != "com" {
+ return false;
+ }
+ iter.next_back().is_none()
+ })
+ );
+ assert!(
+ Domain::try_from_bytes("www.example.com", &allowed_ascii).is_ok_and(|d| {
+ let mut iter = d.iter();
+ let Some(l) = iter.next_back() else {
+ return false;
+ };
+ if l.value != "www" {
+ return false;
+ }
+ let Some(l2) = iter.next() else { return false };
+ if l2.value != "com" {
+ return false;
+ }
+ let Some(l3) = iter.next_back() else {
+ return false;
+ };
+ if l3.value != "example" {
+ return false;
+ }
+ iter.next().is_none() && iter.next_back().is_none()
+ })
+ );
+}
+#[test]
+fn rfc1123() {
+ assert!(
+ Domain::try_from_bytes("example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
+ .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
+ .is_ok_and(|rfc_dom| rfc_dom.as_str() == "example.com"))
+ );
+ assert!(
+ AllowedAscii::try_from_unique_ascii(b"exampl!co".to_owned()).is_ok_and(|ascii| {
+ Domain::try_from_bytes("exampl!e.com", &ascii).is_ok_and(|dom| {
+ Rfc1123Domain::try_from(dom)
+ .is_err_and(|e| e == Rfc1123Err::DomainErr(DomainErr::InvalidByte(b'!')))
+ })
+ })
+ );
+ assert!(
+ Domain::try_from_bytes("example-.com", &ASCII_HYPHEN_DIGITS_LETTERS)
+ .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
+ .is_err_and(|e| e == Rfc1123Err::LabelEndsWithAHyphen))
+ );
+ assert!(
+ Domain::try_from_bytes("-example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
+ .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
+ .is_err_and(|e| e == Rfc1123Err::LabelStartsWithAHyphen))
+ );
+ assert!(
+ Domain::try_from_bytes("example.c1m", &ASCII_HYPHEN_DIGITS_LETTERS).is_ok_and(|dom| {
+ Rfc1123Domain::try_from(dom).is_err_and(|e| e == Rfc1123Err::InvalidTld)
+ })
+ );
+ assert!(
+ Domain::try_from_bytes("example.commm", &ASCII_HYPHEN_DIGITS_LETTERS).is_ok_and(|dom| {
+ Rfc1123Domain::try_from(dom).is_ok_and(|rfc| rfc.is_literal_interpretation())
+ })
+ );
+ assert!(
+ Domain::try_from_bytes("example.xn--abc", &ASCII_HYPHEN_DIGITS_LETTERS)
+ .is_ok_and(|dom| Rfc1123Domain::try_from(dom)
+ .is_ok_and(|rfc| !rfc.is_literal_interpretation()))
+ );
+ assert!(
+ Domain::try_from_bytes("example.com", &ASCII_HYPHEN_DIGITS_LETTERS).is_ok_and(|dom| {
+ Rfc1123Domain::try_from(dom).is_ok_and(|rfc| rfc.is_strict_interpretation())
+ })
+ );
+ assert!(
+ Domain::try_from_bytes("example.comm", &ASCII_HYPHEN_DIGITS_LETTERS).is_ok_and(|dom| {
+ Rfc1123Domain::try_from(dom).is_ok_and(|rfc| !rfc.is_strict_interpretation())
+ })
+ );
+}
+#[test]
+fn tld() {
+ assert!(
+ Domain::try_from_bytes("example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
+ .is_ok_and(|dom| dom.tld().as_str() == "com",)
+ );
+}
+#[expect(clippy::cognitive_complexity, reason = "want to test many things")]
+#[test]
+fn rfc1123_parse() {
+ // Test empty is error.
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes(""),
+ Err(Rfc1123Err::DomainErr(DomainErr::Empty))
+ );
+ // Test root domain.
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("."),
+ Err(Rfc1123Err::DomainErr(DomainErr::RootDomain))
+ );
+ // Test empty label is error.
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("a..com"),
+ Err(Rfc1123Err::DomainErr(DomainErr::EmptyLabel))
+ );
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("a.."),
+ Err(Rfc1123Err::DomainErr(DomainErr::EmptyLabel))
+ );
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes(".."),
+ Err(Rfc1123Err::DomainErr(DomainErr::EmptyLabel))
+ );
+ // Test label too long.
+ let val = "www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com";
+ // 4 + 64 + 4
+ assert_eq!(val.len(), 72);
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes(val),
+ Err(Rfc1123Err::DomainErr(DomainErr::LabelLenExceeds63),)
+ );
+ assert!(
+ Rfc1123Domain::try_from_bytes(
+ "www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
+ )
+ .is_ok_and(|d| d.len().get() == 71)
+ );
+ // Test domain too long.
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ ),
+ Err(Rfc1123Err::DomainErr(DomainErr::LenExceeds253(254)))
+ );
+ assert!(Rfc1123Domain::try_from_bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").is_ok_and(|d| d.len().get() == 253 ));
+ // Test max labels.
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes(
+ "a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a"
+ ),
+ Err(Rfc1123Err::DomainErr(DomainErr::LenExceeds253(255)))
+ );
+ assert!(Rfc1123Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").is_ok_and(|d| d.iter().count() == 127 && d.len().get() == 253));
+ assert!(Rfc1123Domain::try_from_bytes("a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.").is_ok_and(|d| d.iter().count() == 127 && d.len().get() == 253));
+ // Test removal of trailing '.'.
+ assert!(Rfc1123Domain::try_from_bytes("com.").is_ok_and(|d| d.as_str() == "com"));
+ // Test single label.
+ assert!(Rfc1123Domain::try_from_bytes("c").is_ok_and(|d| *d.as_inner() == "c"));
+ // Test ends with hyphen.
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("-"),
+ Err(Rfc1123Err::LabelEndsWithAHyphen)
+ );
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("-."),
+ Err(Rfc1123Err::LabelEndsWithAHyphen)
+ );
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("a.com.-"),
+ Err(Rfc1123Err::LabelEndsWithAHyphen)
+ );
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("a.com-"),
+ Err(Rfc1123Err::LabelEndsWithAHyphen)
+ );
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("a-.com"),
+ Err(Rfc1123Err::LabelEndsWithAHyphen)
+ );
+ // Test starts with hyphen.
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("a.-com"),
+ Err(Rfc1123Err::LabelStartsWithAHyphen)
+ );
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("-a.com"),
+ Err(Rfc1123Err::LabelStartsWithAHyphen)
+ );
+ // Test case-insensitivity.
+ assert!(
+ Rfc1123Domain::try_from_bytes("wwW.ExAMple.COm").is_ok_and(|d| {
+ Rfc1123Domain::try_from_bytes("www.example.com")
+ .is_ok_and(|d2| d == d2 && d.cmp(&d2) == Ordering::Equal)
+ })
+ );
+ assert!(Rfc1123Domain::try_from_bytes("ww-W.com").is_ok_and(|d| {
+ Rfc1123Domain::try_from_bytes("Ww-w.com")
+ .is_ok_and(|d2| d.domain() == d2.domain() && d.cmp(&d2) == Ordering::Equal)
+ }));
+ assert_eq!(
+ Rfc1123Domain::try_from_bytes("1.1.1.1"),
+ Err(Rfc1123Err::InvalidTld)
+ );
+}
diff --git a/src/serde.rs b/src/serde.rs
@@ -1,4 +1,7 @@
extern crate alloc;
+#[cfg(test)]
+/// Unit tests.
+mod tests;
use crate::{
char_set::{AllowedAscii, PRINTABLE_ASCII},
dom::{Domain, DomainErr, Rfc1123Domain, Rfc1123Err},
@@ -233,51 +236,3 @@ impl<'de: 'a, 'a> Deserialize<'de> for Rfc1123Domain<&'a str> {
deserializer.deserialize_str(Rfc1123Visitor::<&'a str>(PhantomData))
}
}
-#[cfg(test)]
-mod tests {
- extern crate alloc;
- use crate::{
- char_set::ASCII_HYPHEN_DIGITS_LETTERS,
- dom::{Domain, Rfc1123Domain},
- };
- use alloc::string::String;
- #[test]
- fn serde() {
- assert!(
- serde_json::from_str::<Domain<&str>>(r#""example.com""#)
- .is_ok_and(|dom| dom.into_iter().count() == 2)
- );
- assert!(
- serde_json::from_str::<Domain<String>>(r#""c\"om""#)
- .is_ok_and(|dom| dom.into_iter().count() == 1)
- );
- // Can't borrow since input needs to be de-escaped.
- assert!(
- serde_json::from_str::<Domain<&str>>(r#""c\"om""#)
- .is_err_and(|err| err.is_data() && err.column() == 7)
- );
- assert!(
- Domain::try_from_bytes("example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| serde_json::to_string(&dom)
- .is_ok_and(|output| output == r#""example.com""#))
- );
- assert!(
- Domain::try_from_bytes(b"example.com", &ASCII_HYPHEN_DIGITS_LETTERS)
- .is_ok_and(|dom| serde_json::to_string(&dom)
- .is_ok_and(|output| output == r#""example.com""#))
- );
- assert!(
- serde_json::from_str::<Rfc1123Domain<&str>>(r#""example.com""#)
- .is_ok_and(|dom| dom.into_iter().count() == 2)
- );
- assert!(
- serde_json::from_str::<Rfc1123Domain<String>>(r#""c\u006fm""#)
- .is_ok_and(|dom| dom.tld().as_str() == "com")
- );
- // Can't borrow since input needs to be de-escaped.
- assert!(
- serde_json::from_str::<Rfc1123Domain<&str>>(r#""c\u006fm""#)
- .is_err_and(|err| err.is_data() && err.column() == 10)
- );
- }
-}
diff --git a/src/serde/tests.rs b/src/serde/tests.rs
@@ -0,0 +1,45 @@
+extern crate alloc;
+use crate::{
+ char_set::ASCII_HYPHEN_DIGITS_LETTERS,
+ dom::{Domain, Rfc1123Domain},
+};
+use alloc::string::String;
+#[test]
+fn serde() {
+ assert!(
+ serde_json::from_str::<Domain<&str>>(r#""example.com""#)
+ .is_ok_and(|dom| dom.into_iter().count() == 2)
+ );
+ assert!(
+ serde_json::from_str::<Domain<String>>(r#""c\"om""#)
+ .is_ok_and(|dom| dom.into_iter().count() == 1)
+ );
+ // Can't borrow since input needs to be de-escaped.
+ assert!(
+ serde_json::from_str::<Domain<&str>>(r#""c\"om""#)
+ .is_err_and(|err| err.is_data() && err.column() == 7)
+ );
+ assert!(
+ Domain::try_from_bytes("example.com", &ASCII_HYPHEN_DIGITS_LETTERS).is_ok_and(|dom| {
+ serde_json::to_string(&dom).is_ok_and(|output| output == r#""example.com""#)
+ })
+ );
+ assert!(
+ Domain::try_from_bytes(b"example.com", &ASCII_HYPHEN_DIGITS_LETTERS).is_ok_and(|dom| {
+ serde_json::to_string(&dom).is_ok_and(|output| output == r#""example.com""#)
+ })
+ );
+ assert!(
+ serde_json::from_str::<Rfc1123Domain<&str>>(r#""example.com""#)
+ .is_ok_and(|dom| dom.into_iter().count() == 2)
+ );
+ assert!(
+ serde_json::from_str::<Rfc1123Domain<String>>(r#""c\u006fm""#)
+ .is_ok_and(|dom| dom.tld().as_str() == "com")
+ );
+ // Can't borrow since input needs to be de-escaped.
+ assert!(
+ serde_json::from_str::<Rfc1123Domain<&str>>(r#""c\u006fm""#)
+ .is_err_and(|err| err.is_data() && err.column() == 10)
+ );
+}