use std::{
error::Error,
fmt::{Display, Formatter, Result as FmtResult},
time::{SystemTime, UNIX_EPOCH},
};
use twilight_model::util::Timestamp;
pub const AUDIT_REASON_MAX: usize = 512;
pub const AUTO_MODERATION_METADATA_MENTION_TOTAL_LIMIT: u8 = 50;
pub const CREATE_GUILD_BAN_DELETE_MESSAGE_SECONDS_MAX: u32 = 604_800;
pub const COMMUNICATION_DISABLED_MAX_DURATION: i64 = 28 * 24 * 60 * 60;
pub const GET_CHANNEL_MESSAGES_LIMIT_MAX: u16 = 100;
pub const GET_CHANNEL_MESSAGES_LIMIT_MIN: u16 = 1;
pub const GET_CURRENT_USER_GUILDS_LIMIT_MAX: u16 = 200;
pub const GET_CURRENT_USER_GUILDS_LIMIT_MIN: u16 = 1;
pub const GET_GUILD_AUDIT_LOG_LIMIT_MAX: u16 = 100;
pub const GET_GUILD_AUDIT_LOG_LIMIT_MIN: u16 = 1;
pub const GET_GUILD_BANS_LIMIT_MAX: u16 = 1000;
pub const GET_GUILD_MEMBERS_LIMIT_MAX: u16 = 1000;
pub const GET_GUILD_MEMBERS_LIMIT_MIN: u16 = 1;
pub const GET_REACTIONS_LIMIT_MIN: u16 = 1;
pub const GET_REACTIONS_LIMIT_MAX: u16 = 100;
pub const GUILD_NAME_LENGTH_MAX: usize = 100;
pub const GUILD_NAME_LENGTH_MIN: usize = 2;
pub const GUILD_PRUNE_DAYS_MAX: u16 = 30;
pub const GUILD_PRUNE_DAYS_MIN: u16 = 1;
pub const INVITE_AGE_MAX: u32 = 604_800;
pub const INVITE_USES_MAX: u16 = 100;
pub const NICKNAME_LIMIT_MAX: usize = 32;
pub const NICKNAME_LIMIT_MIN: usize = 1;
pub const SCHEDULED_EVENT_DESCRIPTION_MAX: usize = 1000;
pub const SCHEDULED_EVENT_DESCRIPTION_MIN: usize = 1;
pub const SCHEDULED_EVENT_GET_USERS_MAX: u16 = 100;
pub const SCHEDULED_EVENT_GET_USERS_MIN: u16 = 1;
pub const SCHEDULED_EVENT_NAME_MAX: usize = 100;
pub const SCHEDULED_EVENT_NAME_MIN: usize = 1;
pub const SEARCH_GUILD_MEMBERS_LIMIT_MAX: u16 = 1000;
pub const SEARCH_GUILD_MEMBERS_LIMIT_MIN: u16 = 1;
pub const STAGE_TOPIC_LENGTH_MAX: usize = 120;
pub const STAGE_TOPIC_LENGTH_MIN: usize = 1;
pub const TEMPLATE_DESCRIPTION_LENGTH_MAX: usize = 120;
pub const TEMPLATE_NAME_LENGTH_MAX: usize = 100;
pub const TEMPLATE_NAME_LENGTH_MIN: usize = 1;
pub const USERNAME_LIMIT_MAX: usize = 32;
pub const USERNAME_LIMIT_MIN: usize = 2;
pub const WEBHOOK_USERNAME_LIMIT_MAX: usize = 80;
pub const WEBHOOK_USERNAME_LIMIT_MIN: usize = 2;
const USERNAME_INVALID_SUBSTRINGS: [&str; 5] = ["@", "#", ":", "```", "discord"];
const USERNAME_INVALID_STRINGS: [&str; 2] = ["everyone", "here"];
const WEBHOOK_INVALID_STRINGS: [&str; 1] = ["clyde"];
#[derive(Debug)]
pub struct ValidationError {
kind: ValidationErrorType,
}
impl ValidationError {
#[must_use = "retrieving the type has no effect if left unused"]
pub const fn kind(&self) -> &ValidationErrorType {
&self.kind
}
#[allow(clippy::unused_self)]
#[must_use = "consuming the error and retrieving the source has no effect if left unused"]
pub fn into_source(self) -> Option<Box<dyn Error + Send + Sync>> {
None
}
#[must_use = "consuming the error into its parts has no effect if left unused"]
pub fn into_parts(self) -> (ValidationErrorType, Option<Box<dyn Error + Send + Sync>>) {
(self.kind, None)
}
}
impl Display for ValidationError {
#[allow(clippy::too_many_lines)]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match &self.kind {
ValidationErrorType::AuditReason { len } => {
f.write_str("provided audit reason length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at most ")?;
Display::fmt(&AUDIT_REASON_MAX, f)
}
ValidationErrorType::AutoModerationMetadataMentionTotalLimit { limit } => {
f.write_str("provided auto moderation metadata mention_total_limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at most ")?;
Display::fmt(&AUTO_MODERATION_METADATA_MENTION_TOTAL_LIMIT, f)
}
ValidationErrorType::CreateGuildBanDeleteMessageSeconds {
seconds: delete_message_seconds,
} => {
f.write_str("provided create guild ban delete_message_seconds is ")?;
Display::fmt(delete_message_seconds, f)?;
f.write_str(", but it must be at most ")?;
Display::fmt(&CREATE_GUILD_BAN_DELETE_MESSAGE_SECONDS_MAX, f)
}
ValidationErrorType::CommunicationDisabledUntil { .. } => {
f.write_str("provided timestamp is too far in the future")
}
ValidationErrorType::GetChannelMessages { limit } => {
f.write_str("provided get guild members limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&GET_CHANNEL_MESSAGES_LIMIT_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&GET_CHANNEL_MESSAGES_LIMIT_MAX, f)
}
ValidationErrorType::GetCurrentUserGuilds { limit } => {
f.write_str("provided get current user guilds limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&GET_CURRENT_USER_GUILDS_LIMIT_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&GET_CURRENT_USER_GUILDS_LIMIT_MAX, f)
}
ValidationErrorType::GetGuildAuditLog { limit } => {
f.write_str("provided get guild audit log limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&GET_GUILD_MEMBERS_LIMIT_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&GET_GUILD_MEMBERS_LIMIT_MAX, f)
}
ValidationErrorType::GetGuildBans { limit } => {
f.write_str("provided get guild bans limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at most ")?;
Display::fmt(&GET_GUILD_BANS_LIMIT_MAX, f)
}
ValidationErrorType::GetGuildMembers { limit } => {
f.write_str("provided get guild members limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&GET_GUILD_MEMBERS_LIMIT_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&GET_GUILD_MEMBERS_LIMIT_MAX, f)
}
ValidationErrorType::GetReactions { limit } => {
f.write_str("provided get reactions limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&GET_REACTIONS_LIMIT_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&GET_REACTIONS_LIMIT_MAX, f)
}
ValidationErrorType::GuildName { len } => {
f.write_str("provided guild name length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&GUILD_NAME_LENGTH_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&GUILD_NAME_LENGTH_MAX, f)
}
ValidationErrorType::GuildPruneDays { days } => {
f.write_str("provided prune days is ")?;
Display::fmt(days, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&GUILD_PRUNE_DAYS_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&GUILD_PRUNE_DAYS_MAX, f)
}
ValidationErrorType::InviteMaxAge { max_age } => {
f.write_str("provided invite max_age is ")?;
Display::fmt(max_age, f)?;
f.write_str(", but it must be at most ")?;
Display::fmt(&INVITE_AGE_MAX, f)
}
ValidationErrorType::InviteMaxUses { max_uses } => {
f.write_str("provided invite max_uses is ")?;
Display::fmt(max_uses, f)?;
f.write_str(", but it must be at most ")?;
Display::fmt(&INVITE_USES_MAX, f)
}
ValidationErrorType::Nickname { len } => {
f.write_str("provided nickname length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&NICKNAME_LIMIT_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&NICKNAME_LIMIT_MAX, f)
}
ValidationErrorType::ScheduledEventDescription { len } => {
f.write_str("provided scheduled event description is length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&SCHEDULED_EVENT_DESCRIPTION_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&SCHEDULED_EVENT_DESCRIPTION_MAX, f)
}
ValidationErrorType::ScheduledEventGetUsers { limit } => {
f.write_str("provided scheduled event get users limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&SCHEDULED_EVENT_GET_USERS_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&SCHEDULED_EVENT_GET_USERS_MAX, f)
}
ValidationErrorType::ScheduledEventName { len } => {
f.write_str("provided scheduled event name is length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&SCHEDULED_EVENT_NAME_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&SCHEDULED_EVENT_NAME_MAX, f)
}
ValidationErrorType::SearchGuildMembers { limit } => {
f.write_str("provided search guild members limit is ")?;
Display::fmt(limit, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&SEARCH_GUILD_MEMBERS_LIMIT_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&SEARCH_GUILD_MEMBERS_LIMIT_MAX, f)
}
ValidationErrorType::StageTopic { len } => {
f.write_str("provided stage instance topic length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&STAGE_TOPIC_LENGTH_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&STAGE_TOPIC_LENGTH_MAX, f)
}
ValidationErrorType::TemplateDescription { len } => {
f.write_str("provided guild template description topic length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at most ")?;
Display::fmt(&TEMPLATE_DESCRIPTION_LENGTH_MAX, f)
}
ValidationErrorType::TemplateName { len } => {
f.write_str("provided guild template name length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&TEMPLATE_NAME_LENGTH_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&TEMPLATE_NAME_LENGTH_MAX, f)
}
ValidationErrorType::Username { len, substring }
| ValidationErrorType::WebhookUsername { len, substring } => {
f.write_str("provided username")?;
if let Some(len) = len {
f.write_str(" length is ")?;
Display::fmt(len, f)?;
f.write_str(", but it must be at least ")?;
Display::fmt(&USERNAME_LIMIT_MIN, f)?;
f.write_str(" and at most ")?;
Display::fmt(&USERNAME_LIMIT_MAX, f)?;
}
if let Some(substring) = substring {
if len.is_some() {
f.write_str(", and")?;
}
f.write_str(" cannot contain ")?;
Display::fmt(substring, f)?;
}
Ok(())
}
}
}
}
impl Error for ValidationError {}
#[derive(Debug)]
pub enum ValidationErrorType {
AuditReason {
len: usize,
},
AutoModerationMetadataMentionTotalLimit {
limit: u8,
},
CreateGuildBanDeleteMessageSeconds {
seconds: u32,
},
CommunicationDisabledUntil {
timestamp: Timestamp,
},
GetChannelMessages {
limit: u16,
},
GetCurrentUserGuilds {
limit: u16,
},
GetGuildAuditLog {
limit: u16,
},
GetGuildBans {
limit: u16,
},
GetGuildMembers {
limit: u16,
},
GetReactions {
limit: u16,
},
GuildName {
len: usize,
},
GuildPruneDays {
days: u16,
},
InviteMaxAge {
max_age: u32,
},
InviteMaxUses {
max_uses: u16,
},
Nickname {
len: usize,
},
ScheduledEventDescription {
len: usize,
},
ScheduledEventGetUsers {
limit: u16,
},
ScheduledEventName {
len: usize,
},
SearchGuildMembers {
limit: u16,
},
StageTopic {
len: usize,
},
TemplateDescription {
len: usize,
},
TemplateName {
len: usize,
},
Username {
len: Option<usize>,
substring: Option<&'static str>,
},
WebhookUsername {
len: Option<usize>,
substring: Option<&'static str>,
},
}
pub fn audit_reason(audit_reason: impl AsRef<str>) -> Result<(), ValidationError> {
let len = audit_reason.as_ref().chars().count();
if len <= AUDIT_REASON_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::AuditReason { len },
})
}
}
pub const fn auto_moderation_metadata_mention_total_limit(
limit: u8,
) -> Result<(), ValidationError> {
if limit <= AUTO_MODERATION_METADATA_MENTION_TOTAL_LIMIT {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::AutoModerationMetadataMentionTotalLimit { limit },
})
}
}
pub const fn create_guild_ban_delete_message_seconds(seconds: u32) -> Result<(), ValidationError> {
if seconds <= CREATE_GUILD_BAN_DELETE_MESSAGE_SECONDS_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::CreateGuildBanDeleteMessageSeconds { seconds },
})
}
}
#[allow(clippy::cast_possible_wrap)] pub fn communication_disabled_until(timestamp: Timestamp) -> Result<(), ValidationError> {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|_| ValidationError {
kind: ValidationErrorType::CommunicationDisabledUntil { timestamp },
})?;
let end = timestamp.as_secs();
if end - now.as_secs() as i64 <= COMMUNICATION_DISABLED_MAX_DURATION {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::CommunicationDisabledUntil { timestamp },
})
}
}
pub const fn get_channel_messages_limit(limit: u16) -> Result<(), ValidationError> {
if limit >= GET_CHANNEL_MESSAGES_LIMIT_MIN && limit <= GET_CHANNEL_MESSAGES_LIMIT_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::GetChannelMessages { limit },
})
}
}
pub const fn get_current_user_guilds_limit(limit: u16) -> Result<(), ValidationError> {
if limit >= GET_CURRENT_USER_GUILDS_LIMIT_MIN && limit <= GET_CURRENT_USER_GUILDS_LIMIT_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::GetCurrentUserGuilds { limit },
})
}
}
pub const fn get_guild_audit_log_limit(limit: u16) -> Result<(), ValidationError> {
if limit >= GET_GUILD_AUDIT_LOG_LIMIT_MIN && limit <= GET_GUILD_AUDIT_LOG_LIMIT_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::GetGuildAuditLog { limit },
})
}
}
pub const fn get_guild_bans_limit(limit: u16) -> Result<(), ValidationError> {
if limit <= GET_GUILD_BANS_LIMIT_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::GetGuildBans { limit },
})
}
}
pub const fn get_guild_members_limit(limit: u16) -> Result<(), ValidationError> {
if limit >= GET_GUILD_MEMBERS_LIMIT_MIN && limit <= GET_GUILD_MEMBERS_LIMIT_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::GetGuildMembers { limit },
})
}
}
pub const fn get_reactions_limit(limit: u16) -> Result<(), ValidationError> {
if limit >= GET_REACTIONS_LIMIT_MIN && limit <= GET_REACTIONS_LIMIT_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::GetReactions { limit },
})
}
}
pub fn guild_name(name: impl AsRef<str>) -> Result<(), ValidationError> {
let len = name.as_ref().chars().count();
if (GUILD_NAME_LENGTH_MIN..=GUILD_NAME_LENGTH_MAX).contains(&len) {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::GuildName { len },
})
}
}
pub const fn guild_prune_days(days: u16) -> Result<(), ValidationError> {
if days >= GUILD_PRUNE_DAYS_MIN && days <= GUILD_PRUNE_DAYS_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::GuildPruneDays { days },
})
}
}
pub const fn invite_max_age(max_age: u32) -> Result<(), ValidationError> {
if max_age <= INVITE_AGE_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::InviteMaxAge { max_age },
})
}
}
pub const fn invite_max_uses(max_uses: u16) -> Result<(), ValidationError> {
if max_uses <= INVITE_USES_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::InviteMaxUses { max_uses },
})
}
}
pub fn nickname(nickname: impl AsRef<str>) -> Result<(), ValidationError> {
let len = nickname.as_ref().chars().count();
if (NICKNAME_LIMIT_MIN..=NICKNAME_LIMIT_MAX).contains(&len) {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::Nickname { len },
})
}
}
pub fn scheduled_event_description(description: impl AsRef<str>) -> Result<(), ValidationError> {
let len = description.as_ref().chars().count();
if (SCHEDULED_EVENT_DESCRIPTION_MIN..=SCHEDULED_EVENT_DESCRIPTION_MAX).contains(&len) {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::ScheduledEventDescription { len },
})
}
}
pub const fn scheduled_event_get_users(limit: u16) -> Result<(), ValidationError> {
if limit <= SCHEDULED_EVENT_GET_USERS_MIN && limit >= SCHEDULED_EVENT_GET_USERS_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::ScheduledEventGetUsers { limit },
})
}
}
pub fn scheduled_event_name(name: impl AsRef<str>) -> Result<(), ValidationError> {
let len = name.as_ref().chars().count();
if (SCHEDULED_EVENT_NAME_MIN..=SCHEDULED_EVENT_NAME_MAX).contains(&len) {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::ScheduledEventName { len },
})
}
}
pub const fn search_guild_members_limit(limit: u16) -> Result<(), ValidationError> {
if limit >= SEARCH_GUILD_MEMBERS_LIMIT_MIN && limit <= SEARCH_GUILD_MEMBERS_LIMIT_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::SearchGuildMembers { limit },
})
}
}
pub fn stage_topic(topic: impl AsRef<str>) -> Result<(), ValidationError> {
let len = topic.as_ref().chars().count();
if (STAGE_TOPIC_LENGTH_MIN..=STAGE_TOPIC_LENGTH_MAX).contains(&len) {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::StageTopic { len },
})
}
}
pub fn template_description(description: impl AsRef<str>) -> Result<(), ValidationError> {
let len = description.as_ref().chars().count();
if len <= TEMPLATE_DESCRIPTION_LENGTH_MAX {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::TemplateDescription { len },
})
}
}
pub fn template_name(name: impl AsRef<str>) -> Result<(), ValidationError> {
let len = name.as_ref().chars().count();
if (TEMPLATE_NAME_LENGTH_MIN..=TEMPLATE_NAME_LENGTH_MAX).contains(&len) {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::TemplateName { len },
})
}
}
pub fn username(value: impl AsRef<str>) -> Result<(), ValidationError> {
let value = value.as_ref();
let len = value.chars().count();
let range = USERNAME_LIMIT_MIN..=USERNAME_LIMIT_MAX;
let invalid_len = (!range.contains(&len)).then_some(len);
let invalid_substring = USERNAME_INVALID_SUBSTRINGS
.into_iter()
.find(|invalid_substring| value.contains(invalid_substring))
.or_else(|| {
USERNAME_INVALID_STRINGS
.into_iter()
.find(|invalid_string| value == *invalid_string)
});
if invalid_len.is_none() && invalid_substring.is_none() {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::Username {
len: invalid_len,
substring: invalid_substring,
},
})
}
}
pub fn webhook_username(value: impl AsRef<str>) -> Result<(), ValidationError> {
let value = value.as_ref();
let len = value.chars().count();
let range = WEBHOOK_USERNAME_LIMIT_MIN..=WEBHOOK_USERNAME_LIMIT_MAX;
let invalid_len = (!range.contains(&len)).then_some(len);
let invalid_substring = WEBHOOK_INVALID_STRINGS
.into_iter()
.find(|invalid_string| value == *invalid_string);
if invalid_len.is_none() && invalid_substring.is_none() {
Ok(())
} else {
Err(ValidationError {
kind: ValidationErrorType::WebhookUsername {
len: invalid_len,
substring: invalid_substring,
},
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn username_variants() {
let expected = format!(
"provided username length is 200, but it must be at least {USERNAME_LIMIT_MIN} and at \
most {USERNAME_LIMIT_MAX}, and cannot contain :"
);
let actual = ValidationError {
kind: ValidationErrorType::Username {
len: Some(200),
substring: Some(":"),
},
};
assert_eq!(expected, actual.to_string());
let expected = format!(
"provided username length is 200, but it must be at least {USERNAME_LIMIT_MIN} and at \
most {USERNAME_LIMIT_MAX}",
);
let actual = ValidationError {
kind: ValidationErrorType::Username {
len: Some(200),
substring: None,
},
};
assert_eq!(expected, actual.to_string());
let expected = "provided username cannot contain :".to_string();
let actual = ValidationError {
kind: ValidationErrorType::Username {
len: None,
substring: Some(":"),
},
};
assert_eq!(expected, actual.to_string());
}
#[test]
fn audit_reason_length() {
assert!(audit_reason("").is_ok());
assert!(audit_reason("a").is_ok());
assert!(audit_reason("a".repeat(500)).is_ok());
assert!(audit_reason("a".repeat(512)).is_ok());
assert!(audit_reason("a".repeat(513)).is_err());
}
#[test]
fn auto_moderation_metadata_mention_total() {
assert!(auto_moderation_metadata_mention_total_limit(0).is_ok());
assert!(auto_moderation_metadata_mention_total_limit(1).is_ok());
assert!(auto_moderation_metadata_mention_total_limit(50).is_ok());
assert!(auto_moderation_metadata_mention_total_limit(51).is_err());
}
#[test]
fn create_guild_ban_delete_message_seconds_max() {
assert!(create_guild_ban_delete_message_seconds(0).is_ok());
assert!(create_guild_ban_delete_message_seconds(1).is_ok());
assert!(create_guild_ban_delete_message_seconds(604_800).is_ok());
assert!(create_guild_ban_delete_message_seconds(604_801).is_err());
}
#[test]
fn communication_disabled_until_max() {
#[allow(clippy::cast_possible_wrap)]
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i64;
let ok_timestamp =
Timestamp::from_secs(now + COMMUNICATION_DISABLED_MAX_DURATION - 1000).unwrap();
assert!(communication_disabled_until(ok_timestamp).is_ok());
let err_timestamp =
Timestamp::from_secs(now + COMMUNICATION_DISABLED_MAX_DURATION + 1000).unwrap();
assert!(communication_disabled_until(err_timestamp).is_err());
}
#[test]
fn get_channel_messages_limit_count() {
assert!(get_channel_messages_limit(1).is_ok());
assert!(get_channel_messages_limit(100).is_ok());
assert!(get_channel_messages_limit(0).is_err());
assert!(get_channel_messages_limit(101).is_err());
}
#[test]
fn get_current_user_guilds_limit_count() {
assert!(get_current_user_guilds_limit(1).is_ok());
assert!(get_current_user_guilds_limit(200).is_ok());
assert!(get_current_user_guilds_limit(0).is_err());
assert!(get_current_user_guilds_limit(201).is_err());
}
#[test]
fn get_guild_log_limit_count() {
assert!(get_guild_audit_log_limit(1).is_ok());
assert!(get_guild_audit_log_limit(100).is_ok());
assert!(get_guild_audit_log_limit(0).is_err());
assert!(get_guild_audit_log_limit(101).is_err());
}
#[test]
fn get_guild_bans_limit_count() {
assert!(get_guild_bans_limit(0).is_ok());
assert!(get_guild_bans_limit(1000).is_ok());
assert!(get_guild_bans_limit(1001).is_err());
}
#[test]
fn get_guild_members_limit_count() {
assert!(get_guild_members_limit(1).is_ok());
assert!(get_guild_members_limit(1000).is_ok());
assert!(get_guild_members_limit(0).is_err());
assert!(get_guild_members_limit(1001).is_err());
}
#[test]
fn get_reactions_limit_count() {
assert!(get_reactions_limit(1).is_ok());
assert!(get_reactions_limit(100).is_ok());
assert!(get_reactions_limit(0).is_err());
assert!(get_reactions_limit(101).is_err());
}
#[test]
fn guild_name_length() {
assert!(guild_name("aa").is_ok());
assert!(guild_name("a".repeat(100)).is_ok());
assert!(guild_name("").is_err());
assert!(guild_name("a").is_err());
assert!(guild_name("a".repeat(101)).is_err());
}
#[test]
fn guild_prune_days_length() {
assert!(guild_prune_days(1).is_ok());
assert!(guild_prune_days(30).is_ok());
assert!(guild_prune_days(0).is_err());
assert!(guild_prune_days(31).is_err());
assert!(guild_prune_days(100).is_err());
}
#[test]
fn invite_max_age_length() {
assert!(invite_max_age(0).is_ok());
assert!(invite_max_age(86_400).is_ok());
assert!(invite_max_age(604_800).is_ok());
assert!(invite_max_age(604_801).is_err());
}
#[test]
fn invite_max_uses_count() {
assert!(invite_max_uses(0).is_ok());
assert!(invite_max_uses(100).is_ok());
assert!(invite_max_uses(101).is_err());
}
#[test]
fn nickname_length() {
assert!(nickname("a").is_ok());
assert!(nickname("a".repeat(32)).is_ok());
assert!(nickname("").is_err());
assert!(nickname("a".repeat(33)).is_err());
}
#[test]
fn scheduled_event_description_length() {
assert!(scheduled_event_description("a").is_ok());
assert!(scheduled_event_description("a".repeat(1000)).is_ok());
assert!(scheduled_event_description("").is_err());
assert!(scheduled_event_description("a".repeat(1001)).is_err());
}
#[test]
fn scheduled_event_name_length() {
assert!(scheduled_event_name("a").is_ok());
assert!(scheduled_event_name("a".repeat(100)).is_ok());
assert!(scheduled_event_name("").is_err());
assert!(scheduled_event_name("a".repeat(101)).is_err());
}
#[test]
fn search_guild_members_limit_count() {
assert!(search_guild_members_limit(1).is_ok());
assert!(search_guild_members_limit(1000).is_ok());
assert!(search_guild_members_limit(0).is_err());
assert!(search_guild_members_limit(1001).is_err());
}
#[test]
fn stage_topic_length() {
assert!(stage_topic("a").is_ok());
assert!(stage_topic("a".repeat(120)).is_ok());
assert!(stage_topic("").is_err());
assert!(stage_topic("a".repeat(121)).is_err());
}
#[test]
fn template_description_length() {
assert!(template_description("").is_ok());
assert!(template_description("a").is_ok());
assert!(template_description("a".repeat(120)).is_ok());
assert!(template_description("a".repeat(121)).is_err());
}
#[test]
fn template_name_length() {
assert!(template_name("a").is_ok());
assert!(template_name("a".repeat(100)).is_ok());
assert!(template_name("").is_err());
assert!(template_name("a".repeat(101)).is_err());
}
#[test]
fn username_length() {
assert!(username("aa").is_ok());
assert!(username("a".repeat(32)).is_ok());
assert!(username("a").is_err());
assert!(username("a".repeat(33)).is_err());
assert!(username("no @ in username").is_err());
assert!(username("no # in username").is_err());
assert!(username("no : in username").is_err());
assert!(username(r#"no ``` in username"#).is_err());
assert!(username("no discord in username").is_err());
assert!(username("everyone").is_err());
assert!(username("here").is_err());
}
#[test]
fn webhook_username_length() {
assert!(webhook_username("aa").is_ok());
assert!(webhook_username("a".repeat(80)).is_ok());
assert!(webhook_username("a").is_err());
assert!(webhook_username("a".repeat(81)).is_err());
assert!(webhook_username("clyde").is_err());
}
}