From 74fc954d1a75b3d6f61a7bbc4787a26287c5eba4 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 22 Jan 2024 20:57:08 +0100 Subject: [PATCH 01/21] Fix broken behaviour for ConfigEntity --- src/types/entities/config.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/types/entities/config.rs b/src/types/entities/config.rs index 25b1ef1..6244e9d 100644 --- a/src/types/entities/config.rs +++ b/src/types/entities/config.rs @@ -15,20 +15,29 @@ impl ConfigEntity { let Some(v) = self.value.as_ref() else { return None; }; - Some(v.as_str().expect("value is not a string").to_string()) + let Some(v) = v.as_str() else { + return None; + }; + Some(v.to_string()) } pub fn as_bool(&self) -> Option { let Some(v) = self.value.as_ref() else { return None; }; - Some(v.as_bool().expect("value is not a boolean")) + let Some(v) = v.as_bool() else { + return None; + }; + Some(v) } pub fn as_int(&self) -> Option { let Some(v) = self.value.as_ref() else { return None; }; - Some(v.as_i64().expect("value is not a number")) + let Some(v) = v.as_i64() else { + return None; + }; + Some(v) } } From c6e77246501d9188bff0d9d224a15f0473110e4f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 22 Jan 2024 20:57:17 +0100 Subject: [PATCH 02/21] rustfmt --- src/instance.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/instance.rs b/src/instance.rs index 68a1f7d..7ec673c 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -73,7 +73,6 @@ impl PartialEq for LimitsInformation { } impl Instance { - pub(crate) fn clone_limits_if_some(&self) -> Option> { if self.limits_information.is_some() { return Some(self.limits_information.as_ref().unwrap().ratelimits.clone()); From 013687c81079461a27aaee5c38ba9f193a110977 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 22 Jan 2024 20:57:29 +0100 Subject: [PATCH 03/21] write unit tests for config and entities --- tests/types.rs | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 tests/types.rs diff --git a/tests/types.rs b/tests/types.rs new file mode 100644 index 0000000..c5f131c --- /dev/null +++ b/tests/types.rs @@ -0,0 +1,119 @@ +mod config { + mod subconfigs { + mod client { + use chorus::types::types::subconfigs::client::ClientReleaseConfiguration; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn client_release_configuration() { + let _client_release_configuration = ClientReleaseConfiguration::default(); + } + } + + mod limits { + use chorus::types::types::subconfigs::limits::rates::RateLimits; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn rates() { + let rate_limits = RateLimits::default(); + let hash_map = rate_limits.to_hash_map(); + assert!(hash_map.contains_key(&chorus::types::LimitType::ChannelBaseline)); + assert!(hash_map.contains_key(&chorus::types::LimitType::GuildBaseline)); + assert!(hash_map.contains_key(&chorus::types::LimitType::AuthLogin)); + assert!(hash_map.contains_key(&chorus::types::LimitType::AuthRegister)); + assert!(hash_map.contains_key(&chorus::types::LimitType::Error)); + assert!(hash_map.contains_key(&chorus::types::LimitType::Global)); + assert!(hash_map.contains_key(&chorus::types::LimitType::Ip)); + assert!(hash_map.contains_key(&chorus::types::LimitType::WebhookBaseline)); + assert!(hash_map.len() == 8) + } + } + } + + mod guild_configuration { + use std::ops::Deref; + + use chorus::types::types::guild_configuration::GuildFeaturesList; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn deref_guild_features_list() { + let guild_features_list = &GuildFeaturesList::default(); + let _guild_features_list_deref = guild_features_list.deref().clone(); + } + } + + mod domains_configuration { + use chorus::types::types::domains_configuration::Domains; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn display_domains() { + let domains = Domains { + cdn: "http://localhost:3020/cdn/".to_string(), + gateway: "ws://localhost:3020/".to_string(), + api_endpoint: "http://localhost:3020/".to_string(), + default_api_version: "9".to_string(), + }; + let fmt_domains = domains.to_string(); + assert!(fmt_domains.contains("CDN URL: http://localhost:3020/cdn/")); + assert!(fmt_domains.contains("Gateway URL: ws://localhost:3020/")); + assert!(fmt_domains.contains("API Endpoint: http://localhost:3020/")); + assert!(fmt_domains.contains("Default API Version: 9")); + } + } +} + +mod entities { + use std::sync::{Arc, RwLock}; + + use chorus::types::{ApplicationFlags, ConfigEntity, Emoji, User}; + use serde_json::json; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn application() { + let application = chorus::types::Application::default(); + assert!(application.name == *""); + assert!(application.verify_key == *""); + assert_ne!( + application.owner.read().unwrap().clone(), + Arc::new(RwLock::new(User::default())) + .read() + .unwrap() + .clone() + ); + let flags = ApplicationFlags::from_bits(0).unwrap(); + assert!(application.flags() == flags); + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn config() { + let mut config_entity = ConfigEntity { + key: "ExampleKey".to_string(), + value: Some(json!(1)), + }; + config_entity.as_int().unwrap(); + assert!(config_entity.as_bool().is_none()); + assert!(config_entity.as_string().is_none()); + config_entity.value = Some(json!(true)); + config_entity.as_bool().unwrap(); + assert!(config_entity.as_int().is_none()); + assert!(config_entity.as_string().is_none()); + config_entity.value = Some(json!("Hello")); + config_entity.as_string().unwrap(); + assert!(config_entity.as_bool().is_none()); + assert!(config_entity.as_int().is_none()); + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn emoji() { + let emoji = Emoji::default(); + let another_emoji = Emoji::default(); + assert_ne!(emoji.id, another_emoji.id); + assert_ne!(emoji, another_emoji); + } +} From 8846159ffd6f10c2d8555a476c0b0a6ecc1bc21a Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 18:43:06 +0100 Subject: [PATCH 04/21] Remove impl Eq from types that didn't qualify for Eq --- src/instance.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index 7ec673c..bfa794a 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -37,8 +37,6 @@ impl PartialEq for Instance { } } -impl Eq for Instance {} - impl std::hash::Hash for Instance { fn hash(&self, state: &mut H) { self.urls.hash(state); @@ -171,8 +169,6 @@ impl PartialEq for ChorusUser { } } -impl Eq for ChorusUser {} - impl ChorusUser { pub fn token(&self) -> String { self.token.clone() From 0923de59a420ecc56ad3a6166a232351ec8a30bf Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 19:07:23 +0100 Subject: [PATCH 05/21] Replace usage of Arc> in public APIs with Shared<...> --- src/instance.rs | 16 ++++++++-------- src/types/entities/application.rs | 15 ++++++++------- src/types/entities/audit_log.rs | 3 ++- src/types/entities/auto_moderation.rs | 7 ++++--- src/types/entities/channel.rs | 7 ++++--- src/types/entities/emoji.rs | 3 ++- src/types/entities/guild.rs | 19 ++++++++++--------- src/types/entities/guild_member.rs | 3 ++- src/types/entities/integration.rs | 5 +++-- src/types/entities/invite.rs | 5 +++-- src/types/entities/message.rs | 3 ++- src/types/entities/mod.rs | 2 -- src/types/entities/relationship.rs | 3 ++- src/types/entities/sticker.rs | 3 ++- src/types/entities/team.rs | 3 ++- src/types/entities/template.rs | 7 ++++--- src/types/entities/user_settings.rs | 6 ++++-- src/types/entities/voice_state.rs | 3 ++- src/types/entities/webhook.rs | 5 +++-- src/types/events/channel.rs | 11 ++++++----- src/types/events/guild.rs | 18 +++++++++--------- src/types/events/mod.rs | 10 ++++++---- 22 files changed, 88 insertions(+), 69 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index bfa794a..cd5f6b2 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -9,7 +9,7 @@ use reqwest::Client; use serde::{Deserialize, Serialize}; use crate::errors::ChorusResult; -use crate::gateway::{Gateway, GatewayHandle}; +use crate::gateway::{Gateway, GatewayHandle, Shared}; use crate::ratelimiter::ChorusRequest; use crate::types::types::subconfigs::limits::rates::RateLimits; use crate::types::{ @@ -153,11 +153,11 @@ impl fmt::Display for Token { /// It is used for most authenticated actions on a Spacebar server. /// It also has its own [Gateway] connection. pub struct ChorusUser { - pub belongs_to: Arc>, + pub belongs_to: Shared, pub token: String, pub limits: Option>, - pub settings: Arc>, - pub object: Arc>, + pub settings: Shared, + pub object: Shared, pub gateway: GatewayHandle, } @@ -184,11 +184,11 @@ impl ChorusUser { /// This isn't the prefered way to create a ChorusUser. /// See [Instance::login_account] and [Instance::register_account] instead. pub fn new( - belongs_to: Arc>, + belongs_to: Shared, token: String, limits: Option>, - settings: Arc>, - object: Arc>, + settings: Shared, + object: Shared, gateway: GatewayHandle, ) -> ChorusUser { ChorusUser { @@ -206,7 +206,7 @@ impl ChorusUser { /// registering or logging in to the Instance, where you do not yet have a User object, but still /// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify /// first. - pub(crate) async fn shell(instance: Arc>, token: String) -> ChorusUser { + pub(crate) async fn shell(instance: Shared, token: String) -> ChorusUser { let settings = Arc::new(RwLock::new(UserSettings::default())); let object = Arc::new(RwLock::new(User::default())); let wss_url = instance.read().unwrap().urls.wss.clone(); diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index 0b55626..0f95ce8 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_repr::{Deserialize_repr, Serialize_repr}; +use crate::gateway::Shared; use crate::types::utils::Snowflake; use crate::types::{Team, User}; @@ -27,7 +28,7 @@ pub struct Application { pub bot_require_code_grant: bool, pub verify_key: String, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub owner: Arc>, + pub owner: Shared, pub flags: u64, #[cfg(feature = "sqlx")] pub redirect_uris: Option>>, @@ -49,7 +50,7 @@ pub struct Application { #[cfg(feature = "sqlx")] pub install_params: Option>, #[cfg(not(feature = "sqlx"))] - pub install_params: Option>>, + pub install_params: Option>, pub terms_of_service_url: Option, pub privacy_policy_url: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] @@ -142,7 +143,7 @@ pub struct ApplicationCommand { pub application_id: Snowflake, pub name: String, pub description: String, - pub options: Vec>>, + pub options: Vec>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -154,7 +155,7 @@ pub struct ApplicationCommandOption { pub description: String, pub required: bool, pub choices: Vec, - pub options: Arc>>, + pub options: Shared>, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -190,14 +191,14 @@ pub enum ApplicationCommandOptionType { pub struct ApplicationCommandInteractionData { pub id: Snowflake, pub name: String, - pub options: Vec>>, + pub options: Vec>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApplicationCommandInteractionDataOption { pub name: String, pub value: Value, - pub options: Vec>>, + pub options: Vec>, } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -206,7 +207,7 @@ pub struct GuildApplicationCommandPermissions { pub id: Snowflake, pub application_id: Snowflake, pub guild_id: Snowflake, - pub permissions: Vec>>, + pub permissions: Vec>, } #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index be14f0f..b6a43a7 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -2,13 +2,14 @@ use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::utils::Snowflake; #[derive(Serialize, Deserialize, Debug, Default, Clone)] /// See pub struct AuditLogEntry { pub target_id: Option, - pub changes: Option>>>, + pub changes: Option>>, pub user_id: Option, pub id: Snowflake, // to:do implement an enum for these types diff --git a/src/types/entities/auto_moderation.rs b/src/types/entities/auto_moderation.rs index a8910b1..11bc258 100644 --- a/src/types/entities/auto_moderation.rs +++ b/src/types/entities/auto_moderation.rs @@ -1,5 +1,6 @@ use std::sync::{Arc, RwLock}; +use crate::gateway::Shared; #[cfg(feature = "client")] use crate::gateway::Updateable; @@ -21,8 +22,8 @@ pub struct AutoModerationRule { pub creator_id: Snowflake, pub event_type: AutoModerationRuleEventType, pub trigger_type: AutoModerationRuleTriggerType, - pub trigger_metadata: Arc>, - pub actions: Vec>>, + pub trigger_metadata: Shared, + pub actions: Vec>, pub enabled: bool, pub exempt_roles: Vec, pub exempt_channels: Vec, @@ -99,7 +100,7 @@ pub enum AutoModerationRuleKeywordPresetType { pub struct AutoModerationAction { #[serde(rename = "type")] pub action_type: AutoModerationActionType, - pub metadata: Option>>, + pub metadata: Option>, } #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 5acf2ae..75fffbc 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -6,6 +6,7 @@ use serde_aux::prelude::deserialize_string_from_number; use serde_repr::{Deserialize_repr, Serialize_repr}; use std::fmt::Debug; +use crate::gateway::Shared; use crate::types::{ entities::{GuildMember, User}, utils::Snowflake, @@ -71,13 +72,13 @@ pub struct Channel { pub permission_overwrites: Option>>, #[cfg(not(feature = "sqlx"))] #[cfg_attr(feature = "client", observe_option_vec)] - pub permission_overwrites: Option>>>, + pub permission_overwrites: Option>>, pub permissions: Option, pub position: Option, pub rate_limit_per_user: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "client", observe_option_vec)] - pub recipients: Option>>>, + pub recipients: Option>>, pub rtc_region: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub thread_metadata: Option, @@ -171,7 +172,7 @@ pub struct ThreadMember { pub user_id: Option, pub join_timestamp: Option, pub flags: Option, - pub member: Option>>, + pub member: Option>, } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index b3916e2..fd2b252 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -3,6 +3,7 @@ use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::entities::User; use crate::types::Snowflake; @@ -31,7 +32,7 @@ pub struct Emoji { #[cfg(not(feature = "sqlx"))] pub roles: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub user: Option>>, + pub user: Option>, pub require_colons: Option, pub managed: Option, pub animated: Option, diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 1fe235b..e386fed 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -6,6 +6,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; +use crate::gateway::Shared; use crate::types::types::guild_configuration::GuildFeaturesList; use crate::types::{ entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook}, @@ -45,14 +46,14 @@ pub struct Guild { pub bans: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "client", observe_option_vec)] - pub channels: Option>>>, + pub channels: Option>>, pub default_message_notifications: Option, pub description: Option, pub discovery_splash: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "client", observe_vec)] #[serde(default)] - pub emojis: Vec>>, + pub emojis: Vec>, pub explicit_content_filter: Option, //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] pub features: Option, @@ -88,7 +89,7 @@ pub struct Guild { pub region: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "client", observe_option_vec)] - pub roles: Option>>>, + pub roles: Option>>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub rules_channel: Option, pub rules_channel_id: Option, @@ -102,10 +103,10 @@ pub struct Guild { pub verification_level: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "client", observe_option_vec)] - pub voice_states: Option>>>, + pub voice_states: Option>>, #[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "client", observe_option_vec)] - pub webhooks: Option>>>, + pub webhooks: Option>>, #[cfg(feature = "sqlx")] pub welcome_screen: Option>, #[cfg(not(feature = "sqlx"))] @@ -239,11 +240,11 @@ pub struct GuildInvite { pub created_at: DateTime, pub expires_at: Option>, pub guild_id: Snowflake, - pub guild: Option>>, + pub guild: Option>, pub channel_id: Snowflake, - pub channel: Option>>, + pub channel: Option>, pub inviter_id: Option, - pub inviter: Option>>, + pub inviter: Option>, pub target_user_id: Option, pub target_user: Option, pub target_user_type: Option, @@ -296,7 +297,7 @@ pub struct GuildScheduledEvent { pub entity_type: GuildScheduledEventEntityType, pub entity_id: Option, pub entity_metadata: Option, - pub creator: Option>>, + pub creator: Option>, pub user_count: Option, pub image: Option, } diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index bf2f93b..a9701fa 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -2,6 +2,7 @@ use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::{entities::PublicUser, Snowflake}; #[derive(Debug, Deserialize, Default, Serialize, Clone)] @@ -10,7 +11,7 @@ use crate::types::{entities::PublicUser, Snowflake}; /// # Reference /// See pub struct GuildMember { - pub user: Option>>, + pub user: Option>, pub nick: Option, pub avatar: Option, pub roles: Vec, diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 0913213..15ca42f 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -3,6 +3,7 @@ use std::sync::{Arc, RwLock}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::{ entities::{Application, User}, utils::Snowflake, @@ -23,14 +24,14 @@ pub struct Integration { pub expire_behaviour: Option, pub expire_grace_period: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub user: Option>>, + pub user: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub account: IntegrationAccount, pub synced_at: Option>, pub subscriber_count: Option, pub revoked: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub application: Option>>, + pub application: Option>, pub scopes: Option>, } diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index d08ad1d..577d237 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -3,6 +3,7 @@ use std::sync::{Arc, RwLock}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::{Snowflake, WelcomeScreenObject}; use super::guild::GuildScheduledEvent; @@ -21,7 +22,7 @@ pub struct Invite { pub flags: Option, pub guild: Option, pub guild_id: Option, - pub guild_scheduled_event: Option>>, + pub guild_scheduled_event: Option>, #[serde(rename = "type")] pub invite_type: Option, pub inviter: Option, @@ -59,7 +60,7 @@ pub struct InviteGuild { /// See #[derive(Debug, Serialize, Deserialize)] pub struct InviteStageInstance { - pub members: Vec>>, + pub members: Vec>, pub participant_count: i32, pub speaker_count: i32, pub topic: String, diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 41c4d51..802f806 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -2,6 +2,7 @@ use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::{ entities::{ Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, @@ -121,7 +122,7 @@ pub struct MessageInteraction { pub interaction_type: u8, pub name: String, pub user: User, - pub member: Option>>, + pub member: Option>, } #[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, Eq, PartialOrd, Ord)] diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 5ceada6..7e88a62 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -24,7 +24,6 @@ pub use voice_state::*; pub use webhook::*; use crate::gateway::Shared; - #[cfg(feature = "client")] use crate::gateway::Updateable; @@ -36,7 +35,6 @@ use async_trait::async_trait; #[cfg(feature = "client")] use std::fmt::Debug; - #[cfg(feature = "client")] use std::sync::{Arc, RwLock}; diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index 576d99a..b73388e 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -4,6 +4,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; +use crate::gateway::Shared; use crate::types::Snowflake; use super::PublicUser; @@ -15,7 +16,7 @@ pub struct Relationship { #[serde(rename = "type")] pub relationship_type: RelationshipType, pub nickname: Option, - pub user: Arc>, + pub user: Shared, pub since: Option>, } diff --git a/src/types/entities/sticker.rs b/src/types/entities/sticker.rs index 593206d..c4bc4e8 100644 --- a/src/types/entities/sticker.rs +++ b/src/types/entities/sticker.rs @@ -2,6 +2,7 @@ use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::{entities::User, utils::Snowflake}; #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -24,7 +25,7 @@ pub struct Sticker { pub available: Option, pub guild_id: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub user: Option>>, + pub user: Option>, pub sort_value: Option, } diff --git a/src/types/entities/team.rs b/src/types/entities/team.rs index 8e32f55..1359a9a 100644 --- a/src/types/entities/team.rs +++ b/src/types/entities/team.rs @@ -2,6 +2,7 @@ use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::entities::User; use crate::types::Snowflake; @@ -21,5 +22,5 @@ pub struct TeamMember { pub membership_state: u8, pub permissions: Vec, pub team_id: Snowflake, - pub user: Arc>, + pub user: Shared, } diff --git a/src/types/entities/template.rs b/src/types/entities/template.rs index 1305a98..a5c7a38 100644 --- a/src/types/entities/template.rs +++ b/src/types/entities/template.rs @@ -3,6 +3,7 @@ use std::sync::{Arc, RwLock}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; use crate::types::{ entities::{Guild, User}, utils::Snowflake, @@ -18,13 +19,13 @@ pub struct GuildTemplate { pub usage_count: Option, pub creator_id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub creator: Arc>, + pub creator: Shared, pub created_at: DateTime, pub updated_at: DateTime, pub source_guild_id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub source_guild: Vec>>, + pub source_guild: Vec>, // Unsure how a {recursive: Guild} looks like, might be a Vec? #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub serialized_source_guild: Vec>>, + pub serialized_source_guild: Vec>, } diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index e6db7e7..a27e748 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -3,6 +3,8 @@ use std::sync::{Arc, RwLock}; use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "lowercase")] @@ -77,7 +79,7 @@ pub struct UserSettings { #[cfg(not(feature = "sqlx"))] pub restricted_guilds: Vec, pub show_current_game: bool, - pub status: Arc>, + pub status: Shared, pub stream_notifications_enabled: bool, pub theme: UserTheme, pub timezone_offset: i16, @@ -153,5 +155,5 @@ pub struct GuildFolder { #[derive(Debug, Serialize, Deserialize)] pub struct LoginResult { pub token: String, - pub settings: Arc>, + pub settings: Shared, } diff --git a/src/types/entities/voice_state.rs b/src/types/entities/voice_state.rs index 1a0c3b3..d75dde7 100644 --- a/src/types/entities/voice_state.rs +++ b/src/types/entities/voice_state.rs @@ -3,6 +3,7 @@ use std::sync::{Arc, RwLock}; #[cfg(feature = "client")] use chorus_macros::Composite; +use crate::gateway::Shared; #[cfg(feature = "client")] use crate::types::Composite; @@ -33,7 +34,7 @@ pub struct VoiceState { pub guild: Option, pub channel_id: Option, pub user_id: Snowflake, - pub member: Option>>, + pub member: Option>, pub session_id: String, pub token: Option, pub deaf: bool, diff --git a/src/types/entities/webhook.rs b/src/types/entities/webhook.rs index cf5716c..ad4f4ec 100644 --- a/src/types/entities/webhook.rs +++ b/src/types/entities/webhook.rs @@ -3,6 +3,7 @@ use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; +use crate::gateway::Shared; #[cfg(feature = "client")] use crate::gateway::Updateable; @@ -36,10 +37,10 @@ pub struct Webhook { pub application_id: Snowflake, #[serde(skip_serializing_if = "Option::is_none")] #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub user: Option>>, + pub user: Option>, #[serde(skip_serializing_if = "Option::is_none")] #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub source_guild: Option>>, + pub source_guild: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub url: Option, } diff --git a/src/types/events/channel.rs b/src/types/events/channel.rs index eb557d7..5ca73ec 100644 --- a/src/types/events/channel.rs +++ b/src/types/events/channel.rs @@ -1,4 +1,5 @@ use crate::types::events::WebSocketEvent; +use crate::types::IntoShared; use crate::types::{entities::Channel, JsonField, Snowflake, SourceUrlField}; use chorus_macros::{JsonField, SourceUrlField}; use chrono::{DateTime, Utc}; @@ -8,7 +9,7 @@ use serde::{Deserialize, Serialize}; use super::UpdateMessage; #[cfg(feature = "client")] -use std::sync::{Arc, RwLock}; +use crate::gateway::Shared; #[cfg(feature = "client")] use crate::types::Guild; @@ -42,9 +43,9 @@ impl UpdateMessage for ChannelCreate { self.channel.guild_id } - fn update(&mut self, object_to_update: Arc>) { + fn update(&mut self, object_to_update: Shared) { let mut write = object_to_update.write().unwrap(); - let update = Arc::new(RwLock::new(self.channel.clone())); + let update = self.channel.clone().into_shared(); if write.channels.is_some() { write.channels.as_mut().unwrap().push(update); } else { @@ -68,7 +69,7 @@ impl WebSocketEvent for ChannelUpdate {} #[cfg(feature = "client")] impl UpdateMessage for ChannelUpdate { - fn update(&mut self, object_to_update: Arc>) { + fn update(&mut self, object_to_update: Shared) { let mut write = object_to_update.write().unwrap(); *write = self.channel.clone(); } @@ -114,7 +115,7 @@ impl UpdateMessage for ChannelDelete { self.channel.guild_id } - fn update(&mut self, object_to_update: Arc>) { + fn update(&mut self, object_to_update: Shared) { if self.id().is_none() { return; } diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index 89e4a75..04f871a 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{Guild, PublicUser, UnavailableGuild}; use crate::types::events::WebSocketEvent; use crate::types::{ - AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, JsonField, RoleObject, Snowflake, - SourceUrlField, Sticker, + AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, IntoShared, JsonField, RoleObject, + Snowflake, SourceUrlField, Sticker, }; use super::PresenceUpdate; @@ -14,7 +14,7 @@ use super::PresenceUpdate; #[cfg(feature = "client")] use super::UpdateMessage; #[cfg(feature = "client")] -use std::sync::{Arc, RwLock}; +use crate::gateway::Shared; #[derive(Debug, Deserialize, Serialize, Default, Clone, SourceUrlField, JsonField)] /// See ; @@ -38,7 +38,7 @@ impl UpdateMessage for GuildCreate { } } - fn update(&mut self, _: Arc>) {} + fn update(&mut self, _: Shared) {} } #[derive(Debug, Deserialize, Serialize, Clone)] @@ -114,7 +114,7 @@ impl UpdateMessage for GuildDelete { fn id(&self) -> Option { Some(self.guild.id) } - fn update(&mut self, _: Arc>) {} + fn update(&mut self, _: Shared) {} } impl WebSocketEvent for GuildDelete {} @@ -229,16 +229,16 @@ impl UpdateMessage for GuildRoleCreate { Some(self.guild_id) } - fn update(&mut self, object_to_update: Arc>) { + fn update(&mut self, object_to_update: Shared) { let mut object_to_update = object_to_update.write().unwrap(); if object_to_update.roles.is_some() { object_to_update .roles .as_mut() .unwrap() - .push(Arc::new(RwLock::new(self.role.clone()))); + .push(self.role.clone().into_shared()); } else { - object_to_update.roles = Some(Vec::from([Arc::new(RwLock::new(self.role.clone()))])); + object_to_update.roles = Some(Vec::from([self.role.clone().into_shared()])); } } } @@ -262,7 +262,7 @@ impl UpdateMessage for GuildRoleUpdate { Some(self.role.id) } - fn update(&mut self, object_to_update: Arc>) { + fn update(&mut self, object_to_update: Shared) { let mut write = object_to_update.write().unwrap(); *write = self.role.clone(); } diff --git a/src/types/events/mod.rs b/src/types/events/mod.rs index f4e926c..ac0f121 100644 --- a/src/types/events/mod.rs +++ b/src/types/events/mod.rs @@ -39,9 +39,9 @@ use serde_json::{from_str, from_value, to_value, Value}; #[cfg(feature = "client")] use std::collections::HashMap; -use std::fmt::Debug; #[cfg(feature = "client")] -use std::sync::{Arc, RwLock}; +use crate::gateway::Shared; +use std::fmt::Debug; #[cfg(feature = "client")] use serde::de::DeserializeOwned; @@ -132,7 +132,7 @@ pub(crate) trait UpdateMessage: Clone + JsonField + SourceUrlField where T: Updateable + Serialize + DeserializeOwned + Clone, { - fn update(&mut self, object_to_update: Arc>) { + fn update(&mut self, object_to_update: Shared) { update_object(self.get_json(), object_to_update) } fn id(&self) -> Option; @@ -152,8 +152,10 @@ pub trait SourceUrlField: Clone { /// Only applicable for events where the Update struct is the same as the Entity struct pub(crate) fn update_object( value: String, - object: Arc>, + object: Shared<(impl Updateable + Serialize + DeserializeOwned + Clone)>, ) { + use crate::gateway::Shared; + let data_from_event: HashMap = from_str(&value).unwrap(); let mut original_data: HashMap = from_value(to_value(object.clone()).unwrap()).unwrap(); From 11df180446b021f8a101f736ca78aee36f4e1f0d Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 19:08:26 +0100 Subject: [PATCH 06/21] APPEND: Remove unused imports --- src/types/entities/application.rs | 2 -- src/types/entities/audit_log.rs | 2 -- src/types/entities/auto_moderation.rs | 2 -- src/types/entities/channel.rs | 2 -- src/types/entities/emoji.rs | 1 - src/types/entities/guild.rs | 1 - src/types/entities/guild_member.rs | 2 -- src/types/entities/integration.rs | 2 -- src/types/entities/invite.rs | 2 -- src/types/entities/message.rs | 2 -- src/types/entities/relationship.rs | 2 -- src/types/entities/sticker.rs | 2 -- src/types/entities/team.rs | 2 -- src/types/entities/template.rs | 2 -- src/types/entities/voice_state.rs | 2 -- src/types/entities/webhook.rs | 1 - src/types/events/mod.rs | 2 -- 17 files changed, 31 deletions(-) diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index 0f95ce8..95df4f2 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use bitflags::bitflags; use serde::{Deserialize, Serialize}; use serde_json::Value; diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index b6a43a7..4023b7a 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use serde::{Deserialize, Serialize}; use crate::gateway::Shared; diff --git a/src/types/entities/auto_moderation.rs b/src/types/entities/auto_moderation.rs index 11bc258..779f58b 100644 --- a/src/types/entities/auto_moderation.rs +++ b/src/types/entities/auto_moderation.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use crate::gateway::Shared; #[cfg(feature = "client")] use crate::gateway::Updateable; diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 75fffbc..c268859 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_aux::prelude::deserialize_string_from_number; diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index fd2b252..5170637 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -1,5 +1,4 @@ use std::fmt::Debug; -use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index e386fed..ee796e4 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -1,5 +1,4 @@ use std::fmt::Debug; -use std::sync::{Arc, RwLock}; use bitflags::bitflags; use chrono::{DateTime, Utc}; diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index a9701fa..a18afbc 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use serde::{Deserialize, Serialize}; use crate::gateway::Shared; diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 15ca42f..580590a 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 577d237..f9eaaa3 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 802f806..923ee61 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use serde::{Deserialize, Serialize}; use crate::gateway::Shared; diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index b73388e..6f207f2 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; diff --git a/src/types/entities/sticker.rs b/src/types/entities/sticker.rs index c4bc4e8..d4331fd 100644 --- a/src/types/entities/sticker.rs +++ b/src/types/entities/sticker.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use serde::{Deserialize, Serialize}; use crate::gateway::Shared; diff --git a/src/types/entities/team.rs b/src/types/entities/team.rs index 1359a9a..daac58c 100644 --- a/src/types/entities/team.rs +++ b/src/types/entities/team.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use serde::{Deserialize, Serialize}; use crate::gateway::Shared; diff --git a/src/types/entities/template.rs b/src/types/entities/template.rs index a5c7a38..167697f 100644 --- a/src/types/entities/template.rs +++ b/src/types/entities/template.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; diff --git a/src/types/entities/voice_state.rs b/src/types/entities/voice_state.rs index d75dde7..911cf96 100644 --- a/src/types/entities/voice_state.rs +++ b/src/types/entities/voice_state.rs @@ -1,5 +1,3 @@ -use std::sync::{Arc, RwLock}; - #[cfg(feature = "client")] use chorus_macros::Composite; diff --git a/src/types/entities/webhook.rs b/src/types/entities/webhook.rs index ad4f4ec..7eb2b66 100644 --- a/src/types/entities/webhook.rs +++ b/src/types/entities/webhook.rs @@ -1,5 +1,4 @@ use std::fmt::Debug; -use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; diff --git a/src/types/events/mod.rs b/src/types/events/mod.rs index ac0f121..5644d8a 100644 --- a/src/types/events/mod.rs +++ b/src/types/events/mod.rs @@ -154,8 +154,6 @@ pub(crate) fn update_object( value: String, object: Shared<(impl Updateable + Serialize + DeserializeOwned + Clone)>, ) { - use crate::gateway::Shared; - let data_from_event: HashMap = from_str(&value).unwrap(); let mut original_data: HashMap = from_value(to_value(object.clone()).unwrap()).unwrap(); From 577a399a7b93e634b8f5c6d8123bc4398f7a071e Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 20:50:19 +0100 Subject: [PATCH 07/21] Create tests from to_str and from_str for GuildFeatures --- tests/types.rs | 833 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 832 insertions(+), 1 deletion(-) diff --git a/tests/types.rs b/tests/types.rs index c5f131c..e9a1de5 100644 --- a/tests/types.rs +++ b/tests/types.rs @@ -33,8 +33,10 @@ mod config { mod guild_configuration { use std::ops::Deref; + use std::str::FromStr; - use chorus::types::types::guild_configuration::GuildFeaturesList; + use chorus::types::types::guild_configuration::{GuildFeatures, GuildFeaturesList}; + use chorus::types::{Error, GuildError}; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] @@ -42,6 +44,835 @@ mod config { let guild_features_list = &GuildFeaturesList::default(); let _guild_features_list_deref = guild_features_list.deref().clone(); } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn test_deref_mut() { + let mut guild_features_list = GuildFeaturesList::default(); + guild_features_list.clear(); + let mut list = GuildFeaturesList::default().to_vec(); + list.push(GuildFeatures::ActivitiesAlpha); + *guild_features_list = list.to_vec(); + assert_eq!(guild_features_list.len(), 1); + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn test_display() { + let mut guild_features_list = GuildFeaturesList::default(); + guild_features_list.push(GuildFeatures::ActivitiesAlpha); + guild_features_list.push(GuildFeatures::AnimatedBanner); + assert_eq!( + format!("{}", guild_features_list), + "ACTIVITIES_ALPHA,ANIMATED_BANNER" + ); + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn test_from_str() { + // GPT moment + assert_eq!( + GuildFeatures::from_str("ACTIVITIES_ALPHA").unwrap(), + GuildFeatures::ActivitiesAlpha + ); + assert_eq!( + GuildFeatures::from_str("ACTIVITIES_EMPLOYEE").unwrap(), + GuildFeatures::ActivitiesEmployee + ); + assert_eq!( + GuildFeatures::from_str("ACTIVITIES_INTERNAL_DEV").unwrap(), + GuildFeatures::ActivitiesInternalDev + ); + assert_eq!( + GuildFeatures::from_str("ANIMATED_BANNER").unwrap(), + GuildFeatures::AnimatedBanner + ); + assert_eq!( + GuildFeatures::from_str("ANIMATED_ICON").unwrap(), + GuildFeatures::AnimatedIcon + ); + assert_eq!( + GuildFeatures::from_str("APPLICATION_COMMAND_PERMISSIONS_V2").unwrap(), + GuildFeatures::ApplicationCommandPermissionsV2 + ); + assert_eq!( + GuildFeatures::from_str("AUTO_MODERATION").unwrap(), + GuildFeatures::AutoModeration + ); + assert_eq!( + GuildFeatures::from_str("AUTO_MOD_TRIGGER_KEYWORD_FILTER").unwrap(), + GuildFeatures::AutoModTriggerKeywordFilter + ); + assert_eq!( + GuildFeatures::from_str("AUTO_MOD_TRIGGER_ML_SPAM_FILTER").unwrap(), + GuildFeatures::AutoModTriggerMLSpamFilter + ); + assert_eq!( + GuildFeatures::from_str("AUTO_MOD_TRIGGER_SPAM_LINK_FILTER").unwrap(), + GuildFeatures::AutoModTriggerSpamLinkFilter + ); + assert_eq!( + GuildFeatures::from_str("AUTO_MOD_TRIGGER_USER_PROFILE").unwrap(), + GuildFeatures::AutoModTriggerUserProfile + ); + assert_eq!( + GuildFeatures::from_str("BANNER").unwrap(), + GuildFeatures::Banner + ); + assert_eq!(GuildFeatures::from_str("BFG").unwrap(), GuildFeatures::Bfg); + assert_eq!( + GuildFeatures::from_str("BOOSTING_TIERS_EXPERIMENT_MEDIUM_GUILD").unwrap(), + GuildFeatures::BoostingTiersExperimentMediumGuild + ); + assert_eq!( + GuildFeatures::from_str("BOOSTING_TIERS_EXPERIMENT_SMALL_GUILD").unwrap(), + GuildFeatures::BoostingTiersExperimentSmallGuild + ); + assert_eq!( + GuildFeatures::from_str("BOT_DEVELOPER_EARLY_ACCESS").unwrap(), + GuildFeatures::BotDeveloperEarlyAccess + ); + assert_eq!( + GuildFeatures::from_str("BURST_REACTIONS").unwrap(), + GuildFeatures::BurstReactions + ); + assert_eq!( + GuildFeatures::from_str("COMMUNITY_CANARY").unwrap(), + GuildFeatures::CommunityCanary + ); + assert_eq!( + GuildFeatures::from_str("COMMUNITY_EXP_LARGE_GATED").unwrap(), + GuildFeatures::CommunityExpLargeGated + ); + assert_eq!( + GuildFeatures::from_str("COMMUNITY_EXP_LARGE_UNGATED").unwrap(), + GuildFeatures::CommunityExpLargeUngated + ); + assert_eq!( + GuildFeatures::from_str("COMMUNITY_EXP_MEDIUM").unwrap(), + GuildFeatures::CommunityExpMedium + ); + assert_eq!( + GuildFeatures::from_str("CHANNEL_EMOJIS_GENERATED").unwrap(), + GuildFeatures::ChannelEmojisGenerated + ); + assert_eq!( + GuildFeatures::from_str("CHANNEL_HIGHLIGHTS").unwrap(), + GuildFeatures::ChannelHighlights + ); + assert_eq!( + GuildFeatures::from_str("CHANNEL_HIGHLIGHTS_DISABLED").unwrap(), + GuildFeatures::ChannelHighlightsDisabled + ); + assert_eq!( + GuildFeatures::from_str("CLYDE_ENABLED").unwrap(), + GuildFeatures::ClydeEnabled + ); + assert_eq!( + GuildFeatures::from_str("CLYDE_EXPERIMENT_ENABLED").unwrap(), + GuildFeatures::ClydeExperimentEnabled + ); + assert_eq!( + GuildFeatures::from_str("CLYDE_DISABLED").unwrap(), + GuildFeatures::ClydeDisabled + ); + assert_eq!( + GuildFeatures::from_str("COMMUNITY").unwrap(), + GuildFeatures::Community + ); + assert_eq!( + GuildFeatures::from_str("CREATOR_ACCEPTED_NEW_TERMS").unwrap(), + GuildFeatures::CreatorAcceptedNewTerms + ); + assert_eq!( + GuildFeatures::from_str("CREATOR_MONETIZABLE").unwrap(), + GuildFeatures::CreatorMonetizable + ); + assert_eq!( + GuildFeatures::from_str("CREATOR_MONETIZABLE_DISABLED").unwrap(), + GuildFeatures::CreatorMonetizableDisabled + ); + assert_eq!( + GuildFeatures::from_str("CREATOR_MONETIZABLE_PENDING_NEW_OWNER_ONBOARDING") + .unwrap(), + GuildFeatures::CreatorMonetizablePendingNewOwnerOnboarding + ); + assert_eq!( + GuildFeatures::from_str("CREATOR_MONETIZABLE_PROVISIONAL").unwrap(), + GuildFeatures::CreatorMonetizableProvisional + ); + assert_eq!( + GuildFeatures::from_str("CREATOR_MONETIZABLE_RESTRICTED").unwrap(), + GuildFeatures::CreatorMonetizableRestricted + ); + assert_eq!( + GuildFeatures::from_str("CREATOR_MONETIZABLE_WHITEGLOVE").unwrap(), + GuildFeatures::CreatorMonetizableWhiteglove + ); + assert_eq!( + GuildFeatures::from_str("CREATOR_MONETIZABLE_APPLICATION_ALLOWLIST").unwrap(), + GuildFeatures::CreatorMonetizableApplicationAllowlist + ); + assert_eq!( + GuildFeatures::from_str("CREATE_STORE_PAGE").unwrap(), + GuildFeatures::CreateStorePage + ); + assert_eq!( + GuildFeatures::from_str("DEVELOPER_SUPPORT_SERVER").unwrap(), + GuildFeatures::DeveloperSupportServer + ); + assert_eq!( + GuildFeatures::from_str("DISCOVERABLE_DISABLED").unwrap(), + GuildFeatures::DiscoverableDisabled + ); + assert_eq!( + GuildFeatures::from_str("DISCOVERABLE").unwrap(), + GuildFeatures::Discoverable + ); + assert_eq!( + GuildFeatures::from_str("ENABLED_DISCOVERABLE_BEFORE").unwrap(), + GuildFeatures::EnabledDiscoverableBefore + ); + assert_eq!( + GuildFeatures::from_str("EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT").unwrap(), + GuildFeatures::ExposedToActivitiesWTPExperiment + ); + assert_eq!( + GuildFeatures::from_str("GUESTS_ENABLED").unwrap(), + GuildFeatures::GuestsEnabled + ); + assert_eq!( + GuildFeatures::from_str("GUILD_AUTOMOD_DEFAULT_LIST").unwrap(), + GuildFeatures::GuildAutomodDefaultList + ); + assert_eq!( + GuildFeatures::from_str("GUILD_COMMUNICATION_DISABLED_GUILDS").unwrap(), + GuildFeatures::GuildCommunicationDisabledGuilds + ); + assert_eq!( + GuildFeatures::from_str("GUILD_HOME_DEPRECATION_OVERRIDE").unwrap(), + GuildFeatures::GuildHomeDeprecationOverride + ); + assert_eq!( + GuildFeatures::from_str("GUILD_HOME_OVERRIDE").unwrap(), + GuildFeatures::GuildHomeOverride + ); + assert_eq!( + GuildFeatures::from_str("GUILD_HOME_TEST").unwrap(), + GuildFeatures::GuildHomeTest + ); + assert_eq!( + GuildFeatures::from_str("GUILD_MEMBER_VERIFICATION_EXPERIMENT").unwrap(), + GuildFeatures::GuildMemberVerificationExperiment + ); + assert_eq!( + GuildFeatures::from_str("GUILD_ONBOARDING").unwrap(), + GuildFeatures::GuildOnboarding + ); + assert_eq!( + GuildFeatures::from_str("GUILD_ONBOARDING_ADMIN_ONLY").unwrap(), + GuildFeatures::GuildOnboardingAdminOnly + ); + assert_eq!( + GuildFeatures::from_str("GUILD_ONBOARDING_EVER_ENABLED").unwrap(), + GuildFeatures::GuildOnboardingEverEnabled + ); + assert_eq!( + GuildFeatures::from_str("GUILD_ONBOARDING_HAS_PROMPTS").unwrap(), + GuildFeatures::GuildOnboardingHasPrompts + ); + assert_eq!( + GuildFeatures::from_str("GUILD_ROLE_SUBSCRIPTION").unwrap(), + GuildFeatures::GuildRoleSubscription + ); + assert_eq!( + GuildFeatures::from_str("GUILD_ROLE_SUBSCRIPTION_PURCHASE_FEEDBACK_LOOP").unwrap(), + GuildFeatures::GuildRoleSubscriptionPurchaseFeedbackLoop + ); + assert_eq!( + GuildFeatures::from_str("GUILD_ROLE_SUBSCRIPTION_TRIALS").unwrap(), + GuildFeatures::GuildRoleSubscriptionTrials + ); + assert_eq!( + GuildFeatures::from_str("GUILD_SERVER_GUIDE").unwrap(), + GuildFeatures::GuildServerGuide + ); + assert_eq!( + GuildFeatures::from_str("GUILD_WEB_PAGE_VANITY_URL").unwrap(), + GuildFeatures::GuildWebPageVanityURL + ); + assert_eq!( + GuildFeatures::from_str("HAD_EARLY_ACTIVITIES_ACCESS").unwrap(), + GuildFeatures::HadEarlyActivitiesAccess + ); + assert_eq!( + GuildFeatures::from_str("HAS_DIRECTORY_ENTRY").unwrap(), + GuildFeatures::HasDirectoryEntry + ); + assert_eq!( + GuildFeatures::from_str("HIDE_FROM_EXPERIMENT_UI").unwrap(), + GuildFeatures::HideFromExperimentUi + ); + assert_eq!(GuildFeatures::from_str("HUB").unwrap(), GuildFeatures::Hub); + assert_eq!( + GuildFeatures::from_str("INCREASED_THREAD_LIMIT").unwrap(), + GuildFeatures::IncreasedThreadLimit + ); + assert_eq!( + GuildFeatures::from_str("INTERNAL_EMPLOYEE_ONLY").unwrap(), + GuildFeatures::InternalEmployeeOnly + ); + assert_eq!( + GuildFeatures::from_str("INVITE_SPLASH").unwrap(), + GuildFeatures::InviteSplash + ); + assert_eq!( + GuildFeatures::from_str("INVITES_DISABLED").unwrap(), + GuildFeatures::InvitesDisabled + ); + assert_eq!( + GuildFeatures::from_str("LINKED_TO_HUB").unwrap(), + GuildFeatures::LinkedToHub + ); + assert_eq!( + GuildFeatures::from_str("MARKETPLACES_CONNECTION_ROLES").unwrap(), + GuildFeatures::MarketplacesConnectionRoles + ); + assert_eq!( + GuildFeatures::from_str("MEMBER_PROFILES").unwrap(), + GuildFeatures::MemberProfiles + ); + assert_eq!( + GuildFeatures::from_str("MEMBER_VERIFICATION_GATE_ENABLED").unwrap(), + GuildFeatures::MemberVerificationGateEnabled + ); + assert_eq!( + GuildFeatures::from_str("MEMBER_VERIFICATION_MANUAL_APPROVAL").unwrap(), + GuildFeatures::MemberVerificationManualApproval + ); + assert_eq!( + GuildFeatures::from_str("MOBILE_WEB_ROLE_SUBSCRIPTION_PURCHASE_PAGE").unwrap(), + GuildFeatures::MobileWebRoleSubscriptionPurchasePage + ); + assert_eq!( + GuildFeatures::from_str("MONETIZATION_ENABLED").unwrap(), + GuildFeatures::MonetizationEnabled + ); + assert_eq!( + GuildFeatures::from_str("MORE_EMOJI").unwrap(), + GuildFeatures::MoreEmoji + ); + assert_eq!( + GuildFeatures::from_str("MORE_STICKERS").unwrap(), + GuildFeatures::MoreStickers + ); + assert_eq!( + GuildFeatures::from_str("NEWS").unwrap(), + GuildFeatures::News + ); + assert_eq!( + GuildFeatures::from_str("NEW_THREAD_PERMISSIONS").unwrap(), + GuildFeatures::NewThreadPermissions + ); + assert_eq!( + GuildFeatures::from_str("PARTNERED").unwrap(), + GuildFeatures::Partnered + ); + assert_eq!( + GuildFeatures::from_str("PREMIUM_TIER_3_OVERRIDE").unwrap(), + GuildFeatures::PremiumTier3Override + ); + assert_eq!( + GuildFeatures::from_str("PREVIEW_ENABLED").unwrap(), + GuildFeatures::PreviewEnabled + ); + assert_eq!( + GuildFeatures::from_str("RAID_ALERTS_DISABLED").unwrap(), + GuildFeatures::RaidAlertsDisabled + ); + assert_eq!( + GuildFeatures::from_str("RELAY_ENABLED").unwrap(), + GuildFeatures::RelayEnabled + ); + assert_eq!( + GuildFeatures::from_str("RESTRICT_SPAM_RISK_GUILD").unwrap(), + GuildFeatures::RestrictSpamRiskGuild + ); + assert_eq!( + GuildFeatures::from_str("ROLE_ICONS").unwrap(), + GuildFeatures::RoleIcons + ); + assert_eq!( + GuildFeatures::from_str("ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE").unwrap(), + GuildFeatures::RoleSubscriptionsAvailableForPurchase + ); + assert_eq!( + GuildFeatures::from_str("ROLE_SUBSCRIPTIONS_ENABLED").unwrap(), + GuildFeatures::RoleSubscriptionsEnabled + ); + assert_eq!( + GuildFeatures::from_str("ROLE_SUBSCRIPTIONS_ENABLED_FOR_PURCHASE").unwrap(), + GuildFeatures::RoleSubscriptionsEnabledForPurchase + ); + assert_eq!( + GuildFeatures::from_str("SHARD").unwrap(), + GuildFeatures::Shard + ); + assert_eq!( + GuildFeatures::from_str("SHARED_CANVAS_FRIENDS_AND_FAMILY_TEST").unwrap(), + GuildFeatures::SharedCanvasFriendsAndFamilyTest + ); + assert_eq!( + GuildFeatures::from_str("SOUNDBOARD").unwrap(), + GuildFeatures::Soundboard + ); + assert_eq!( + GuildFeatures::from_str("SUMMARIES_ENABLED").unwrap(), + GuildFeatures::SummariesEnabled + ); + assert_eq!( + GuildFeatures::from_str("SUMMARIES_ENABLED_GA").unwrap(), + GuildFeatures::SummariesEnabledGa + ); + assert_eq!( + GuildFeatures::from_str("SUMMARIES_DISABLED_BY_USER").unwrap(), + GuildFeatures::SummariesDisabledByUser + ); + assert_eq!( + GuildFeatures::from_str("SUMMARIES_ENABLED_BY_USER").unwrap(), + GuildFeatures::SummariesEnabledByUser + ); + assert_eq!( + GuildFeatures::from_str("TEXT_IN_STAGE_ENABLED").unwrap(), + GuildFeatures::TextInStageEnabled + ); + assert_eq!( + GuildFeatures::from_str("TEXT_IN_VOICE_ENABLED").unwrap(), + GuildFeatures::TextInVoiceEnabled + ); + assert_eq!( + GuildFeatures::from_str("THREADS_ENABLED_TESTING").unwrap(), + GuildFeatures::ThreadsEnabledTesting + ); + assert_eq!( + GuildFeatures::from_str("THREADS_ENABLED").unwrap(), + GuildFeatures::ThreadsEnabled + ); + assert_eq!( + GuildFeatures::from_str("THREAD_DEFAULT_AUTO_ARCHIVE_DURATION").unwrap(), + GuildFeatures::ThreadDefaultAutoArchiveDuration + ); + assert_eq!( + GuildFeatures::from_str("THREADS_ONLY_CHANNEL").unwrap(), + GuildFeatures::ThreadsOnlyChannel + ); + assert_eq!( + GuildFeatures::from_str("TICKETED_EVENTS_ENABLED").unwrap(), + GuildFeatures::TicketedEventsEnabled + ); + assert_eq!( + GuildFeatures::from_str("TICKETING_ENABLED").unwrap(), + GuildFeatures::TicketingEnabled + ); + assert_eq!( + GuildFeatures::from_str("VANITY_URL").unwrap(), + GuildFeatures::VanityUrl + ); + assert_eq!( + GuildFeatures::from_str("VERIFIED").unwrap(), + GuildFeatures::Verified + ); + assert_eq!( + GuildFeatures::from_str("VIP_REGIONS").unwrap(), + GuildFeatures::VipRegions + ); + assert_eq!( + GuildFeatures::from_str("VOICE_CHANNEL_EFFECTS").unwrap(), + GuildFeatures::VoiceChannelEffects + ); + assert_eq!( + GuildFeatures::from_str("WELCOME_SCREEN_ENABLED").unwrap(), + GuildFeatures::WelcomeScreenEnabled + ); + assert_eq!( + GuildFeatures::from_str("ALIASABLE_NAMES").unwrap(), + GuildFeatures::AliasableNames + ); + assert_eq!( + GuildFeatures::from_str("ALLOW_INVALID_CHANNEL_NAME").unwrap(), + GuildFeatures::AllowInvalidChannelName + ); + assert_eq!( + GuildFeatures::from_str("ALLOW_UNNAMED_CHANNELS").unwrap(), + GuildFeatures::AllowUnnamedChannels + ); + assert_eq!( + GuildFeatures::from_str("CROSS_CHANNEL_REPLIES").unwrap(), + GuildFeatures::CrossChannelReplies + ); + assert_eq!( + GuildFeatures::from_str("IRC_LIKE_CATEGORY_NAMES").unwrap(), + GuildFeatures::IrcLikeCategoryNames + ); + assert_eq!( + GuildFeatures::from_str("INVITES_CLOSED").unwrap(), + GuildFeatures::InvitesClosed + ); + assert_eq!( + GuildFeatures::from_str("INVALID").unwrap_err().to_string(), + Error::Guild(GuildError::InvalidGuildFeature).to_string() + ); + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn test_to_str() { + assert_eq!(GuildFeatures::ActivitiesAlpha.to_str(), "ACTIVITIES_ALPHA"); + assert_eq!( + GuildFeatures::ActivitiesEmployee.to_str(), + "ACTIVITIES_EMPLOYEE" + ); + assert_eq!( + GuildFeatures::ActivitiesInternalDev.to_str(), + "ACTIVITIES_INTERNAL_DEV" + ); + assert_eq!(GuildFeatures::AnimatedBanner.to_str(), "ANIMATED_BANNER"); + assert_eq!(GuildFeatures::AnimatedIcon.to_str(), "ANIMATED_ICON"); + assert_eq!( + GuildFeatures::ApplicationCommandPermissionsV2.to_str(), + "APPLICATION_COMMAND_PERMISSIONS_V2" + ); + assert_eq!(GuildFeatures::AutoModeration.to_str(), "AUTO_MODERATION"); + assert_eq!( + GuildFeatures::AutoModTriggerKeywordFilter.to_str(), + "AUTO_MOD_TRIGGER_KEYWORD_FILTER" + ); + assert_eq!( + GuildFeatures::AutoModTriggerMLSpamFilter.to_str(), + "AUTO_MOD_TRIGGER_ML_SPAM_FILTER" + ); + assert_eq!( + GuildFeatures::AutoModTriggerSpamLinkFilter.to_str(), + "AUTO_MOD_TRIGGER_SPAM_LINK_FILTER" + ); + assert_eq!( + GuildFeatures::AutoModTriggerUserProfile.to_str(), + "AUTO_MOD_TRIGGER_USER_PROFILE" + ); + assert_eq!(GuildFeatures::Banner.to_str(), "BANNER"); + assert_eq!(GuildFeatures::Bfg.to_str(), "BFG"); + assert_eq!( + GuildFeatures::BoostingTiersExperimentMediumGuild.to_str(), + "BOOSTING_TIERS_EXPERIMENT_MEDIUM_GUILD" + ); + assert_eq!( + GuildFeatures::BoostingTiersExperimentSmallGuild.to_str(), + "BOOSTING_TIERS_EXPERIMENT_SMALL_GUILD" + ); + assert_eq!( + GuildFeatures::BotDeveloperEarlyAccess.to_str(), + "BOT_DEVELOPER_EARLY_ACCESS" + ); + assert_eq!(GuildFeatures::BurstReactions.to_str(), "BURST_REACTIONS"); + assert_eq!(GuildFeatures::CommunityCanary.to_str(), "COMMUNITY_CANARY"); + assert_eq!( + GuildFeatures::CommunityExpLargeGated.to_str(), + "COMMUNITY_EXP_LARGE_GATED" + ); + assert_eq!( + GuildFeatures::CommunityExpLargeUngated.to_str(), + "COMMUNITY_EXP_LARGE_UNGATED" + ); + assert_eq!( + GuildFeatures::CommunityExpMedium.to_str(), + "COMMUNITY_EXP_MEDIUM" + ); + assert_eq!( + GuildFeatures::ChannelEmojisGenerated.to_str(), + "CHANNEL_EMOJIS_GENERATED" + ); + assert_eq!( + GuildFeatures::ChannelHighlights.to_str(), + "CHANNEL_HIGHLIGHTS" + ); + assert_eq!( + GuildFeatures::ChannelHighlightsDisabled.to_str(), + "CHANNEL_HIGHLIGHTS_DISABLED" + ); + assert_eq!(GuildFeatures::ClydeEnabled.to_str(), "CLYDE_ENABLED"); + assert_eq!( + GuildFeatures::ClydeExperimentEnabled.to_str(), + "CLYDE_EXPERIMENT_ENABLED" + ); + assert_eq!(GuildFeatures::ClydeDisabled.to_str(), "CLYDE_DISABLED"); + assert_eq!(GuildFeatures::Community.to_str(), "COMMUNITY"); + assert_eq!( + GuildFeatures::CreatorAcceptedNewTerms.to_str(), + "CREATOR_ACCEPTED_NEW_TERMS" + ); + assert_eq!( + GuildFeatures::CreatorMonetizable.to_str(), + "CREATOR_MONETIZABLE" + ); + assert_eq!( + GuildFeatures::CreatorMonetizableDisabled.to_str(), + "CREATOR_MONETIZABLE_DISABLED" + ); + assert_eq!( + GuildFeatures::CreatorMonetizablePendingNewOwnerOnboarding.to_str(), + "CREATOR_MONETIZABLE_PENDING_NEW_OWNER_ONBOARDING" + ); + assert_eq!( + GuildFeatures::CreatorMonetizableProvisional.to_str(), + "CREATOR_MONETIZABLE_PROVISIONAL" + ); + assert_eq!( + GuildFeatures::CreatorMonetizableRestricted.to_str(), + "CREATOR_MONETIZABLE_RESTRICTED" + ); + assert_eq!( + GuildFeatures::CreatorMonetizableWhiteglove.to_str(), + "CREATOR_MONETIZABLE_WHITEGLOVE" + ); + assert_eq!( + GuildFeatures::CreatorMonetizableApplicationAllowlist.to_str(), + "CREATOR_MONETIZABLE_APPLICATION_ALLOWLIST" + ); + assert_eq!(GuildFeatures::CreateStorePage.to_str(), "CREATE_STORE_PAGE"); + assert_eq!( + GuildFeatures::DeveloperSupportServer.to_str(), + "DEVELOPER_SUPPORT_SERVER" + ); + assert_eq!( + GuildFeatures::DiscoverableDisabled.to_str(), + "DISCOVERABLE_DISABLED" + ); + assert_eq!(GuildFeatures::Discoverable.to_str(), "DISCOVERABLE"); + assert_eq!( + GuildFeatures::EnabledDiscoverableBefore.to_str(), + "ENABLED_DISCOVERABLE_BEFORE" + ); + assert_eq!( + GuildFeatures::ExposedToActivitiesWTPExperiment.to_str(), + "EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT" + ); + assert_eq!(GuildFeatures::GuestsEnabled.to_str(), "GUESTS_ENABLED"); + assert_eq!( + GuildFeatures::GuildAutomodDefaultList.to_str(), + "GUILD_AUTOMOD_DEFAULT_LIST" + ); + assert_eq!( + GuildFeatures::GuildCommunicationDisabledGuilds.to_str(), + "GUILD_COMMUNICATION_DISABLED_GUILDS" + ); + assert_eq!( + GuildFeatures::GuildHomeDeprecationOverride.to_str(), + "GUILD_HOME_DEPRECATION_OVERRIDE" + ); + assert_eq!( + GuildFeatures::GuildHomeOverride.to_str(), + "GUILD_HOME_OVERRIDE" + ); + assert_eq!(GuildFeatures::GuildHomeTest.to_str(), "GUILD_HOME_TEST"); + assert_eq!( + GuildFeatures::GuildMemberVerificationExperiment.to_str(), + "GUILD_MEMBER_VERIFICATION_EXPERIMENT" + ); + assert_eq!(GuildFeatures::GuildOnboarding.to_str(), "GUILD_ONBOARDING"); + assert_eq!( + GuildFeatures::GuildOnboardingAdminOnly.to_str(), + "GUILD_ONBOARDING_ADMIN_ONLY" + ); + assert_eq!( + GuildFeatures::GuildOnboardingEverEnabled.to_str(), + "GUILD_ONBOARDING_EVER_ENABLED" + ); + assert_eq!( + GuildFeatures::GuildOnboardingHasPrompts.to_str(), + "GUILD_ONBOARDING_HAS_PROMPTS" + ); + assert_eq!( + GuildFeatures::GuildRoleSubscription.to_str(), + "GUILD_ROLE_SUBSCRIPTION" + ); + assert_eq!( + GuildFeatures::GuildRoleSubscriptionPurchaseFeedbackLoop.to_str(), + "GUILD_ROLE_SUBSCRIPTION_PURCHASE_FEEDBACK_LOOP" + ); + assert_eq!( + GuildFeatures::GuildRoleSubscriptionTrials.to_str(), + "GUILD_ROLE_SUBSCRIPTION_TRIALS" + ); + assert_eq!( + GuildFeatures::GuildServerGuide.to_str(), + "GUILD_SERVER_GUIDE" + ); + assert_eq!( + GuildFeatures::GuildWebPageVanityURL.to_str(), + "GUILD_WEB_PAGE_VANITY_URL" + ); + assert_eq!( + GuildFeatures::HadEarlyActivitiesAccess.to_str(), + "HAD_EARLY_ACTIVITIES_ACCESS" + ); + assert_eq!( + GuildFeatures::HasDirectoryEntry.to_str(), + "HAS_DIRECTORY_ENTRY" + ); + assert_eq!( + GuildFeatures::HideFromExperimentUi.to_str(), + "HIDE_FROM_EXPERIMENT_UI" + ); + assert_eq!(GuildFeatures::Hub.to_str(), "HUB"); + assert_eq!( + GuildFeatures::IncreasedThreadLimit.to_str(), + "INCREASED_THREAD_LIMIT" + ); + assert_eq!( + GuildFeatures::InternalEmployeeOnly.to_str(), + "INTERNAL_EMPLOYEE_ONLY" + ); + assert_eq!(GuildFeatures::InviteSplash.to_str(), "INVITE_SPLASH"); + assert_eq!(GuildFeatures::InvitesDisabled.to_str(), "INVITES_DISABLED"); + assert_eq!(GuildFeatures::LinkedToHub.to_str(), "LINKED_TO_HUB"); + assert_eq!( + GuildFeatures::MarketplacesConnectionRoles.to_str(), + "MARKETPLACES_CONNECTION_ROLES" + ); + assert_eq!(GuildFeatures::MemberProfiles.to_str(), "MEMBER_PROFILES"); + assert_eq!( + GuildFeatures::MemberVerificationGateEnabled.to_str(), + "MEMBER_VERIFICATION_GATE_ENABLED" + ); + assert_eq!( + GuildFeatures::MemberVerificationManualApproval.to_str(), + "MEMBER_VERIFICATION_MANUAL_APPROVAL" + ); + assert_eq!( + GuildFeatures::MobileWebRoleSubscriptionPurchasePage.to_str(), + "MOBILE_WEB_ROLE_SUBSCRIPTION_PURCHASE_PAGE" + ); + assert_eq!( + GuildFeatures::MonetizationEnabled.to_str(), + "MONETIZATION_ENABLED" + ); + assert_eq!(GuildFeatures::MoreEmoji.to_str(), "MORE_EMOJI"); + assert_eq!(GuildFeatures::MoreStickers.to_str(), "MORE_STICKERS"); + assert_eq!(GuildFeatures::News.to_str(), "NEWS"); + assert_eq!( + GuildFeatures::NewThreadPermissions.to_str(), + "NEW_THREAD_PERMISSIONS" + ); + assert_eq!(GuildFeatures::Partnered.to_str(), "PARTNERED"); + assert_eq!( + GuildFeatures::PremiumTier3Override.to_str(), + "PREMIUM_TIER_3_OVERRIDE" + ); + assert_eq!(GuildFeatures::PreviewEnabled.to_str(), "PREVIEW_ENABLED"); + assert_eq!( + GuildFeatures::RaidAlertsDisabled.to_str(), + "RAID_ALERTS_DISABLED" + ); + assert_eq!(GuildFeatures::RelayEnabled.to_str(), "RELAY_ENABLED"); + assert_eq!( + GuildFeatures::RestrictSpamRiskGuild.to_str(), + "RESTRICT_SPAM_RISK_GUILD" + ); + assert_eq!(GuildFeatures::RoleIcons.to_str(), "ROLE_ICONS"); + assert_eq!( + GuildFeatures::RoleSubscriptionsAvailableForPurchase.to_str(), + "ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE" + ); + assert_eq!( + GuildFeatures::RoleSubscriptionsEnabled.to_str(), + "ROLE_SUBSCRIPTIONS_ENABLED" + ); + assert_eq!( + GuildFeatures::RoleSubscriptionsEnabledForPurchase.to_str(), + "ROLE_SUBSCRIPTIONS_ENABLED_FOR_PURCHASE" + ); + assert_eq!(GuildFeatures::Shard.to_str(), "SHARD"); + assert_eq!( + GuildFeatures::SharedCanvasFriendsAndFamilyTest.to_str(), + "SHARED_CANVAS_FRIENDS_AND_FAMILY_TEST" + ); + assert_eq!(GuildFeatures::Soundboard.to_str(), "SOUNDBOARD"); + assert_eq!( + GuildFeatures::SummariesEnabled.to_str(), + "SUMMARIES_ENABLED" + ); + assert_eq!( + GuildFeatures::SummariesEnabledGa.to_str(), + "SUMMARIES_ENABLED_GA" + ); + assert_eq!( + GuildFeatures::SummariesDisabledByUser.to_str(), + "SUMMARIES_DISABLED_BY_USER" + ); + assert_eq!( + GuildFeatures::SummariesEnabledByUser.to_str(), + "SUMMARIES_ENABLED_BY_USER" + ); + assert_eq!( + GuildFeatures::TextInStageEnabled.to_str(), + "TEXT_IN_STAGE_ENABLED" + ); + assert_eq!( + GuildFeatures::TextInVoiceEnabled.to_str(), + "TEXT_IN_VOICE_ENABLED" + ); + assert_eq!( + GuildFeatures::ThreadsEnabledTesting.to_str(), + "THREADS_ENABLED_TESTING" + ); + assert_eq!(GuildFeatures::ThreadsEnabled.to_str(), "THREADS_ENABLED"); + assert_eq!( + GuildFeatures::ThreadDefaultAutoArchiveDuration.to_str(), + "THREAD_DEFAULT_AUTO_ARCHIVE_DURATION" + ); + assert_eq!( + GuildFeatures::ThreadsOnlyChannel.to_str(), + "THREADS_ONLY_CHANNEL" + ); + assert_eq!( + GuildFeatures::TicketedEventsEnabled.to_str(), + "TICKETED_EVENTS_ENABLED" + ); + assert_eq!( + GuildFeatures::TicketingEnabled.to_str(), + "TICKETING_ENABLED" + ); + assert_eq!(GuildFeatures::VanityUrl.to_str(), "VANITY_URL"); + assert_eq!(GuildFeatures::Verified.to_str(), "VERIFIED"); + assert_eq!(GuildFeatures::VipRegions.to_str(), "VIP_REGIONS"); + assert_eq!( + GuildFeatures::VoiceChannelEffects.to_str(), + "VOICE_CHANNEL_EFFECTS" + ); + assert_eq!( + GuildFeatures::WelcomeScreenEnabled.to_str(), + "WELCOME_SCREEN_ENABLED" + ); + assert_eq!(GuildFeatures::AliasableNames.to_str(), "ALIASABLE_NAMES"); + assert_eq!( + GuildFeatures::AllowInvalidChannelName.to_str(), + "ALLOW_INVALID_CHANNEL_NAME" + ); + assert_eq!( + GuildFeatures::AllowUnnamedChannels.to_str(), + "ALLOW_UNNAMED_CHANNELS" + ); + assert_eq!( + GuildFeatures::CrossChannelReplies.to_str(), + "CROSS_CHANNEL_REPLIES" + ); + assert_eq!( + GuildFeatures::IrcLikeCategoryNames.to_str(), + "IRC_LIKE_CATEGORY_NAMES" + ); + assert_eq!(GuildFeatures::InvitesClosed.to_str(), "INVITES_CLOSED"); + } } mod domains_configuration { From 74346900273882f1085dfe20748299722da409d6 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 21:05:01 +0100 Subject: [PATCH 08/21] Remove Eq fromn Guild as it is not Eq --- src/types/entities/guild.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index ee796e4..4a3d952 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -217,8 +217,6 @@ impl std::cmp::PartialEq for Guild { } } -impl std::cmp::Eq for Guild {} - /// See #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] From 97ab7576330531de367da052262f94ef8dabfced Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 21:13:15 +0100 Subject: [PATCH 09/21] Add unit tests for guild.rs entities --- tests/types.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/types.rs b/tests/types.rs index e9a1de5..2caef09 100644 --- a/tests/types.rs +++ b/tests/types.rs @@ -947,4 +947,58 @@ mod entities { assert_ne!(emoji.id, another_emoji.id); assert_ne!(emoji, another_emoji); } + + mod guild { + use std::hash::{Hash, Hasher}; + + use chorus::types::{Guild, GuildInvite}; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn guild_hash() { + let id: u64 = 1; + let mut guild1 = Guild::default(); + let mut guild2 = Guild::default(); + guild1.id = id.into(); + guild2.id = id.into(); + let mut hasher1 = std::collections::hash_map::DefaultHasher::new(); + guild1.hash(&mut hasher1); + + let mut hasher2 = std::collections::hash_map::DefaultHasher::new(); + guild2.hash(&mut hasher2); + + assert_eq!(hasher1.finish(), hasher2.finish()); + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn guild_invite_hash() { + let id: u64 = 1; + let mut invite1 = GuildInvite::default(); + let mut invite2 = GuildInvite::default(); + invite1.channel_id = id.into(); + invite2.channel_id = id.into(); + invite1.guild_id = id.into(); + invite2.guild_id = id.into(); + let mut hasher1 = std::collections::hash_map::DefaultHasher::new(); + invite1.hash(&mut hasher1); + + let mut hasher2 = std::collections::hash_map::DefaultHasher::new(); + invite2.hash(&mut hasher2); + + assert_eq!(hasher1.finish(), hasher2.finish()); + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn guild_partial_eq() { + let id: u64 = 1; + let mut guild1 = Guild::default(); + let mut guild2 = Guild::default(); + guild1.id = id.into(); + guild2.id = id.into(); + + assert_eq!(guild1, guild2); + } + } } From 00c70501c4cd2af422d370c410e47e90a88a0b1f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 23:06:14 +0100 Subject: [PATCH 10/21] Rename to_public_user into into_public_user --- src/types/entities/user.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index a7bdf63..d9f70ce 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -26,7 +26,7 @@ pub struct UserData { } impl User { - pub fn to_public_user(self) -> PublicUser { + pub fn into_public_user(self) -> PublicUser { PublicUser::from(self) } } From 41a0e2fe27dfe9acef650c9a22fc40234e270caa Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 23:06:24 +0100 Subject: [PATCH 11/21] Add to_public_user test --- tests/user.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/user.rs diff --git a/tests/user.rs b/tests/user.rs new file mode 100644 index 0000000..bf7938b --- /dev/null +++ b/tests/user.rs @@ -0,0 +1,18 @@ +use chorus::types::{PublicUser, Snowflake, User}; + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), test)] +fn to_public_user() { + let mut user = User::default(); + let mut public_user = PublicUser { + username: Some("".to_string()), + discriminator: Some("".to_string()), + ..Default::default() + }; + let id: Snowflake = 1_u64.into(); + user.id = id; + public_user.id = id; + + let from_user = user.into_public_user(); + assert_eq!(public_user, from_user); +} From a2b6d4e407b55d4a6264c350dbbaee426a14a668 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 23:11:37 +0100 Subject: [PATCH 12/21] Remove old/redundant code from attachment.rs --- src/api/channels/messages.rs | 6 +-- src/types/entities/attachment.rs | 70 -------------------------------- 2 files changed, 3 insertions(+), 73 deletions(-) diff --git a/src/api/channels/messages.rs b/src/api/channels/messages.rs index 6dfdfbf..3ee5228 100644 --- a/src/api/channels/messages.rs +++ b/src/api/channels/messages.rs @@ -36,7 +36,7 @@ impl Message { chorus_request.deserialize_response::(user).await } else { for (index, attachment) in message.attachments.iter_mut().enumerate() { - attachment.get_mut(index).unwrap().set_id(index as i16); + attachment.get_mut(index).unwrap().id = Some(index as i16); } let mut form = reqwest::multipart::Form::new(); let payload_json = to_string(&message).unwrap(); @@ -45,8 +45,8 @@ impl Message { form = form.part("payload_json", payload_field); for (index, attachment) in message.attachments.unwrap().into_iter().enumerate() { - let (attachment_content, current_attachment) = attachment.move_content(); - let (attachment_filename, _) = current_attachment.move_filename(); + let attachment_content = attachment.content; + let attachment_filename = attachment.filename; let part_name = format!("files[{}]", index); let content_disposition = format!( "form-data; name=\"{}\"'; filename=\"{}\"", diff --git a/src/types/entities/attachment.rs b/src/types/entities/attachment.rs index ffbc520..9aacc08 100644 --- a/src/types/entities/attachment.rs +++ b/src/types/entities/attachment.rs @@ -55,73 +55,3 @@ pub struct PartialDiscordFileAttachment { #[serde(skip_serializing)] pub content: Vec, } - -impl PartialDiscordFileAttachment { - /// Moves `self.content` out of `self` and returns it. - pub fn move_content(self) -> (Vec, PartialDiscordFileAttachment) { - let content = self.content; - let updated_struct = PartialDiscordFileAttachment { - id: self.id, - filename: self.filename, - description: self.description, - content_type: self.content_type, - size: self.size, - url: self.url, - proxy_url: self.proxy_url, - height: self.height, - width: self.width, - ephemeral: self.ephemeral, - duration_secs: self.duration_secs, - waveform: self.waveform, - content: Vec::new(), - }; - (content, updated_struct) - } - - /// Moves `self.filename` out of `self` and returns it. - pub fn move_filename(self) -> (String, PartialDiscordFileAttachment) { - let filename = self.filename; - let updated_struct = PartialDiscordFileAttachment { - id: self.id, - filename: String::new(), - description: self.description, - content_type: self.content_type, - size: self.size, - url: self.url, - proxy_url: self.proxy_url, - height: self.height, - width: self.width, - - ephemeral: self.ephemeral, - duration_secs: self.duration_secs, - waveform: self.waveform, - content: self.content, - }; - (filename, updated_struct) - } - - /// Moves `self.content_type` out of `self` and returns it. - pub fn move_content_type(self) -> (Option, PartialDiscordFileAttachment) { - let content_type = self.content_type; - let updated_struct = PartialDiscordFileAttachment { - id: self.id, - filename: self.filename, - description: self.description, - content_type: None, - size: self.size, - url: self.url, - proxy_url: self.proxy_url, - height: self.height, - width: self.width, - ephemeral: self.ephemeral, - duration_secs: self.duration_secs, - waveform: self.waveform, - content: self.content, - }; - (content_type, updated_struct) - } - - pub fn set_id(&mut self, id: i16) { - self.id = Some(id); - } -} From 9cc7ede7632702a12aeb1514e48fd100ca84c7e9 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 23:31:35 +0100 Subject: [PATCH 13/21] Add partial_eq test for relationship.rs/Relationship --- tests/types.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/types.rs b/tests/types.rs index 2caef09..7c40095 100644 --- a/tests/types.rs +++ b/tests/types.rs @@ -1001,4 +1001,36 @@ mod entities { assert_eq!(guild1, guild2); } } + + mod relationship { + use chorus::types::{IntoShared, Relationship, User}; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn relationship_partial_eq() { + let user = User::default(); + // These 2 users are different, because they do not have the same Snowflake "id". + let user_2 = User::default(); + let relationship_1 = Relationship { + id: 32_u64.into(), + relationship_type: chorus::types::RelationshipType::Friends, + nickname: Some("Xenia".to_string()), + user: user.into_public_user().into_shared(), + since: None, + }; + + let relationship_2 = Relationship { + id: 32_u64.into(), + relationship_type: chorus::types::RelationshipType::Friends, + nickname: Some("Xenia".to_string()), + user: user_2.into_public_user().into_shared(), + since: None, + }; + + // This should succeed, even though the two users' IDs are different. This is because + // `User` is only `PartialEq`, and the actual user object is not checked, since the + // `RwLock` would have to be locked. + assert_eq!(relationship_1, relationship_2); + } + } } From 98f42aa03bcedb9cb339721ddfb87a31e971b01f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 23:42:00 +0100 Subject: [PATCH 14/21] Add Message PartialEq Test --- tests/types.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/types.rs b/tests/types.rs index 7c40095..5acd4c6 100644 --- a/tests/types.rs +++ b/tests/types.rs @@ -1033,4 +1033,22 @@ mod entities { assert_eq!(relationship_1, relationship_2); } } + + mod message { + use chorus::types::{Message, Snowflake}; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] + fn message_partial_eq() { + let id: Snowflake = 1_u64.into(); + let mut message1 = Message::default(); + let mut message2 = Message::default(); + message1.id = id; + message1.channel_id = id; + message2.id = id; + message2.channel_id = id; + + assert_eq!(message1, message2); + } + } } From 970f5b8b4ff027b776b42c58586e092822641fbd Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 23 Jan 2024 23:50:22 +0100 Subject: [PATCH 15/21] Remove PartialOrd from Emoji because unneccessary --- src/types/entities/emoji.rs | 34 ---------------------------------- src/types/entities/message.rs | 2 +- src/types/entities/user.rs | 2 +- src/types/schema/guild.rs | 2 +- 4 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index 5170637..1c78cba 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -62,37 +62,3 @@ impl PartialEq for Emoji { || self.available != other.available) } } - -impl PartialOrd for Emoji { - fn partial_cmp(&self, other: &Self) -> Option { - match self.id.partial_cmp(&other.id) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.name.partial_cmp(&other.name) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.roles.partial_cmp(&other.roles) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.roles.partial_cmp(&other.roles) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.require_colons.partial_cmp(&other.require_colons) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.managed.partial_cmp(&other.managed) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.animated.partial_cmp(&other.animated) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - self.available.partial_cmp(&other.available) - } -} diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 923ee61..1e6810d 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -218,7 +218,7 @@ pub struct EmbedField { inline: Option, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialOrd, PartialEq)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Reaction { pub count: u32, pub burst_count: u32, diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index d9f70ce..90221ca 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -133,7 +133,7 @@ bitflags::bitflags! { } } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct UserProfileMetadata { pub guild_id: Option, pub pronouns: String, diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 56c0f9e..9d2c27d 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -78,7 +78,7 @@ impl std::default::Default for GetUserGuildSchema { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] pub struct GuildPreview { pub id: Snowflake, pub name: String, From 57e6cb438d69640175eed7588a3dde70f671bd1a Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jan 2024 12:21:46 +0100 Subject: [PATCH 16/21] Add test to hit ratelimit --- tests/ratelimit.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/ratelimit.rs diff --git a/tests/ratelimit.rs b/tests/ratelimit.rs new file mode 100644 index 0000000..f9498d7 --- /dev/null +++ b/tests/ratelimit.rs @@ -0,0 +1,23 @@ +use chorus::errors::ChorusError; + +mod common; + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn hit_ratelimit() { + let mut bundle = common::setup().await; + let mut _count = 0; + let guild = bundle.guild.read().unwrap().clone(); + while _count < 1000 { + _count += 1; + match guild.channels(&mut bundle.user).await { + Err(ChorusError::RateLimited { bucket: _ }) => { + return; + } + Err(_) => panic!("Hit different rate limit"), + _ => continue, + } + } + common::teardown(bundle).await; + panic!("Ratelimit never triggered"); +} From 3ffb124cd4a04c40c2fcb0bc08f6e05360dd0a2c Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jan 2024 12:32:08 +0100 Subject: [PATCH 17/21] Add test for get_limit_config --- tests/ratelimit.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/ratelimit.rs b/tests/ratelimit.rs index f9498d7..922857b 100644 --- a/tests/ratelimit.rs +++ b/tests/ratelimit.rs @@ -1,4 +1,5 @@ use chorus::errors::ChorusError; +use chorus::ratelimiter::ChorusRequest; mod common; @@ -21,3 +22,26 @@ async fn hit_ratelimit() { common::teardown(bundle).await; panic!("Ratelimit never triggered"); } + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn get_limit_config() { + let conf = ChorusRequest::get_limits_config("http://localhost:3001/api") + .await + .unwrap(); + assert!(conf.channel.max_pins > 0); + assert!(conf.channel.max_topic > 0); + assert!(conf.channel.max_webhooks > 0); + assert!(conf.guild.max_roles > 0); + assert!(conf.guild.max_channels > 0); + assert!(conf.guild.max_emojis > 0); + assert!(conf.guild.max_channels_in_category > 0); + assert!(conf.guild.max_members > 0); + assert!(conf.message.max_attachment_size > 0); + assert!(conf.message.max_bulk_delete > 0); + assert!(conf.message.max_reactions > 0); + assert!(conf.message.max_characters > 0); + assert!(conf.message.max_tts_characters == 0); + assert!(conf.user.max_guilds > 0); + assert!(conf.user.max_friends > 0); +} From e073ff26c400615274d41868c3c3af0234aa1af4 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jan 2024 18:51:10 +0100 Subject: [PATCH 18/21] remove hit limit test --- tests/ratelimit.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/tests/ratelimit.rs b/tests/ratelimit.rs index 922857b..8843ed0 100644 --- a/tests/ratelimit.rs +++ b/tests/ratelimit.rs @@ -1,28 +1,7 @@ -use chorus::errors::ChorusError; use chorus::ratelimiter::ChorusRequest; mod common; -#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] -#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] -async fn hit_ratelimit() { - let mut bundle = common::setup().await; - let mut _count = 0; - let guild = bundle.guild.read().unwrap().clone(); - while _count < 1000 { - _count += 1; - match guild.channels(&mut bundle.user).await { - Err(ChorusError::RateLimited { bucket: _ }) => { - return; - } - Err(_) => panic!("Hit different rate limit"), - _ => continue, - } - } - common::teardown(bundle).await; - panic!("Ratelimit never triggered"); -} - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn get_limit_config() { From c950288df1aee415f5b611c51fa85819c73faea3 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jan 2024 23:01:38 +0100 Subject: [PATCH 19/21] extend self updating structs test --- tests/gateway.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/gateway.rs b/tests/gateway.rs index 66259f7..0109e2f 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -2,7 +2,10 @@ mod common; use chorus::errors::GatewayError; use chorus::gateway::*; -use chorus::types::{self, ChannelModifySchema, IntoShared, RoleCreateModifySchema, RoleObject}; +use chorus::types::{ + self, Channel, ChannelCreateSchema, ChannelModifySchema, IntoShared, RoleCreateModifySchema, + RoleObject, +}; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] @@ -37,6 +40,7 @@ async fn test_gateway_authenticate() { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_self_updating_structs() { let mut bundle = common::setup().await; + let received_channel = bundle .user .gateway @@ -64,6 +68,34 @@ async fn test_self_updating_structs() { "selfupdating".to_string() ); + let guild = bundle + .user + .gateway + .observe_and_into_inner(bundle.guild.clone()) + .await; + assert!(guild.channels.is_none()); + + Channel::create( + &mut bundle.user, + guild.id, + None, + ChannelCreateSchema { + name: "selfupdating2".to_string(), + channel_type: Some(types::ChannelType::GuildText), + ..Default::default() + }, + ) + .await + .unwrap(); + + let guild = bundle + .user + .gateway + .observe_and_into_inner(guild.into_shared()) + .await; + assert!(guild.channels.is_some()); + assert!(guild.channels.as_ref().unwrap().len() == 1); + common::teardown(bundle).await } From 3040dcc46b66a221ae5b124392087f4519b3b761 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jan 2024 23:02:16 +0100 Subject: [PATCH 20/21] Add comment about test_self_updating_structs --- tests/gateway.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/gateway.rs b/tests/gateway.rs index 0109e2f..76f69ae 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -39,6 +39,8 @@ async fn test_gateway_authenticate() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_self_updating_structs() { + // PRETTYFYME: This test is a bit of a mess, but it works. Ideally, each self-updating struct + // would have its own test. let mut bundle = common::setup().await; let received_channel = bundle From 262a52a8e97ea36c4b51abaa668206b56f56ee85 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jan 2024 23:26:59 +0100 Subject: [PATCH 21/21] exclude trivial id() functions from coverage --- src/types/entities/voice_state.rs | 1 + src/types/events/auto_moderation.rs | 2 ++ src/types/events/channel.rs | 4 ++++ src/types/events/guild.rs | 6 ++++++ src/types/events/mod.rs | 1 + src/types/events/thread.rs | 1 + 6 files changed, 15 insertions(+) diff --git a/src/types/entities/voice_state.rs b/src/types/entities/voice_state.rs index 911cf96..035f8f9 100644 --- a/src/types/entities/voice_state.rs +++ b/src/types/entities/voice_state.rs @@ -47,6 +47,7 @@ pub struct VoiceState { } impl Updateable for VoiceState { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Snowflake { if let Some(id) = self.id { id // ID exists: Only the case for Spacebar Server impls diff --git a/src/types/events/auto_moderation.rs b/src/types/events/auto_moderation.rs index 2a2eb6b..b667486 100644 --- a/src/types/events/auto_moderation.rs +++ b/src/types/events/auto_moderation.rs @@ -31,7 +31,9 @@ pub struct AutoModerationRuleUpdate { } #[cfg(feature = "client")] +#[cfg(not(tarpaulin_include))] impl UpdateMessage for AutoModerationRuleUpdate { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { Some(self.rule.id) } diff --git a/src/types/events/channel.rs b/src/types/events/channel.rs index 5ca73ec..10e8561 100644 --- a/src/types/events/channel.rs +++ b/src/types/events/channel.rs @@ -39,6 +39,7 @@ impl WebSocketEvent for ChannelCreate {} #[cfg(feature = "client")] impl UpdateMessage for ChannelCreate { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { self.channel.guild_id } @@ -73,6 +74,8 @@ impl UpdateMessage for ChannelUpdate { let mut write = object_to_update.write().unwrap(); *write = self.channel.clone(); } + + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { Some(self.channel.id) } @@ -111,6 +114,7 @@ pub struct ChannelDelete { #[cfg(feature = "client")] impl UpdateMessage for ChannelDelete { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { self.channel.guild_id } diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index 04f871a..a460403 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -30,7 +30,9 @@ pub struct GuildCreate { } #[cfg(feature = "client")] +#[cfg(not(tarpaulin_include))] impl UpdateMessage for GuildCreate { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { match &self.d { GuildCreateDataOption::UnavailableGuild(unavailable) => Some(unavailable.id), @@ -92,6 +94,7 @@ impl WebSocketEvent for GuildUpdate {} #[cfg(feature = "client")] impl UpdateMessage for GuildUpdate { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { Some(self.guild.id) } @@ -111,6 +114,7 @@ pub struct GuildDelete { #[cfg(feature = "client")] impl UpdateMessage for GuildDelete { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { Some(self.guild.id) } @@ -225,6 +229,7 @@ impl WebSocketEvent for GuildRoleCreate {} #[cfg(feature = "client")] impl UpdateMessage for GuildRoleCreate { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { Some(self.guild_id) } @@ -258,6 +263,7 @@ impl WebSocketEvent for GuildRoleUpdate {} #[cfg(feature = "client")] impl UpdateMessage for GuildRoleUpdate { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { Some(self.role.id) } diff --git a/src/types/events/mod.rs b/src/types/events/mod.rs index 5644d8a..5c8e6c4 100644 --- a/src/types/events/mod.rs +++ b/src/types/events/mod.rs @@ -135,6 +135,7 @@ where fn update(&mut self, object_to_update: Shared) { update_object(self.get_json(), object_to_update) } + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option; } diff --git a/src/types/events/thread.rs b/src/types/events/thread.rs index cff5f6f..34dd1a2 100644 --- a/src/types/events/thread.rs +++ b/src/types/events/thread.rs @@ -32,6 +32,7 @@ impl WebSocketEvent for ThreadUpdate {} #[cfg(feature = "client")] impl UpdateMessage for ThreadUpdate { + #[cfg(not(tarpaulin_include))] fn id(&self) -> Option { Some(self.thread.id) }