From 27ef3409c28b1042c1bc358e169dbc0d61c404b4 Mon Sep 17 00:00:00 2001 From: puh Date: Sun, 5 Feb 2023 17:15:39 +0300 Subject: [PATCH 1/4] add macro to implement Deserialize on ApiError enum --- crates/teloxide-core/src/errors.rs | 364 ++++++++++++----------------- crates/teloxide/tests/errors.rs | 212 +++++++++++++++++ 2 files changed, 361 insertions(+), 215 deletions(-) create mode 100644 crates/teloxide/tests/errors.rs diff --git a/crates/teloxide-core/src/errors.rs b/crates/teloxide-core/src/errors.rs index 41acffdf..882433ef 100644 --- a/crates/teloxide-core/src/errors.rs +++ b/crates/teloxide-core/src/errors.rs @@ -2,7 +2,6 @@ use std::{io, time::Duration}; -use serde::Deserialize; use thiserror::Error; use crate::types::ResponseParameters; @@ -89,21 +88,93 @@ impl AsResponseParameters for crate::RequestError { } } +macro_rules! match_prefix { + ("") => {{ + |data: &str| Some(data.to_owned()) + }}; + ($prefix: literal) => {{ + |data: &str| { + if data.starts_with($prefix) { + Some(data.to_owned()) + } else { + None + } + } + }}; +} + +macro_rules! impl_api_error { + ( + $(#[$meta: meta])* + $vis: vis enum $ident: ident { + $($(#[$var_meta: meta])* + $var_name: ident$(($var_inner: ty))? = $var_string: literal $(with $var_parser: block)?),* } ) => { + + $(#[$meta])* + #[derive(Error)] + $vis enum $ident { + $( + + $(#[$var_meta])* + #[error($var_string)] + $var_name $(($var_inner))*, + + )* + } + + const _: () = { + struct Visitor; + + impl<'de> ::serde::de::Visitor<'de> for Visitor { + type Value = $ident; + + fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + formatter.write_str("telegram api error string") + } + + fn visit_str(self, v: &str) -> Result + where + E: ::serde::de::Error, + { + $(impl_api_error!(@de v, $var_name, $var_string $(, $var_parser)*);)* + Err(E::unknown_variant(v, &[])) + } + } + + impl<'de> ::serde::de::Deserialize<'de> for $ident { + fn deserialize(deserializer: D) -> Result + where + D: ::serde::de::Deserializer<'de>, + { + deserializer.deserialize_str(Visitor) + } + } + }; + }; + (@de $value: ident, $variant: ident, $val: literal) => { + if $value == $val { + return Ok(Self::Value::$variant) + } + }; + (@de $value: ident, $variant: ident, $val: literal, $block: expr) => { + match $block($value) { + Some(data) => return Ok(Self::Value::$variant(data)), + _ => {} + } + }; +} + +impl_api_error! { /// A kind of an API error. -#[derive(Debug, Error, Deserialize, PartialEq, Hash, Eq, Clone)] -#[serde(field_identifier)] +#[derive(Debug, PartialEq, Hash, Eq, Clone)] #[non_exhaustive] pub enum ApiError { /// Occurs when the bot tries to send message to user who blocked the bot. - #[serde(rename = "Forbidden: bot was blocked by the user")] - #[error("Forbidden: bot was blocked by the user")] - BotBlocked, + BotBlocked = "Forbidden: bot was blocked by the user", /// Occurs when the bot token is incorrect. // FIXME: rename this to something akin "InvalidToken" - #[serde(rename = "Unauthorized")] - #[error("Unauthorized")] - NotFound, + NotFound = "Unauthorized", /// Occurs when bot tries to modify a message without modification content. /// @@ -111,14 +182,8 @@ pub enum ApiError { /// 1. [`EditMessageText`] /// /// [`EditMessageText`]: crate::payloads::EditMessageText - #[serde(rename = "Bad Request: message is not modified: specified new message content and \ - reply markup are exactly the same as a current content and reply markup \ - of the message")] - #[error( - "Bad Request: message is not modified: specified new message content and reply markup are \ - exactly the same as a current content and reply markup of the message" - )] - MessageNotModified, + MessageNotModified = "Bad Request: message is not modified: specified new message content and reply markup are \ + exactly the same as a current content and reply markup of the message", /// Occurs when bot tries to forward or delete a message which was deleted. /// @@ -128,9 +193,7 @@ pub enum ApiError { /// /// [`ForwardMessage`]: crate::payloads::ForwardMessage /// [`DeleteMessage`]: crate::payloads::DeleteMessage - #[serde(rename = "Bad Request: MESSAGE_ID_INVALID")] - #[error("Bad Request: MESSAGE_ID_INVALID")] - MessageIdInvalid, + MessageIdInvalid = "Bad Request: MESSAGE_ID_INVALID", /// Occurs when bot tries to forward a message which does not exists. /// @@ -138,9 +201,7 @@ pub enum ApiError { /// 1. [`ForwardMessage`] /// /// [`ForwardMessage`]: crate::payloads::ForwardMessage - #[serde(rename = "Bad Request: message to forward not found")] - #[error("Bad Request: message to forward not found")] - MessageToForwardNotFound, + MessageToForwardNotFound = "Bad Request: message to forward not found", /// Occurs when bot tries to delete a message which does not exists. /// @@ -148,9 +209,7 @@ pub enum ApiError { /// 1. [`DeleteMessage`] /// /// [`DeleteMessage`]: crate::payloads::DeleteMessage - #[serde(rename = "Bad Request: message to delete not found")] - #[error("Bad Request: message to delete not found")] - MessageToDeleteNotFound, + MessageToDeleteNotFound = "Bad Request: message to delete not found", /// Occurs when bot tries to send a text message without text. /// @@ -158,9 +217,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: message text is empty")] - #[error("Bad Request: message text is empty")] - MessageTextIsEmpty, + MessageTextIsEmpty = "Bad Request: message text is empty", /// Occurs when bot tries to edit a message after long time. /// @@ -168,9 +225,7 @@ pub enum ApiError { /// 1. [`EditMessageText`] /// /// [`EditMessageText`]: crate::payloads::EditMessageText - #[serde(rename = "Bad Request: message can't be edited")] - #[error("Bad Request: message can't be edited")] - MessageCantBeEdited, + MessageCantBeEdited = "Bad Request: message can't be edited", /// Occurs when bot tries to delete a someone else's message in group where /// it does not have enough rights. @@ -179,9 +234,7 @@ pub enum ApiError { /// 1. [`DeleteMessage`] /// /// [`DeleteMessage`]: crate::payloads::DeleteMessage - #[serde(rename = "Bad Request: message can't be deleted")] - #[error("Bad Request: message can't be deleted")] - MessageCantBeDeleted, + MessageCantBeDeleted = "Bad Request: message can't be deleted", /// Occurs when bot tries to edit a message which does not exists. /// @@ -189,9 +242,7 @@ pub enum ApiError { /// 1. [`EditMessageText`] /// /// [`EditMessageText`]: crate::payloads::EditMessageText - #[serde(rename = "Bad Request: message to edit not found")] - #[error("Bad Request: message to edit not found")] - MessageToEditNotFound, + MessageToEditNotFound = "Bad Request: message to edit not found", /// Occurs when bot tries to reply to a message which does not exists. /// @@ -199,14 +250,10 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: reply message not found")] - #[error("Bad Request: reply message not found")] - MessageToReplyNotFound, + MessageToReplyNotFound = "Bad Request: reply message not found", /// Occurs when bot tries to - #[serde(rename = "Bad Request: message identifier is not specified")] - #[error("Bad Request: message identifier is not specified")] - MessageIdentifierNotSpecified, + MessageIdentifierNotSpecified = "Bad Request: message identifier is not specified", /// Occurs when bot tries to send a message with text size greater then /// 4096 symbols. @@ -215,9 +262,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: message is too long")] - #[error("Bad Request: message is too long")] - MessageIsTooLong, + MessageIsTooLong = "Bad Request: message is too long", /// Occurs when bot tries to edit a message with text size greater then /// 4096 symbols. @@ -232,9 +277,7 @@ pub enum ApiError { /// [`EditMessageTextInline`]: crate::payloads::EditMessageTextInline /// [`EditMessageCaption`]: crate::payloads::EditMessageCaption /// [`EditMessageCaptionInline`]: crate::payloads::EditMessageCaptionInline - #[serde(rename = "Bad Request: MESSAGE_TOO_LONG")] - #[error("Bad Request: MESSAGE_TOO_LONG")] - EditedMessageIsTooLong, + EditedMessageIsTooLong = "Bad Request: MESSAGE_TOO_LONG", /// Occurs when bot tries to send media group with more than 10 items. /// @@ -242,9 +285,7 @@ pub enum ApiError { /// 1. [`SendMediaGroup`] /// /// [`SendMediaGroup`]: crate::payloads::SendMediaGroup - #[serde(rename = "Bad Request: Too much messages to send as an album")] - #[error("Bad Request: Too much messages to send as an album")] - ToMuchMessages, + ToMuchMessages = "Bad Request: Too much messages to send as an album", /// Occurs when bot tries to answer an inline query with more than 50 /// results. @@ -255,9 +296,7 @@ pub enum ApiError { /// 1. [`AnswerInlineQuery`] /// /// [`AnswerInlineQuery`]: crate::payloads::AnswerInlineQuery - #[serde(rename = "Bad Request: RESULTS_TOO_MUCH")] - #[error("Bad Request: RESULTS_TOO_MUCH")] - TooMuchInlineQueryResults, + TooMuchInlineQueryResults = "Bad Request: RESULTS_TOO_MUCH", /// Occurs when bot tries to stop poll that has already been stopped. /// @@ -265,9 +304,7 @@ pub enum ApiError { /// 1. [`SendPoll`] /// /// [`SendPoll`]: crate::payloads::SendPoll - #[serde(rename = "Bad Request: poll has already been closed")] - #[error("Bad Request: poll has already been closed")] - PollHasAlreadyClosed, + PollHasAlreadyClosed = "Bad Request: poll has already been closed", /// Occurs when bot tries to send poll with less than 2 options. /// @@ -275,9 +312,7 @@ pub enum ApiError { /// 1. [`SendPoll`] /// /// [`SendPoll`]: crate::payloads::SendPoll - #[serde(rename = "Bad Request: poll must have at least 2 option")] - #[error("Bad Request: poll must have at least 2 option")] - PollMustHaveMoreOptions, + PollMustHaveMoreOptions = "Bad Request: poll must have at least 2 option", /// Occurs when bot tries to send poll with more than 10 options. /// @@ -285,9 +320,7 @@ pub enum ApiError { /// 1. [`SendPoll`] /// /// [`SendPoll`]: crate::payloads::SendPoll - #[serde(rename = "Bad Request: poll can't have more than 10 options")] - #[error("Bad Request: poll can't have more than 10 options")] - PollCantHaveMoreOptions, + PollCantHaveMoreOptions = "Bad Request: poll can't have more than 10 options", /// Occurs when bot tries to send poll with empty option (without text). /// @@ -295,9 +328,7 @@ pub enum ApiError { /// 1. [`SendPoll`] /// /// [`SendPoll`]: crate::payloads::SendPoll - #[serde(rename = "Bad Request: poll options must be non-empty")] - #[error("Bad Request: poll options must be non-empty")] - PollOptionsMustBeNonEmpty, + PollOptionsMustBeNonEmpty = "Bad Request: poll options must be non-empty", /// Occurs when bot tries to send poll with empty question (without text). /// @@ -305,9 +336,7 @@ pub enum ApiError { /// 1. [`SendPoll`] /// /// [`SendPoll`]: crate::payloads::SendPoll - #[serde(rename = "Bad Request: poll question must be non-empty")] - #[error("Bad Request: poll question must be non-empty")] - PollQuestionMustBeNonEmpty, + PollQuestionMustBeNonEmpty = "Bad Request: poll question must be non-empty", /// Occurs when bot tries to send poll with total size of options more than /// 100 symbols. @@ -316,9 +345,7 @@ pub enum ApiError { /// 1. [`SendPoll`] /// /// [`SendPoll`]: crate::payloads::SendPoll - #[serde(rename = "Bad Request: poll options length must not exceed 100")] - #[error("Bad Request: poll options length must not exceed 100")] - PollOptionsLengthTooLong, + PollOptionsLengthTooLong = "Bad Request: poll options length must not exceed 100", /// Occurs when bot tries to send poll with question size more than 255 /// symbols. @@ -327,9 +354,7 @@ pub enum ApiError { /// 1. [`SendPoll`] /// /// [`SendPoll`]: crate::payloads::SendPoll - #[serde(rename = "Bad Request: poll question length must not exceed 255")] - #[error("Bad Request: poll question length must not exceed 255")] - PollQuestionLengthTooLong, + PollQuestionLengthTooLong = "Bad Request: poll question length must not exceed 255", /// Occurs when bot tries to stop poll with message without poll. /// @@ -337,9 +362,7 @@ pub enum ApiError { /// 1. [`StopPoll`] /// /// [`StopPoll`]: crate::payloads::StopPoll - #[serde(rename = "Bad Request: message with poll to stop not found")] - #[error("Bad Request: message with poll to stop not found")] - MessageWithPollNotFound, + MessageWithPollNotFound = "Bad Request: message with poll to stop not found", /// Occurs when bot tries to stop poll with message without poll. /// @@ -347,9 +370,7 @@ pub enum ApiError { /// 1. [`StopPoll`] /// /// [`StopPoll`]: crate::payloads::StopPoll - #[serde(rename = "Bad Request: message is not a poll")] - #[error("Bad Request: message is not a poll")] - MessageIsNotAPoll, + MessageIsNotAPoll = "Bad Request: message is not a poll", /// Occurs when bot tries to send a message to chat in which it is not a /// member. @@ -358,9 +379,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: chat not found")] - #[error("Bad Request: chat not found")] - ChatNotFound, + ChatNotFound = "Bad Request: chat not found", /// Occurs when bot tries to send method with unknown user_id. /// @@ -369,9 +388,7 @@ pub enum ApiError { /// /// [`getUserProfilePhotos`]: /// crate::payloads::GetUserProfilePhotos - #[serde(rename = "Bad Request: user not found")] - #[error("Bad Request: user not found")] - UserNotFound, + UserNotFound = "Bad Request: user not found", /// Occurs when bot tries to send [`SetChatDescription`] with same text as /// in the current description. @@ -380,9 +397,7 @@ pub enum ApiError { /// 1. [`SetChatDescription`] /// /// [`SetChatDescription`]: crate::payloads::SetChatDescription - #[serde(rename = "Bad Request: chat description is not modified")] - #[error("Bad Request: chat description is not modified")] - ChatDescriptionIsNotModified, + ChatDescriptionIsNotModified = "Bad Request: chat description is not modified", /// Occurs when bot tries to answer to query after timeout expire. /// @@ -390,10 +405,7 @@ pub enum ApiError { /// 1. [`AnswerCallbackQuery`] /// /// [`AnswerCallbackQuery`]: crate::payloads::AnswerCallbackQuery - #[serde(rename = "Bad Request: query is too old and response timeout expired or query id is \ - invalid")] - #[error("Bad Request: query is too old and response timeout expired or query id is invalid")] - InvalidQueryId, + InvalidQueryId = "Bad Request: query is too old and response timeout expired or query id is invalid", /// Occurs when bot tries to send InlineKeyboardMarkup with invalid button /// url. @@ -402,9 +414,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: BUTTON_URL_INVALID")] - #[error("Bad Request: BUTTON_URL_INVALID")] - ButtonUrlInvalid, + ButtonUrlInvalid = "Bad Request: BUTTON_URL_INVALID", /// Occurs when bot tries to send button with data size more than 64 bytes. /// @@ -412,9 +422,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: BUTTON_DATA_INVALID")] - #[error("Bad Request: BUTTON_DATA_INVALID")] - ButtonDataInvalid, + ButtonDataInvalid = "Bad Request: BUTTON_DATA_INVALID", /// Occurs when bot tries to send button with data size == 0. /// @@ -422,13 +430,8 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: can't parse inline keyboard button: Text buttons are \ - unallowed in the inline keyboard")] - #[error( - "Bad Request: can't parse inline keyboard button: Text buttons are unallowed in the \ - inline keyboard" - )] - TextButtonsAreUnallowed, + TextButtonsAreUnallowed = "Bad Request: can't parse inline keyboard button: Text buttons are unallowed in the \ + inline keyboard", /// Occurs when bot tries to get file by wrong file id. /// @@ -436,34 +439,24 @@ pub enum ApiError { /// 1. [`GetFile`] /// /// [`GetFile`]: crate::payloads::GetFile - #[serde(rename = "Bad Request: wrong file id")] - #[error("Bad Request: wrong file id")] - WrongFileId, + WrongFileId = "Bad Request: wrong file id", /// Occurs when bot tries to send files with wrong file identifier or HTTP /// url - #[serde(rename = "Bad Request: wrong file identifier/HTTP URL specified")] - #[error("Bad Request: wrong file identifier/HTTP URL specified")] - WrongFileIdOrUrl, + WrongFileIdOrUrl = "Bad Request: wrong file identifier/HTTP URL specified", /// Occurs when When sending files with an url to a site that doesn't /// respond. - #[serde(rename = "Bad Request: failed to get HTTP URL content")] - #[error("Bad Request: failed to get HTTP URL content")] - FailedToGetUrlContent, + FailedToGetUrlContent = "Bad Request: failed to get HTTP URL content", /// Occurs when bot tries to do some with group which was deactivated. - #[serde(rename = "Bad Request: group is deactivated")] - #[error("Bad Request: group is deactivated")] - GroupDeactivated, + GroupDeactivated = "Bad Request: group is deactivated", /// Occurs when image processing fails on telegram's side. /// /// This is likely caused by an incorrectly encoded image, make sure that /// the image is correctly encoded in a format telegram accepts. - #[serde(rename = "Bad Request: IMAGE_PROCESS_FAILED")] - #[error("Bad Request: IMAGE_PROCESS_FAILED")] - ImageProcessFailed, + ImageProcessFailed = "Bad Request: IMAGE_PROCESS_FAILED", /// Occurs when bot tries to set chat photo from file ID /// @@ -471,9 +464,7 @@ pub enum ApiError { /// 1. [`SetChatPhoto`] /// /// [`SetChatPhoto`]: crate::payloads::SetChatPhoto - #[serde(rename = "Bad Request: Photo should be uploaded as an InputFile")] - #[error("Bad Request: Photo should be uploaded as an InputFile")] - PhotoAsInputFileRequired, + PhotoAsInputFileRequired = "Bad Request: Photo should be uploaded as an InputFile", /// Occurs when bot tries to add sticker to stickerset by invalid name. /// @@ -481,9 +472,7 @@ pub enum ApiError { /// 1. [`AddStickerToSet`] /// /// [`AddStickerToSet`]: crate::payloads::AddStickerToSet - #[serde(rename = "Bad Request: STICKERSET_INVALID")] - #[error("Bad Request: STICKERSET_INVALID")] - InvalidStickersSet, + InvalidStickersSet = "Bad Request: STICKERSET_INVALID", /// Occurs when bot tries to create a sticker set with a name that is /// already used by another sticker set. @@ -492,9 +481,7 @@ pub enum ApiError { /// 1. [`CreateNewStickerSet`] /// /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet - #[serde(rename = "Bad Request: sticker set name is already occupied")] - #[error("Bad Request: sticker set name is already occupied")] - StickerSetNameOccupied, + StickerSetNameOccupied = "Bad Request: sticker set name is already occupied", /// Occurs when bot tries to create a sticker set with user id of a bot. /// @@ -502,9 +489,7 @@ pub enum ApiError { /// 1. [`CreateNewStickerSet`] /// /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet - #[serde(rename = "Bad Request: USER_IS_BOT")] - #[error("Bad Request: USER_IS_BOT")] - StickerSetOwnerIsBot, + StickerSetOwnerIsBot = "Bad Request: USER_IS_BOT", /// Occurs when bot tries to create a sticker set with invalid name. /// @@ -519,9 +504,7 @@ pub enum ApiError { /// 1. [`CreateNewStickerSet`] /// /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet - #[serde(rename = "Bad Request: invalid sticker set name is specified")] - #[error("Bad Request: invalid sticker set name is specified")] - InvalidStickerName, + InvalidStickerName = "Bad Request: invalid sticker set name is specified", /// Occurs when bot tries to pin a message without rights to pin in this /// chat. @@ -530,9 +513,7 @@ pub enum ApiError { /// 1. [`PinChatMessage`] /// /// [`PinChatMessage`]: crate::payloads::PinChatMessage - #[serde(rename = "Bad Request: not enough rights to pin a message")] - #[error("Bad Request: not enough rights to pin a message")] - NotEnoughRightsToPinMessage, + NotEnoughRightsToPinMessage = "Bad Request: not enough rights to pin a message", /// Occurs when bot tries to pin or unpin a message without rights to pin /// in this chat. @@ -543,9 +524,7 @@ pub enum ApiError { /// /// [`PinChatMessage`]: crate::payloads::PinChatMessage /// [`UnpinChatMessage`]: crate::payloads::UnpinChatMessage - #[serde(rename = "Bad Request: not enough rights to manage pinned messages in the chat")] - #[error("Bad Request: not enough rights to manage pinned messages in the chat")] - NotEnoughRightsToManagePins, + NotEnoughRightsToManagePins = "Bad Request: not enough rights to manage pinned messages in the chat", /// Occurs when bot tries change default chat permissions without "Ban /// Users" permission in this chat. @@ -554,15 +533,11 @@ pub enum ApiError { /// 1. [`SetChatPermissions`] /// /// [`SetChatPermissions`]: crate::payloads::SetChatPermissions - #[serde(rename = "Bad Request: not enough rights to change chat permissions")] - #[error("Bad Request: not enough rights to change chat permissions")] - NotEnoughRightsToChangeChatPermissions, + NotEnoughRightsToChangeChatPermissions = "Bad Request: not enough rights to change chat permissions", /// Occurs when bot tries to use method in group which is allowed only in a /// supergroup or channel. - #[serde(rename = "Bad Request: method is available only for supergroups and channel")] - #[error("Bad Request: method is available only for supergroups and channel")] - MethodNotAvailableInPrivateChats, + MethodNotAvailableInPrivateChats = "Bad Request: method is available only for supergroups and channel", /// Occurs when bot tries to demote chat creator. /// @@ -570,9 +545,7 @@ pub enum ApiError { /// 1. [`PromoteChatMember`] /// /// [`PromoteChatMember`]: crate::payloads::PromoteChatMember - #[serde(rename = "Bad Request: can't demote chat creator")] - #[error("Bad Request: can't demote chat creator")] - CantDemoteChatCreator, + CantDemoteChatCreator = "Bad Request: can't demote chat creator", /// Occurs when bot tries to restrict self in group chats. /// @@ -580,9 +553,7 @@ pub enum ApiError { /// 1. [`RestrictChatMember`] /// /// [`RestrictChatMember`]: crate::payloads::RestrictChatMember - #[serde(rename = "Bad Request: can't restrict self")] - #[error("Bad Request: can't restrict self")] - CantRestrictSelf, + CantRestrictSelf = "Bad Request: can't restrict self", /// Occurs when bot tries to restrict chat member without rights to /// restrict in this chat. @@ -591,15 +562,11 @@ pub enum ApiError { /// 1. [`RestrictChatMember`] /// /// [`RestrictChatMember`]: crate::payloads::RestrictChatMember - #[serde(rename = "Bad Request: not enough rights to restrict/unrestrict chat member")] - #[error("Bad Request: not enough rights to restrict/unrestrict chat member")] - NotEnoughRightsToRestrict, + NotEnoughRightsToRestrict = "Bad Request: not enough rights to restrict/unrestrict chat member", /// Occurs when bot tries to post a message in a channel without "Post /// Messages" admin right. - #[serde(rename = "Bad Request: need administrator rights in the channel chat")] - #[error("Bad Request: need administrator rights in the channel chat")] - NotEnoughRightsToPostMessages, + NotEnoughRightsToPostMessages = "Bad Request: need administrator rights in the channel chat", /// Occurs when bot tries set webhook to protocol other than HTTPS. /// @@ -607,9 +574,7 @@ pub enum ApiError { /// 1. [`SetWebhook`] /// /// [`SetWebhook`]: crate::payloads::SetWebhook - #[serde(rename = "Bad Request: bad webhook: HTTPS url must be provided for webhook")] - #[error("Bad Request: bad webhook: HTTPS url must be provided for webhook")] - WebhookRequireHttps, + WebhookRequireHttps = "Bad Request: bad webhook: HTTPS url must be provided for webhook", /// Occurs when bot tries to set webhook to port other than 80, 88, 443 or /// 8443. @@ -618,10 +583,7 @@ pub enum ApiError { /// 1. [`SetWebhook`] /// /// [`SetWebhook`]: crate::payloads::SetWebhook - #[serde(rename = "Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 \ - or 8443")] - #[error("Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443")] - BadWebhookPort, + BadWebhookPort = "Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443", /// Occurs when bot tries to set webhook to unknown host. /// @@ -629,9 +591,7 @@ pub enum ApiError { /// 1. [`SetWebhook`] /// /// [`SetWebhook`]: crate::payloads::SetWebhook - #[serde(rename = "Bad Request: bad webhook: Failed to resolve host: Name or service not known")] - #[error("Bad Request: bad webhook: Failed to resolve host: Name or service not known")] - UnknownHost, + UnknownHost = "Bad Request: bad webhook: Failed to resolve host: Name or service not known", /// Occurs when bot tries to set webhook to invalid URL. /// @@ -639,9 +599,7 @@ pub enum ApiError { /// 1. [`SetWebhook`] /// /// [`SetWebhook`]: crate::payloads::SetWebhook - #[serde(rename = "Bad Request: can't parse URL")] - #[error("Bad Request: can't parse URL")] - CantParseUrl, + CantParseUrl = "Bad Request: can't parse URL", /// Occurs when bot tries to send message with unfinished entities. /// @@ -649,9 +607,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: can't parse entities")] - #[error("Bad Request: can't parse entities")] - CantParseEntities, + CantParseEntities(String) = "{0}" with {match_prefix!("Bad Request: can't parse entities")}, /// Occurs when bot tries to use getUpdates while webhook is active. /// @@ -659,9 +615,7 @@ pub enum ApiError { /// 1. [`GetUpdates`] /// /// [`GetUpdates`]: crate::payloads::GetUpdates - #[serde(rename = "can't use getUpdates method while webhook is active")] - #[error("can't use getUpdates method while webhook is active")] - CantGetUpdates, + CantGetUpdates = "can't use getUpdates method while webhook is active", /// Occurs when bot tries to do some in group where bot was kicked. /// @@ -669,9 +623,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Unauthorized: bot was kicked from a chat")] - #[error("Unauthorized: bot was kicked from a chat")] - BotKicked, + BotKicked = "Unauthorized: bot was kicked from a chat", /// Occurs when bot tries to do something in a supergroup the bot was /// kicked from. @@ -680,9 +632,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Forbidden: bot was kicked from the supergroup chat")] - #[error("Forbidden: bot was kicked from the supergroup chat")] - BotKickedFromSupergroup, + BotKickedFromSupergroup = "Forbidden: bot was kicked from the supergroup chat", /// Occurs when bot tries to send a message to a deactivated user (i.e. a /// user that was banned by telegram). @@ -691,9 +641,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Forbidden: user is deactivated")] - #[error("Forbidden: user is deactivated")] - UserDeactivated, + UserDeactivated = "Forbidden: user is deactivated", /// Occurs when you tries to initiate conversation with a user. /// @@ -701,9 +649,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Unauthorized: bot can't initiate conversation with a user")] - #[error("Unauthorized: bot can't initiate conversation with a user")] - CantInitiateConversation, + CantInitiateConversation = "Unauthorized: bot can't initiate conversation with a user", /// Occurs when you tries to send message to bot. /// @@ -711,9 +657,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Unauthorized: bot can't send messages to bots")] - #[error("Unauthorized: bot can't send messages to bots")] - CantTalkWithBots, + CantTalkWithBots = "Unauthorized: bot can't send messages to bots", /// Occurs when bot tries to send button with invalid http url. /// @@ -721,9 +665,7 @@ pub enum ApiError { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - #[serde(rename = "Bad Request: wrong HTTP URL")] - #[error("Bad Request: wrong HTTP URL")] - WrongHttpUrl, + WrongHttpUrl = "Bad Request: wrong HTTP URL", /// Occurs when bot tries GetUpdate before the timeout. Make sure that only /// one Updater is running. @@ -732,13 +674,8 @@ pub enum ApiError { /// 1. [`GetUpdates`] /// /// [`GetUpdates`]: crate::payloads::GetUpdates - #[serde(rename = "Conflict: terminated by other getUpdates request; make sure that only one \ - bot instance is running")] - #[error( - "Conflict: terminated by other getUpdates request; make sure that only one bot instance \ - is running" - )] - TerminatedByOtherGetUpdates, + TerminatedByOtherGetUpdates = "Conflict: terminated by other getUpdates request; make sure that only one bot instance \ + is running", /// Occurs when bot tries to get file by invalid file id. /// @@ -746,9 +683,7 @@ pub enum ApiError { /// 1. [`GetFile`] /// /// [`GetFile`]: crate::payloads::GetFile - #[serde(rename = "Bad Request: invalid file id")] - #[error("Bad Request: invalid file id")] - FileIdInvalid, + FileIdInvalid = "Bad Request: invalid file id", /// Occurs when bot tries to upload a file which is larger than 50 MB using /// multipart/form-data. @@ -759,9 +694,8 @@ pub enum ApiError { /// /// [`SendVideo`]: crate::payloads::SendVideo /// [`SendDocument`]: crate::payloads::SendDocument - #[serde(rename = "Request Entity Too Large")] - #[error("Request Entity Too Large")] - RequestEntityTooLarge, + RequestEntityTooLarge = "Request Entity Too Large", + /// Error which is not known to `teloxide`. /// @@ -769,8 +703,8 @@ pub enum ApiError { /// description of the error. /// /// [open an issue]: https://github.com/teloxide/teloxide/issues/new - #[error("Unknown error: {0:?}")] - Unknown(String), + Unknown(String) = "Unknown error: {0:?}" with {match_prefix!("")} +} } /// This impl allows to use `?` to propagate [`DownloadError`]s in function diff --git a/crates/teloxide/tests/errors.rs b/crates/teloxide/tests/errors.rs new file mode 100644 index 00000000..f0edcf78 --- /dev/null +++ b/crates/teloxide/tests/errors.rs @@ -0,0 +1,212 @@ +use serde::Deserialize; + +#[test] +fn custom_result() { + use teloxide_core::ApiError; + + let cases = &[ + ("{\"data\": \"Forbidden: bot was blocked by the user\"}", ApiError::BotBlocked), + ("{\"data\": \"Unauthorized\"}", ApiError::NotFound), + ( + "{\"data\": \"Bad Request: message is not modified: specified new message content and \ + reply markup are exactly the same as a current content and reply markup of the \ + message\"}", + ApiError::MessageNotModified, + ), + ("{\"data\": \"Bad Request: MESSAGE_ID_INVALID\"}", ApiError::MessageIdInvalid), + ( + "{\"data\": \"Bad Request: message to forward not found\"}", + ApiError::MessageToForwardNotFound, + ), + ( + "{\"data\": \"Bad Request: message to delete not found\"}", + ApiError::MessageToDeleteNotFound, + ), + ("{\"data\": \"Bad Request: message text is empty\"}", ApiError::MessageTextIsEmpty), + ("{\"data\": \"Bad Request: message can't be edited\"}", ApiError::MessageCantBeEdited), + ("{\"data\": \"Bad Request: message can't be deleted\"}", ApiError::MessageCantBeDeleted), + ("{\"data\": \"Bad Request: message to edit not found\"}", ApiError::MessageToEditNotFound), + ("{\"data\": \"Bad Request: reply message not found\"}", ApiError::MessageToReplyNotFound), + ( + "{\"data\": \"Bad Request: message identifier is not specified\"}", + ApiError::MessageIdentifierNotSpecified, + ), + ("{\"data\": \"Bad Request: message is too long\"}", ApiError::MessageIsTooLong), + ("{\"data\": \"Bad Request: MESSAGE_TOO_LONG\"}", ApiError::EditedMessageIsTooLong), + ( + "{\"data\": \"Bad Request: Too much messages to send as an album\"}", + ApiError::ToMuchMessages, + ), + ("{\"data\": \"Bad Request: RESULTS_TOO_MUCH\"}", ApiError::TooMuchInlineQueryResults), + ( + "{\"data\": \"Bad Request: poll has already been closed\"}", + ApiError::PollHasAlreadyClosed, + ), + ( + "{\"data\": \"Bad Request: poll must have at least 2 option\"}", + ApiError::PollMustHaveMoreOptions, + ), + ( + "{\"data\": \"Bad Request: poll can't have more than 10 options\"}", + ApiError::PollCantHaveMoreOptions, + ), + ( + "{\"data\": \"Bad Request: poll options must be non-empty\"}", + ApiError::PollOptionsMustBeNonEmpty, + ), + ( + "{\"data\": \"Bad Request: poll question must be non-empty\"}", + ApiError::PollQuestionMustBeNonEmpty, + ), + ( + "{\"data\": \"Bad Request: poll options length must not exceed 100\"}", + ApiError::PollOptionsLengthTooLong, + ), + ( + "{\"data\": \"Bad Request: poll question length must not exceed 255\"}", + ApiError::PollQuestionLengthTooLong, + ), + ( + "{\"data\": \"Bad Request: message with poll to stop not found\"}", + ApiError::MessageWithPollNotFound, + ), + ("{\"data\": \"Bad Request: message is not a poll\"}", ApiError::MessageIsNotAPoll), + ("{\"data\": \"Bad Request: chat not found\"}", ApiError::ChatNotFound), + ("{\"data\": \"Bad Request: user not found\"}", ApiError::UserNotFound), + ( + "{\"data\": \"Bad Request: chat description is not modified\"}", + ApiError::ChatDescriptionIsNotModified, + ), + ( + "{\"data\": \"Bad Request: query is too old and response timeout expired or query id \ + is invalid\"}", + ApiError::InvalidQueryId, + ), + ("{\"data\": \"Bad Request: BUTTON_URL_INVALID\"}", ApiError::ButtonUrlInvalid), + ("{\"data\": \"Bad Request: BUTTON_DATA_INVALID\"}", ApiError::ButtonDataInvalid), + ( + "{\"data\": \"Bad Request: can't parse inline keyboard button: Text buttons are \ + unallowed in the inline keyboard\"}", + ApiError::TextButtonsAreUnallowed, + ), + ("{\"data\": \"Bad Request: wrong file id\"}", ApiError::WrongFileId), + ( + "{\"data\": \"Bad Request: wrong file identifier/HTTP URL specified\"}", + ApiError::WrongFileIdOrUrl, + ), + ( + "{\"data\": \"Bad Request: failed to get HTTP URL content\"}", + ApiError::FailedToGetUrlContent, + ), + ("{\"data\": \"Bad Request: group is deactivated\"}", ApiError::GroupDeactivated), + ("{\"data\": \"Bad Request: IMAGE_PROCESS_FAILED\"}", ApiError::ImageProcessFailed), + ( + "{\"data\": \"Bad Request: Photo should be uploaded as an InputFile\"}", + ApiError::PhotoAsInputFileRequired, + ), + ("{\"data\": \"Bad Request: STICKERSET_INVALID\"}", ApiError::InvalidStickersSet), + ( + "{\"data\": \"Bad Request: sticker set name is already occupied\"}", + ApiError::StickerSetNameOccupied, + ), + ("{\"data\": \"Bad Request: USER_IS_BOT\"}", ApiError::StickerSetOwnerIsBot), + ( + "{\"data\": \"Bad Request: invalid sticker set name is specified\"}", + ApiError::InvalidStickerName, + ), + ( + "{\"data\": \"Bad Request: not enough rights to pin a message\"}", + ApiError::NotEnoughRightsToPinMessage, + ), + ( + "{\"data\": \"Bad Request: not enough rights to manage pinned messages in the chat\"}", + ApiError::NotEnoughRightsToManagePins, + ), + ( + "{\"data\": \"Bad Request: not enough rights to change chat permissions\"}", + ApiError::NotEnoughRightsToChangeChatPermissions, + ), + ( + "{\"data\": \"Bad Request: method is available only for supergroups and channel\"}", + ApiError::MethodNotAvailableInPrivateChats, + ), + ("{\"data\": \"Bad Request: can't demote chat creator\"}", ApiError::CantDemoteChatCreator), + ("{\"data\": \"Bad Request: can't restrict self\"}", ApiError::CantRestrictSelf), + ( + "{\"data\": \"Bad Request: not enough rights to restrict/unrestrict chat member\"}", + ApiError::NotEnoughRightsToRestrict, + ), + ( + "{\"data\": \"Bad Request: need administrator rights in the channel chat\"}", + ApiError::NotEnoughRightsToPostMessages, + ), + ( + "{\"data\": \"Bad Request: bad webhook: HTTPS url must be provided for webhook\"}", + ApiError::WebhookRequireHttps, + ), + ( + "{\"data\": \"Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, \ + 443 or 8443\"}", + ApiError::BadWebhookPort, + ), + ( + "{\"data\": \"Bad Request: bad webhook: Failed to resolve host: Name or service not \ + known\"}", + ApiError::UnknownHost, + ), + ("{\"data\": \"Bad Request: can't parse URL\"}", ApiError::CantParseUrl), + ( + "{\"data\": \"Bad Request: can't parse entities\"}", + ApiError::CantParseEntities( + "Bad Request: can't parse entities: SomeRandomString".to_owned(), + ), + ), + ( + "{\"data\": \"can't use getUpdates method while webhook is active\"}", + ApiError::CantGetUpdates, + ), + ("{\"data\": \"Unauthorized: bot was kicked from a chat\"}", ApiError::BotKicked), + ( + "{\"data\": \"Forbidden: bot was kicked from the supergroup chat\"}", + ApiError::BotKickedFromSupergroup, + ), + ("{\"data\": \"Forbidden: user is deactivated\"}", ApiError::UserDeactivated), + ( + "{\"data\": \"Unauthorized: bot can't initiate conversation with a user\"}", + ApiError::CantInitiateConversation, + ), + ( + "{\"data\": \"Unauthorized: bot can't send messages to bots\"}", + ApiError::CantTalkWithBots, + ), + ("{\"data\": \"Bad Request: wrong HTTP URL\"}", ApiError::WrongHttpUrl), + ( + "{\"data\": \"Conflict: terminated by other getUpdates request; make sure that only \ + one bot instance is running\"}", + ApiError::TerminatedByOtherGetUpdates, + ), + ("{\"data\": \"Bad Request: invalid file id\"}", ApiError::FileIdInvalid), + ("{\"data\": \"Request Entity Too Large\"}", ApiError::RequestEntityTooLarge), + ("{\"data\": \"RandomError\"}", ApiError::Unknown("RandomError".to_string())), + ]; + + #[derive(Deserialize, Debug)] + struct Res { + data: T, + } + + for (data, expected) in cases { + let raw = serde_json::from_str::>(data).unwrap().data; + let parsed = serde_json::from_str::>(data).unwrap().data; + assert_eq!(&parsed, expected); + + let expected_error_message = match parsed { + ApiError::Unknown(_) => { + format!("Unknown error: \"{raw}\"") + } + _ => raw, + }; + assert_eq!(parsed.to_string(), expected_error_message); + } +} + From c7f38981a4f45ac39f86c959f914c1bf3bf63933 Mon Sep 17 00:00:00 2001 From: puuuuh <54703480+puuuuh@users.noreply.github.com> Date: Mon, 6 Feb 2023 13:04:00 +0300 Subject: [PATCH 2/4] Apply suggestions from code review Co-authored-by: Waffle Maybe --- crates/teloxide-core/src/errors.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/teloxide-core/src/errors.rs b/crates/teloxide-core/src/errors.rs index 882433ef..b389f847 100644 --- a/crates/teloxide-core/src/errors.rs +++ b/crates/teloxide-core/src/errors.rs @@ -92,7 +92,7 @@ macro_rules! match_prefix { ("") => {{ |data: &str| Some(data.to_owned()) }}; - ($prefix: literal) => {{ + ($prefix:literal) => {{ |data: &str| { if data.starts_with($prefix) { Some(data.to_owned()) @@ -105,10 +105,14 @@ macro_rules! match_prefix { macro_rules! impl_api_error { ( - $(#[$meta: meta])* - $vis: vis enum $ident: ident { - $($(#[$var_meta: meta])* - $var_name: ident$(($var_inner: ty))? = $var_string: literal $(with $var_parser: block)?),* } ) => { + $( #[$meta:meta] )* + $vis:vis enum $ident:ident { + $( + $( #[$var_meta:meta] )* + $var_name:ident $( ($var_inner:ty) )? = $var_string:literal $(with $var_parser: block)? + ),* + } + ) => { $(#[$meta])* #[derive(Error)] From 8ccac0219a72ac24bba6558c40d61e9c54f9c40c Mon Sep 17 00:00:00 2001 From: puh Date: Mon, 6 Feb 2023 13:12:47 +0300 Subject: [PATCH 3/4] move tests, fix fmt --- crates/teloxide-core/src/errors.rs | 1353 ++++++++++++++++------------ crates/teloxide/tests/errors.rs | 212 ----- 2 files changed, 789 insertions(+), 776 deletions(-) delete mode 100644 crates/teloxide/tests/errors.rs diff --git a/crates/teloxide-core/src/errors.rs b/crates/teloxide-core/src/errors.rs index b389f847..5fc05ad5 100644 --- a/crates/teloxide-core/src/errors.rs +++ b/crates/teloxide-core/src/errors.rs @@ -111,48 +111,46 @@ macro_rules! impl_api_error { $( #[$var_meta:meta] )* $var_name:ident $( ($var_inner:ty) )? = $var_string:literal $(with $var_parser: block)? ),* - } + } ) => { $(#[$meta])* #[derive(Error)] $vis enum $ident { $( - $(#[$var_meta])* #[error($var_string)] $var_name $(($var_inner))*, - )* } const _: () = { - struct Visitor; + struct Visitor; - impl<'de> ::serde::de::Visitor<'de> for Visitor { - type Value = $ident; + impl<'de> ::serde::de::Visitor<'de> for Visitor { + type Value = $ident; - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - formatter.write_str("telegram api error string") + fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + formatter.write_str("telegram api error string") + } + + fn visit_str(self, v: &str) -> Result + where + E: ::serde::de::Error, + { + $(impl_api_error!(@de v, $var_name, $var_string $(, $var_parser)*);)* + Err(E::unknown_variant(v, &[])) + } } - fn visit_str(self, v: &str) -> Result - where - E: ::serde::de::Error, - { - $(impl_api_error!(@de v, $var_name, $var_string $(, $var_parser)*);)* - Err(E::unknown_variant(v, &[])) + impl<'de> ::serde::de::Deserialize<'de> for $ident { + fn deserialize(deserializer: D) -> Result + where + D: ::serde::de::Deserializer<'de>, + { + deserializer.deserialize_str(Visitor) + } } - } - - impl<'de> ::serde::de::Deserialize<'de> for $ident { - fn deserialize(deserializer: D) -> Result - where - D: ::serde::de::Deserializer<'de>, - { - deserializer.deserialize_str(Visitor) - } - } }; }; (@de $value: ident, $variant: ident, $val: literal) => { @@ -169,546 +167,546 @@ macro_rules! impl_api_error { } impl_api_error! { -/// A kind of an API error. -#[derive(Debug, PartialEq, Hash, Eq, Clone)] -#[non_exhaustive] -pub enum ApiError { - /// Occurs when the bot tries to send message to user who blocked the bot. - BotBlocked = "Forbidden: bot was blocked by the user", - - /// Occurs when the bot token is incorrect. - // FIXME: rename this to something akin "InvalidToken" - NotFound = "Unauthorized", - - /// Occurs when bot tries to modify a message without modification content. - /// - /// May happen in methods: - /// 1. [`EditMessageText`] - /// - /// [`EditMessageText`]: crate::payloads::EditMessageText - MessageNotModified = "Bad Request: message is not modified: specified new message content and reply markup are \ - exactly the same as a current content and reply markup of the message", - - /// Occurs when bot tries to forward or delete a message which was deleted. - /// - /// May happen in methods: - /// 1. [`ForwardMessage`] - /// 2. [`DeleteMessage`] - /// - /// [`ForwardMessage`]: crate::payloads::ForwardMessage - /// [`DeleteMessage`]: crate::payloads::DeleteMessage - MessageIdInvalid = "Bad Request: MESSAGE_ID_INVALID", - - /// Occurs when bot tries to forward a message which does not exists. - /// - /// May happen in methods: - /// 1. [`ForwardMessage`] - /// - /// [`ForwardMessage`]: crate::payloads::ForwardMessage - MessageToForwardNotFound = "Bad Request: message to forward not found", - - /// Occurs when bot tries to delete a message which does not exists. - /// - /// May happen in methods: - /// 1. [`DeleteMessage`] - /// - /// [`DeleteMessage`]: crate::payloads::DeleteMessage - MessageToDeleteNotFound = "Bad Request: message to delete not found", - - /// Occurs when bot tries to send a text message without text. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - MessageTextIsEmpty = "Bad Request: message text is empty", - - /// Occurs when bot tries to edit a message after long time. - /// - /// May happen in methods: - /// 1. [`EditMessageText`] - /// - /// [`EditMessageText`]: crate::payloads::EditMessageText - MessageCantBeEdited = "Bad Request: message can't be edited", - - /// Occurs when bot tries to delete a someone else's message in group where - /// it does not have enough rights. - /// - /// May happen in methods: - /// 1. [`DeleteMessage`] - /// - /// [`DeleteMessage`]: crate::payloads::DeleteMessage - MessageCantBeDeleted = "Bad Request: message can't be deleted", - - /// Occurs when bot tries to edit a message which does not exists. - /// - /// May happen in methods: - /// 1. [`EditMessageText`] - /// - /// [`EditMessageText`]: crate::payloads::EditMessageText - MessageToEditNotFound = "Bad Request: message to edit not found", - - /// Occurs when bot tries to reply to a message which does not exists. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - MessageToReplyNotFound = "Bad Request: reply message not found", - - /// Occurs when bot tries to - MessageIdentifierNotSpecified = "Bad Request: message identifier is not specified", - - /// Occurs when bot tries to send a message with text size greater then - /// 4096 symbols. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - MessageIsTooLong = "Bad Request: message is too long", - - /// Occurs when bot tries to edit a message with text size greater then - /// 4096 symbols. - /// - /// May happen in methods: - /// 1. [`EditMessageText`] - /// 2. [`EditMessageTextInline`] - /// 3. [`EditMessageCaption`] - /// 4. [`EditMessageCaptionInline`] - /// - /// [`EditMessageText`]: crate::payloads::EditMessageText - /// [`EditMessageTextInline`]: crate::payloads::EditMessageTextInline - /// [`EditMessageCaption`]: crate::payloads::EditMessageCaption - /// [`EditMessageCaptionInline`]: crate::payloads::EditMessageCaptionInline - EditedMessageIsTooLong = "Bad Request: MESSAGE_TOO_LONG", - - /// Occurs when bot tries to send media group with more than 10 items. - /// - /// May happen in methods: - /// 1. [`SendMediaGroup`] - /// - /// [`SendMediaGroup`]: crate::payloads::SendMediaGroup - ToMuchMessages = "Bad Request: Too much messages to send as an album", - - /// Occurs when bot tries to answer an inline query with more than 50 - /// results. - /// - /// Consider using offsets to paginate results. - /// - /// May happen in methods: - /// 1. [`AnswerInlineQuery`] - /// - /// [`AnswerInlineQuery`]: crate::payloads::AnswerInlineQuery - TooMuchInlineQueryResults = "Bad Request: RESULTS_TOO_MUCH", - - /// Occurs when bot tries to stop poll that has already been stopped. - /// - /// May happen in methods: - /// 1. [`SendPoll`] - /// - /// [`SendPoll`]: crate::payloads::SendPoll - PollHasAlreadyClosed = "Bad Request: poll has already been closed", - - /// Occurs when bot tries to send poll with less than 2 options. - /// - /// May happen in methods: - /// 1. [`SendPoll`] - /// - /// [`SendPoll`]: crate::payloads::SendPoll - PollMustHaveMoreOptions = "Bad Request: poll must have at least 2 option", - - /// Occurs when bot tries to send poll with more than 10 options. - /// - /// May happen in methods: - /// 1. [`SendPoll`] - /// - /// [`SendPoll`]: crate::payloads::SendPoll - PollCantHaveMoreOptions = "Bad Request: poll can't have more than 10 options", - - /// Occurs when bot tries to send poll with empty option (without text). - /// - /// May happen in methods: - /// 1. [`SendPoll`] - /// - /// [`SendPoll`]: crate::payloads::SendPoll - PollOptionsMustBeNonEmpty = "Bad Request: poll options must be non-empty", - - /// Occurs when bot tries to send poll with empty question (without text). - /// - /// May happen in methods: - /// 1. [`SendPoll`] - /// - /// [`SendPoll`]: crate::payloads::SendPoll - PollQuestionMustBeNonEmpty = "Bad Request: poll question must be non-empty", - - /// Occurs when bot tries to send poll with total size of options more than - /// 100 symbols. - /// - /// May happen in methods: - /// 1. [`SendPoll`] - /// - /// [`SendPoll`]: crate::payloads::SendPoll - PollOptionsLengthTooLong = "Bad Request: poll options length must not exceed 100", - - /// Occurs when bot tries to send poll with question size more than 255 - /// symbols. - /// - /// May happen in methods: - /// 1. [`SendPoll`] - /// - /// [`SendPoll`]: crate::payloads::SendPoll - PollQuestionLengthTooLong = "Bad Request: poll question length must not exceed 255", - - /// Occurs when bot tries to stop poll with message without poll. - /// - /// May happen in methods: - /// 1. [`StopPoll`] - /// - /// [`StopPoll`]: crate::payloads::StopPoll - MessageWithPollNotFound = "Bad Request: message with poll to stop not found", - - /// Occurs when bot tries to stop poll with message without poll. - /// - /// May happen in methods: - /// 1. [`StopPoll`] - /// - /// [`StopPoll`]: crate::payloads::StopPoll - MessageIsNotAPoll = "Bad Request: message is not a poll", - - /// Occurs when bot tries to send a message to chat in which it is not a - /// member. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - ChatNotFound = "Bad Request: chat not found", - - /// Occurs when bot tries to send method with unknown user_id. - /// - /// May happen in methods: - /// 1. [`getUserProfilePhotos`] - /// - /// [`getUserProfilePhotos`]: - /// crate::payloads::GetUserProfilePhotos - UserNotFound = "Bad Request: user not found", - - /// Occurs when bot tries to send [`SetChatDescription`] with same text as - /// in the current description. - /// - /// May happen in methods: - /// 1. [`SetChatDescription`] - /// - /// [`SetChatDescription`]: crate::payloads::SetChatDescription - ChatDescriptionIsNotModified = "Bad Request: chat description is not modified", - - /// Occurs when bot tries to answer to query after timeout expire. - /// - /// May happen in methods: - /// 1. [`AnswerCallbackQuery`] - /// - /// [`AnswerCallbackQuery`]: crate::payloads::AnswerCallbackQuery - InvalidQueryId = "Bad Request: query is too old and response timeout expired or query id is invalid", - - /// Occurs when bot tries to send InlineKeyboardMarkup with invalid button - /// url. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - ButtonUrlInvalid = "Bad Request: BUTTON_URL_INVALID", - - /// Occurs when bot tries to send button with data size more than 64 bytes. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - ButtonDataInvalid = "Bad Request: BUTTON_DATA_INVALID", - - /// Occurs when bot tries to send button with data size == 0. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - TextButtonsAreUnallowed = "Bad Request: can't parse inline keyboard button: Text buttons are unallowed in the \ - inline keyboard", - - /// Occurs when bot tries to get file by wrong file id. - /// - /// May happen in methods: - /// 1. [`GetFile`] - /// - /// [`GetFile`]: crate::payloads::GetFile - WrongFileId = "Bad Request: wrong file id", - - /// Occurs when bot tries to send files with wrong file identifier or HTTP - /// url - WrongFileIdOrUrl = "Bad Request: wrong file identifier/HTTP URL specified", - - /// Occurs when When sending files with an url to a site that doesn't - /// respond. - FailedToGetUrlContent = "Bad Request: failed to get HTTP URL content", - - /// Occurs when bot tries to do some with group which was deactivated. - GroupDeactivated = "Bad Request: group is deactivated", - - /// Occurs when image processing fails on telegram's side. - /// - /// This is likely caused by an incorrectly encoded image, make sure that - /// the image is correctly encoded in a format telegram accepts. - ImageProcessFailed = "Bad Request: IMAGE_PROCESS_FAILED", - - /// Occurs when bot tries to set chat photo from file ID - /// - /// May happen in methods: - /// 1. [`SetChatPhoto`] - /// - /// [`SetChatPhoto`]: crate::payloads::SetChatPhoto - PhotoAsInputFileRequired = "Bad Request: Photo should be uploaded as an InputFile", - - /// Occurs when bot tries to add sticker to stickerset by invalid name. - /// - /// May happen in methods: - /// 1. [`AddStickerToSet`] - /// - /// [`AddStickerToSet`]: crate::payloads::AddStickerToSet - InvalidStickersSet = "Bad Request: STICKERSET_INVALID", - - /// Occurs when bot tries to create a sticker set with a name that is - /// already used by another sticker set. - /// - /// May happen in methods: - /// 1. [`CreateNewStickerSet`] - /// - /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet - StickerSetNameOccupied = "Bad Request: sticker set name is already occupied", - - /// Occurs when bot tries to create a sticker set with user id of a bot. - /// - /// May happen in methods: - /// 1. [`CreateNewStickerSet`] - /// - /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet - StickerSetOwnerIsBot = "Bad Request: USER_IS_BOT", - - /// Occurs when bot tries to create a sticker set with invalid name. - /// - /// From documentation of [`CreateNewStickerSet`]: - /// > Short name of sticker set, to be used in `t.me/addstickers/` URLs - /// (e.g., _animals_). Can contain only english letters, digits and - /// underscores. Must begin with a letter, can't contain consecutive - /// underscores and must end in “\_by\_”. - /// is case insensitive. 1-64 characters. - /// - /// May happen in methods: - /// 1. [`CreateNewStickerSet`] - /// - /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet - InvalidStickerName = "Bad Request: invalid sticker set name is specified", - - /// Occurs when bot tries to pin a message without rights to pin in this - /// chat. - /// - /// May happen in methods: - /// 1. [`PinChatMessage`] - /// - /// [`PinChatMessage`]: crate::payloads::PinChatMessage - NotEnoughRightsToPinMessage = "Bad Request: not enough rights to pin a message", - - /// Occurs when bot tries to pin or unpin a message without rights to pin - /// in this chat. - /// - /// May happen in methods: - /// 1. [`PinChatMessage`] - /// 2. [`UnpinChatMessage`] - /// - /// [`PinChatMessage`]: crate::payloads::PinChatMessage - /// [`UnpinChatMessage`]: crate::payloads::UnpinChatMessage - NotEnoughRightsToManagePins = "Bad Request: not enough rights to manage pinned messages in the chat", - - /// Occurs when bot tries change default chat permissions without "Ban - /// Users" permission in this chat. - /// - /// May happen in methods: - /// 1. [`SetChatPermissions`] - /// - /// [`SetChatPermissions`]: crate::payloads::SetChatPermissions - NotEnoughRightsToChangeChatPermissions = "Bad Request: not enough rights to change chat permissions", - - /// Occurs when bot tries to use method in group which is allowed only in a - /// supergroup or channel. - MethodNotAvailableInPrivateChats = "Bad Request: method is available only for supergroups and channel", - - /// Occurs when bot tries to demote chat creator. - /// - /// May happen in methods: - /// 1. [`PromoteChatMember`] - /// - /// [`PromoteChatMember`]: crate::payloads::PromoteChatMember - CantDemoteChatCreator = "Bad Request: can't demote chat creator", - - /// Occurs when bot tries to restrict self in group chats. - /// - /// May happen in methods: - /// 1. [`RestrictChatMember`] - /// - /// [`RestrictChatMember`]: crate::payloads::RestrictChatMember - CantRestrictSelf = "Bad Request: can't restrict self", - - /// Occurs when bot tries to restrict chat member without rights to - /// restrict in this chat. - /// - /// May happen in methods: - /// 1. [`RestrictChatMember`] - /// - /// [`RestrictChatMember`]: crate::payloads::RestrictChatMember - NotEnoughRightsToRestrict = "Bad Request: not enough rights to restrict/unrestrict chat member", - - /// Occurs when bot tries to post a message in a channel without "Post - /// Messages" admin right. - NotEnoughRightsToPostMessages = "Bad Request: need administrator rights in the channel chat", - - /// Occurs when bot tries set webhook to protocol other than HTTPS. - /// - /// May happen in methods: - /// 1. [`SetWebhook`] - /// - /// [`SetWebhook`]: crate::payloads::SetWebhook - WebhookRequireHttps = "Bad Request: bad webhook: HTTPS url must be provided for webhook", - - /// Occurs when bot tries to set webhook to port other than 80, 88, 443 or - /// 8443. - /// - /// May happen in methods: - /// 1. [`SetWebhook`] - /// - /// [`SetWebhook`]: crate::payloads::SetWebhook - BadWebhookPort = "Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443", - - /// Occurs when bot tries to set webhook to unknown host. - /// - /// May happen in methods: - /// 1. [`SetWebhook`] - /// - /// [`SetWebhook`]: crate::payloads::SetWebhook - UnknownHost = "Bad Request: bad webhook: Failed to resolve host: Name or service not known", - - /// Occurs when bot tries to set webhook to invalid URL. - /// - /// May happen in methods: - /// 1. [`SetWebhook`] - /// - /// [`SetWebhook`]: crate::payloads::SetWebhook - CantParseUrl = "Bad Request: can't parse URL", - - /// Occurs when bot tries to send message with unfinished entities. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - CantParseEntities(String) = "{0}" with {match_prefix!("Bad Request: can't parse entities")}, - - /// Occurs when bot tries to use getUpdates while webhook is active. - /// - /// May happen in methods: - /// 1. [`GetUpdates`] - /// - /// [`GetUpdates`]: crate::payloads::GetUpdates - CantGetUpdates = "can't use getUpdates method while webhook is active", - - /// Occurs when bot tries to do some in group where bot was kicked. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - BotKicked = "Unauthorized: bot was kicked from a chat", - - /// Occurs when bot tries to do something in a supergroup the bot was - /// kicked from. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - BotKickedFromSupergroup = "Forbidden: bot was kicked from the supergroup chat", - - /// Occurs when bot tries to send a message to a deactivated user (i.e. a - /// user that was banned by telegram). - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - UserDeactivated = "Forbidden: user is deactivated", - - /// Occurs when you tries to initiate conversation with a user. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - CantInitiateConversation = "Unauthorized: bot can't initiate conversation with a user", - - /// Occurs when you tries to send message to bot. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - CantTalkWithBots = "Unauthorized: bot can't send messages to bots", - - /// Occurs when bot tries to send button with invalid http url. - /// - /// May happen in methods: - /// 1. [`SendMessage`] - /// - /// [`SendMessage`]: crate::payloads::SendMessage - WrongHttpUrl = "Bad Request: wrong HTTP URL", - - /// Occurs when bot tries GetUpdate before the timeout. Make sure that only - /// one Updater is running. - /// - /// May happen in methods: - /// 1. [`GetUpdates`] - /// - /// [`GetUpdates`]: crate::payloads::GetUpdates - TerminatedByOtherGetUpdates = "Conflict: terminated by other getUpdates request; make sure that only one bot instance \ - is running", - - /// Occurs when bot tries to get file by invalid file id. - /// - /// May happen in methods: - /// 1. [`GetFile`] - /// - /// [`GetFile`]: crate::payloads::GetFile - FileIdInvalid = "Bad Request: invalid file id", - - /// Occurs when bot tries to upload a file which is larger than 50 MB using - /// multipart/form-data. - /// - /// May happen in methods: - /// 1. [`SendVideo`] - /// 2. [`SendDocument`] - /// - /// [`SendVideo`]: crate::payloads::SendVideo - /// [`SendDocument`]: crate::payloads::SendDocument - RequestEntityTooLarge = "Request Entity Too Large", - - - /// Error which is not known to `teloxide`. - /// - /// If you've received this error, please [open an issue] with the - /// description of the error. - /// - /// [open an issue]: https://github.com/teloxide/teloxide/issues/new - Unknown(String) = "Unknown error: {0:?}" with {match_prefix!("")} -} + /// A kind of an API error. + #[derive(Debug, PartialEq, Hash, Eq, Clone)] + #[non_exhaustive] + pub enum ApiError { + /// Occurs when the bot tries to send message to user who blocked the bot. + BotBlocked = "Forbidden: bot was blocked by the user", + + /// Occurs when the bot token is incorrect. + // FIXME: rename this to something akin "InvalidToken" + NotFound = "Unauthorized", + + /// Occurs when bot tries to modify a message without modification content. + /// + /// May happen in methods: + /// 1. [`EditMessageText`] + /// + /// [`EditMessageText`]: crate::payloads::EditMessageText + MessageNotModified = "Bad Request: message is not modified: specified new message content and reply markup are \ + exactly the same as a current content and reply markup of the message", + + /// Occurs when bot tries to forward or delete a message which was deleted. + /// + /// May happen in methods: + /// 1. [`ForwardMessage`] + /// 2. [`DeleteMessage`] + /// + /// [`ForwardMessage`]: crate::payloads::ForwardMessage + /// [`DeleteMessage`]: crate::payloads::DeleteMessage + MessageIdInvalid = "Bad Request: MESSAGE_ID_INVALID", + + /// Occurs when bot tries to forward a message which does not exists. + /// + /// May happen in methods: + /// 1. [`ForwardMessage`] + /// + /// [`ForwardMessage`]: crate::payloads::ForwardMessage + MessageToForwardNotFound = "Bad Request: message to forward not found", + + /// Occurs when bot tries to delete a message which does not exists. + /// + /// May happen in methods: + /// 1. [`DeleteMessage`] + /// + /// [`DeleteMessage`]: crate::payloads::DeleteMessage + MessageToDeleteNotFound = "Bad Request: message to delete not found", + + /// Occurs when bot tries to send a text message without text. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + MessageTextIsEmpty = "Bad Request: message text is empty", + + /// Occurs when bot tries to edit a message after long time. + /// + /// May happen in methods: + /// 1. [`EditMessageText`] + /// + /// [`EditMessageText`]: crate::payloads::EditMessageText + MessageCantBeEdited = "Bad Request: message can't be edited", + + /// Occurs when bot tries to delete a someone else's message in group where + /// it does not have enough rights. + /// + /// May happen in methods: + /// 1. [`DeleteMessage`] + /// + /// [`DeleteMessage`]: crate::payloads::DeleteMessage + MessageCantBeDeleted = "Bad Request: message can't be deleted", + + /// Occurs when bot tries to edit a message which does not exists. + /// + /// May happen in methods: + /// 1. [`EditMessageText`] + /// + /// [`EditMessageText`]: crate::payloads::EditMessageText + MessageToEditNotFound = "Bad Request: message to edit not found", + + /// Occurs when bot tries to reply to a message which does not exists. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + MessageToReplyNotFound = "Bad Request: reply message not found", + + /// Occurs when bot tries to + MessageIdentifierNotSpecified = "Bad Request: message identifier is not specified", + + /// Occurs when bot tries to send a message with text size greater then + /// 4096 symbols. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + MessageIsTooLong = "Bad Request: message is too long", + + /// Occurs when bot tries to edit a message with text size greater then + /// 4096 symbols. + /// + /// May happen in methods: + /// 1. [`EditMessageText`] + /// 2. [`EditMessageTextInline`] + /// 3. [`EditMessageCaption`] + /// 4. [`EditMessageCaptionInline`] + /// + /// [`EditMessageText`]: crate::payloads::EditMessageText + /// [`EditMessageTextInline`]: crate::payloads::EditMessageTextInline + /// [`EditMessageCaption`]: crate::payloads::EditMessageCaption + /// [`EditMessageCaptionInline`]: crate::payloads::EditMessageCaptionInline + EditedMessageIsTooLong = "Bad Request: MESSAGE_TOO_LONG", + + /// Occurs when bot tries to send media group with more than 10 items. + /// + /// May happen in methods: + /// 1. [`SendMediaGroup`] + /// + /// [`SendMediaGroup`]: crate::payloads::SendMediaGroup + ToMuchMessages = "Bad Request: Too much messages to send as an album", + + /// Occurs when bot tries to answer an inline query with more than 50 + /// results. + /// + /// Consider using offsets to paginate results. + /// + /// May happen in methods: + /// 1. [`AnswerInlineQuery`] + /// + /// [`AnswerInlineQuery`]: crate::payloads::AnswerInlineQuery + TooMuchInlineQueryResults = "Bad Request: RESULTS_TOO_MUCH", + + /// Occurs when bot tries to stop poll that has already been stopped. + /// + /// May happen in methods: + /// 1. [`SendPoll`] + /// + /// [`SendPoll`]: crate::payloads::SendPoll + PollHasAlreadyClosed = "Bad Request: poll has already been closed", + + /// Occurs when bot tries to send poll with less than 2 options. + /// + /// May happen in methods: + /// 1. [`SendPoll`] + /// + /// [`SendPoll`]: crate::payloads::SendPoll + PollMustHaveMoreOptions = "Bad Request: poll must have at least 2 option", + + /// Occurs when bot tries to send poll with more than 10 options. + /// + /// May happen in methods: + /// 1. [`SendPoll`] + /// + /// [`SendPoll`]: crate::payloads::SendPoll + PollCantHaveMoreOptions = "Bad Request: poll can't have more than 10 options", + + /// Occurs when bot tries to send poll with empty option (without text). + /// + /// May happen in methods: + /// 1. [`SendPoll`] + /// + /// [`SendPoll`]: crate::payloads::SendPoll + PollOptionsMustBeNonEmpty = "Bad Request: poll options must be non-empty", + + /// Occurs when bot tries to send poll with empty question (without text). + /// + /// May happen in methods: + /// 1. [`SendPoll`] + /// + /// [`SendPoll`]: crate::payloads::SendPoll + PollQuestionMustBeNonEmpty = "Bad Request: poll question must be non-empty", + + /// Occurs when bot tries to send poll with total size of options more than + /// 100 symbols. + /// + /// May happen in methods: + /// 1. [`SendPoll`] + /// + /// [`SendPoll`]: crate::payloads::SendPoll + PollOptionsLengthTooLong = "Bad Request: poll options length must not exceed 100", + + /// Occurs when bot tries to send poll with question size more than 255 + /// symbols. + /// + /// May happen in methods: + /// 1. [`SendPoll`] + /// + /// [`SendPoll`]: crate::payloads::SendPoll + PollQuestionLengthTooLong = "Bad Request: poll question length must not exceed 255", + + /// Occurs when bot tries to stop poll with message without poll. + /// + /// May happen in methods: + /// 1. [`StopPoll`] + /// + /// [`StopPoll`]: crate::payloads::StopPoll + MessageWithPollNotFound = "Bad Request: message with poll to stop not found", + + /// Occurs when bot tries to stop poll with message without poll. + /// + /// May happen in methods: + /// 1. [`StopPoll`] + /// + /// [`StopPoll`]: crate::payloads::StopPoll + MessageIsNotAPoll = "Bad Request: message is not a poll", + + /// Occurs when bot tries to send a message to chat in which it is not a + /// member. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + ChatNotFound = "Bad Request: chat not found", + + /// Occurs when bot tries to send method with unknown user_id. + /// + /// May happen in methods: + /// 1. [`getUserProfilePhotos`] + /// + /// [`getUserProfilePhotos`]: + /// crate::payloads::GetUserProfilePhotos + UserNotFound = "Bad Request: user not found", + + /// Occurs when bot tries to send [`SetChatDescription`] with same text as + /// in the current description. + /// + /// May happen in methods: + /// 1. [`SetChatDescription`] + /// + /// [`SetChatDescription`]: crate::payloads::SetChatDescription + ChatDescriptionIsNotModified = "Bad Request: chat description is not modified", + + /// Occurs when bot tries to answer to query after timeout expire. + /// + /// May happen in methods: + /// 1. [`AnswerCallbackQuery`] + /// + /// [`AnswerCallbackQuery`]: crate::payloads::AnswerCallbackQuery + InvalidQueryId = "Bad Request: query is too old and response timeout expired or query id is invalid", + + /// Occurs when bot tries to send InlineKeyboardMarkup with invalid button + /// url. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + ButtonUrlInvalid = "Bad Request: BUTTON_URL_INVALID", + + /// Occurs when bot tries to send button with data size more than 64 bytes. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + ButtonDataInvalid = "Bad Request: BUTTON_DATA_INVALID", + + /// Occurs when bot tries to send button with data size == 0. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + TextButtonsAreUnallowed = "Bad Request: can't parse inline keyboard button: Text buttons are unallowed in the \ + inline keyboard", + + /// Occurs when bot tries to get file by wrong file id. + /// + /// May happen in methods: + /// 1. [`GetFile`] + /// + /// [`GetFile`]: crate::payloads::GetFile + WrongFileId = "Bad Request: wrong file id", + + /// Occurs when bot tries to send files with wrong file identifier or HTTP + /// url + WrongFileIdOrUrl = "Bad Request: wrong file identifier/HTTP URL specified", + + /// Occurs when When sending files with an url to a site that doesn't + /// respond. + FailedToGetUrlContent = "Bad Request: failed to get HTTP URL content", + + /// Occurs when bot tries to do some with group which was deactivated. + GroupDeactivated = "Bad Request: group is deactivated", + + /// Occurs when image processing fails on telegram's side. + /// + /// This is likely caused by an incorrectly encoded image, make sure that + /// the image is correctly encoded in a format telegram accepts. + ImageProcessFailed = "Bad Request: IMAGE_PROCESS_FAILED", + + /// Occurs when bot tries to set chat photo from file ID + /// + /// May happen in methods: + /// 1. [`SetChatPhoto`] + /// + /// [`SetChatPhoto`]: crate::payloads::SetChatPhoto + PhotoAsInputFileRequired = "Bad Request: Photo should be uploaded as an InputFile", + + /// Occurs when bot tries to add sticker to stickerset by invalid name. + /// + /// May happen in methods: + /// 1. [`AddStickerToSet`] + /// + /// [`AddStickerToSet`]: crate::payloads::AddStickerToSet + InvalidStickersSet = "Bad Request: STICKERSET_INVALID", + + /// Occurs when bot tries to create a sticker set with a name that is + /// already used by another sticker set. + /// + /// May happen in methods: + /// 1. [`CreateNewStickerSet`] + /// + /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet + StickerSetNameOccupied = "Bad Request: sticker set name is already occupied", + + /// Occurs when bot tries to create a sticker set with user id of a bot. + /// + /// May happen in methods: + /// 1. [`CreateNewStickerSet`] + /// + /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet + StickerSetOwnerIsBot = "Bad Request: USER_IS_BOT", + + /// Occurs when bot tries to create a sticker set with invalid name. + /// + /// From documentation of [`CreateNewStickerSet`]: + /// > Short name of sticker set, to be used in `t.me/addstickers/` URLs + /// (e.g., _animals_). Can contain only english letters, digits and + /// underscores. Must begin with a letter, can't contain consecutive + /// underscores and must end in “\_by\_”. + /// is case insensitive. 1-64 characters. + /// + /// May happen in methods: + /// 1. [`CreateNewStickerSet`] + /// + /// [`CreateNewStickerSet`]: crate::payloads::CreateNewStickerSet + InvalidStickerName = "Bad Request: invalid sticker set name is specified", + + /// Occurs when bot tries to pin a message without rights to pin in this + /// chat. + /// + /// May happen in methods: + /// 1. [`PinChatMessage`] + /// + /// [`PinChatMessage`]: crate::payloads::PinChatMessage + NotEnoughRightsToPinMessage = "Bad Request: not enough rights to pin a message", + + /// Occurs when bot tries to pin or unpin a message without rights to pin + /// in this chat. + /// + /// May happen in methods: + /// 1. [`PinChatMessage`] + /// 2. [`UnpinChatMessage`] + /// + /// [`PinChatMessage`]: crate::payloads::PinChatMessage + /// [`UnpinChatMessage`]: crate::payloads::UnpinChatMessage + NotEnoughRightsToManagePins = "Bad Request: not enough rights to manage pinned messages in the chat", + + /// Occurs when bot tries change default chat permissions without "Ban + /// Users" permission in this chat. + /// + /// May happen in methods: + /// 1. [`SetChatPermissions`] + /// + /// [`SetChatPermissions`]: crate::payloads::SetChatPermissions + NotEnoughRightsToChangeChatPermissions = "Bad Request: not enough rights to change chat permissions", + + /// Occurs when bot tries to use method in group which is allowed only in a + /// supergroup or channel. + MethodNotAvailableInPrivateChats = "Bad Request: method is available only for supergroups and channel", + + /// Occurs when bot tries to demote chat creator. + /// + /// May happen in methods: + /// 1. [`PromoteChatMember`] + /// + /// [`PromoteChatMember`]: crate::payloads::PromoteChatMember + CantDemoteChatCreator = "Bad Request: can't demote chat creator", + + /// Occurs when bot tries to restrict self in group chats. + /// + /// May happen in methods: + /// 1. [`RestrictChatMember`] + /// + /// [`RestrictChatMember`]: crate::payloads::RestrictChatMember + CantRestrictSelf = "Bad Request: can't restrict self", + + /// Occurs when bot tries to restrict chat member without rights to + /// restrict in this chat. + /// + /// May happen in methods: + /// 1. [`RestrictChatMember`] + /// + /// [`RestrictChatMember`]: crate::payloads::RestrictChatMember + NotEnoughRightsToRestrict = "Bad Request: not enough rights to restrict/unrestrict chat member", + + /// Occurs when bot tries to post a message in a channel without "Post + /// Messages" admin right. + NotEnoughRightsToPostMessages = "Bad Request: need administrator rights in the channel chat", + + /// Occurs when bot tries set webhook to protocol other than HTTPS. + /// + /// May happen in methods: + /// 1. [`SetWebhook`] + /// + /// [`SetWebhook`]: crate::payloads::SetWebhook + WebhookRequireHttps = "Bad Request: bad webhook: HTTPS url must be provided for webhook", + + /// Occurs when bot tries to set webhook to port other than 80, 88, 443 or + /// 8443. + /// + /// May happen in methods: + /// 1. [`SetWebhook`] + /// + /// [`SetWebhook`]: crate::payloads::SetWebhook + BadWebhookPort = "Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443", + + /// Occurs when bot tries to set webhook to unknown host. + /// + /// May happen in methods: + /// 1. [`SetWebhook`] + /// + /// [`SetWebhook`]: crate::payloads::SetWebhook + UnknownHost = "Bad Request: bad webhook: Failed to resolve host: Name or service not known", + + /// Occurs when bot tries to set webhook to invalid URL. + /// + /// May happen in methods: + /// 1. [`SetWebhook`] + /// + /// [`SetWebhook`]: crate::payloads::SetWebhook + CantParseUrl = "Bad Request: can't parse URL", + + /// Occurs when bot tries to send message with unfinished entities. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + CantParseEntities(String) = "{0}" with {match_prefix!("Bad Request: can't parse entities")}, + + /// Occurs when bot tries to use getUpdates while webhook is active. + /// + /// May happen in methods: + /// 1. [`GetUpdates`] + /// + /// [`GetUpdates`]: crate::payloads::GetUpdates + CantGetUpdates = "can't use getUpdates method while webhook is active", + + /// Occurs when bot tries to do some in group where bot was kicked. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + BotKicked = "Unauthorized: bot was kicked from a chat", + + /// Occurs when bot tries to do something in a supergroup the bot was + /// kicked from. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + BotKickedFromSupergroup = "Forbidden: bot was kicked from the supergroup chat", + + /// Occurs when bot tries to send a message to a deactivated user (i.e. a + /// user that was banned by telegram). + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + UserDeactivated = "Forbidden: user is deactivated", + + /// Occurs when you tries to initiate conversation with a user. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + CantInitiateConversation = "Unauthorized: bot can't initiate conversation with a user", + + /// Occurs when you tries to send message to bot. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + CantTalkWithBots = "Unauthorized: bot can't send messages to bots", + + /// Occurs when bot tries to send button with invalid http url. + /// + /// May happen in methods: + /// 1. [`SendMessage`] + /// + /// [`SendMessage`]: crate::payloads::SendMessage + WrongHttpUrl = "Bad Request: wrong HTTP URL", + + /// Occurs when bot tries GetUpdate before the timeout. Make sure that only + /// one Updater is running. + /// + /// May happen in methods: + /// 1. [`GetUpdates`] + /// + /// [`GetUpdates`]: crate::payloads::GetUpdates + TerminatedByOtherGetUpdates = "Conflict: terminated by other getUpdates request; make sure that only one bot instance \ + is running", + + /// Occurs when bot tries to get file by invalid file id. + /// + /// May happen in methods: + /// 1. [`GetFile`] + /// + /// [`GetFile`]: crate::payloads::GetFile + FileIdInvalid = "Bad Request: invalid file id", + + /// Occurs when bot tries to upload a file which is larger than 50 MB using + /// multipart/form-data. + /// + /// May happen in methods: + /// 1. [`SendVideo`] + /// 2. [`SendDocument`] + /// + /// [`SendVideo`]: crate::payloads::SendVideo + /// [`SendDocument`]: crate::payloads::SendDocument + RequestEntityTooLarge = "Request Entity Too Large", + + + /// Error which is not known to `teloxide`. + /// + /// If you've received this error, please [open an issue] with the + /// description of the error. + /// + /// [open an issue]: https://github.com/teloxide/teloxide/issues/new + Unknown(String) = "Unknown error: {0:?}" with {match_prefix!("")} + } } /// This impl allows to use `?` to propagate [`DownloadError`]s in function @@ -798,3 +796,230 @@ pub(crate) fn hide_token(mut error: reqwest::Error) -> reqwest::Error { // couldn't find token in the url, hide the whole url error.without_url() } + +#[cfg(test)] +mod tests { + #[test] + fn custom_result() { + use super::ApiError; + use serde::Deserialize; + + let cases = &[ + ("{\"data\": \"Forbidden: bot was blocked by the user\"}", ApiError::BotBlocked), + ("{\"data\": \"Unauthorized\"}", ApiError::NotFound), + ( + "{\"data\": \"Bad Request: message is not modified: specified new message content \ + and reply markup are exactly the same as a current content and reply markup of \ + the message\"}", + ApiError::MessageNotModified, + ), + ("{\"data\": \"Bad Request: MESSAGE_ID_INVALID\"}", ApiError::MessageIdInvalid), + ( + "{\"data\": \"Bad Request: message to forward not found\"}", + ApiError::MessageToForwardNotFound, + ), + ( + "{\"data\": \"Bad Request: message to delete not found\"}", + ApiError::MessageToDeleteNotFound, + ), + ("{\"data\": \"Bad Request: message text is empty\"}", ApiError::MessageTextIsEmpty), + ("{\"data\": \"Bad Request: message can't be edited\"}", ApiError::MessageCantBeEdited), + ( + "{\"data\": \"Bad Request: message can't be deleted\"}", + ApiError::MessageCantBeDeleted, + ), + ( + "{\"data\": \"Bad Request: message to edit not found\"}", + ApiError::MessageToEditNotFound, + ), + ( + "{\"data\": \"Bad Request: reply message not found\"}", + ApiError::MessageToReplyNotFound, + ), + ( + "{\"data\": \"Bad Request: message identifier is not specified\"}", + ApiError::MessageIdentifierNotSpecified, + ), + ("{\"data\": \"Bad Request: message is too long\"}", ApiError::MessageIsTooLong), + ("{\"data\": \"Bad Request: MESSAGE_TOO_LONG\"}", ApiError::EditedMessageIsTooLong), + ( + "{\"data\": \"Bad Request: Too much messages to send as an album\"}", + ApiError::ToMuchMessages, + ), + ("{\"data\": \"Bad Request: RESULTS_TOO_MUCH\"}", ApiError::TooMuchInlineQueryResults), + ( + "{\"data\": \"Bad Request: poll has already been closed\"}", + ApiError::PollHasAlreadyClosed, + ), + ( + "{\"data\": \"Bad Request: poll must have at least 2 option\"}", + ApiError::PollMustHaveMoreOptions, + ), + ( + "{\"data\": \"Bad Request: poll can't have more than 10 options\"}", + ApiError::PollCantHaveMoreOptions, + ), + ( + "{\"data\": \"Bad Request: poll options must be non-empty\"}", + ApiError::PollOptionsMustBeNonEmpty, + ), + ( + "{\"data\": \"Bad Request: poll question must be non-empty\"}", + ApiError::PollQuestionMustBeNonEmpty, + ), + ( + "{\"data\": \"Bad Request: poll options length must not exceed 100\"}", + ApiError::PollOptionsLengthTooLong, + ), + ( + "{\"data\": \"Bad Request: poll question length must not exceed 255\"}", + ApiError::PollQuestionLengthTooLong, + ), + ( + "{\"data\": \"Bad Request: message with poll to stop not found\"}", + ApiError::MessageWithPollNotFound, + ), + ("{\"data\": \"Bad Request: message is not a poll\"}", ApiError::MessageIsNotAPoll), + ("{\"data\": \"Bad Request: chat not found\"}", ApiError::ChatNotFound), + ("{\"data\": \"Bad Request: user not found\"}", ApiError::UserNotFound), + ( + "{\"data\": \"Bad Request: chat description is not modified\"}", + ApiError::ChatDescriptionIsNotModified, + ), + ( + "{\"data\": \"Bad Request: query is too old and response timeout expired or query \ + id is invalid\"}", + ApiError::InvalidQueryId, + ), + ("{\"data\": \"Bad Request: BUTTON_URL_INVALID\"}", ApiError::ButtonUrlInvalid), + ("{\"data\": \"Bad Request: BUTTON_DATA_INVALID\"}", ApiError::ButtonDataInvalid), + ( + "{\"data\": \"Bad Request: can't parse inline keyboard button: Text buttons are \ + unallowed in the inline keyboard\"}", + ApiError::TextButtonsAreUnallowed, + ), + ("{\"data\": \"Bad Request: wrong file id\"}", ApiError::WrongFileId), + ( + "{\"data\": \"Bad Request: wrong file identifier/HTTP URL specified\"}", + ApiError::WrongFileIdOrUrl, + ), + ( + "{\"data\": \"Bad Request: failed to get HTTP URL content\"}", + ApiError::FailedToGetUrlContent, + ), + ("{\"data\": \"Bad Request: group is deactivated\"}", ApiError::GroupDeactivated), + ("{\"data\": \"Bad Request: IMAGE_PROCESS_FAILED\"}", ApiError::ImageProcessFailed), + ( + "{\"data\": \"Bad Request: Photo should be uploaded as an InputFile\"}", + ApiError::PhotoAsInputFileRequired, + ), + ("{\"data\": \"Bad Request: STICKERSET_INVALID\"}", ApiError::InvalidStickersSet), + ( + "{\"data\": \"Bad Request: sticker set name is already occupied\"}", + ApiError::StickerSetNameOccupied, + ), + ("{\"data\": \"Bad Request: USER_IS_BOT\"}", ApiError::StickerSetOwnerIsBot), + ( + "{\"data\": \"Bad Request: invalid sticker set name is specified\"}", + ApiError::InvalidStickerName, + ), + ( + "{\"data\": \"Bad Request: not enough rights to pin a message\"}", + ApiError::NotEnoughRightsToPinMessage, + ), + ( + "{\"data\": \"Bad Request: not enough rights to manage pinned messages in the \ + chat\"}", + ApiError::NotEnoughRightsToManagePins, + ), + ( + "{\"data\": \"Bad Request: not enough rights to change chat permissions\"}", + ApiError::NotEnoughRightsToChangeChatPermissions, + ), + ( + "{\"data\": \"Bad Request: method is available only for supergroups and channel\"}", + ApiError::MethodNotAvailableInPrivateChats, + ), + ( + "{\"data\": \"Bad Request: can't demote chat creator\"}", + ApiError::CantDemoteChatCreator, + ), + ("{\"data\": \"Bad Request: can't restrict self\"}", ApiError::CantRestrictSelf), + ( + "{\"data\": \"Bad Request: not enough rights to restrict/unrestrict chat member\"}", + ApiError::NotEnoughRightsToRestrict, + ), + ( + "{\"data\": \"Bad Request: need administrator rights in the channel chat\"}", + ApiError::NotEnoughRightsToPostMessages, + ), + ( + "{\"data\": \"Bad Request: bad webhook: HTTPS url must be provided for webhook\"}", + ApiError::WebhookRequireHttps, + ), + ( + "{\"data\": \"Bad Request: bad webhook: Webhook can be set up only on ports 80, \ + 88, 443 or 8443\"}", + ApiError::BadWebhookPort, + ), + ( + "{\"data\": \"Bad Request: bad webhook: Failed to resolve host: Name or service \ + not known\"}", + ApiError::UnknownHost, + ), + ("{\"data\": \"Bad Request: can't parse URL\"}", ApiError::CantParseUrl), + ( + "{\"data\": \"Bad Request: can't parse entities: SomeRandomString\"}", + ApiError::CantParseEntities( + "Bad Request: can't parse entities: SomeRandomString".to_owned(), + ), + ), + ( + "{\"data\": \"can't use getUpdates method while webhook is active\"}", + ApiError::CantGetUpdates, + ), + ("{\"data\": \"Unauthorized: bot was kicked from a chat\"}", ApiError::BotKicked), + ( + "{\"data\": \"Forbidden: bot was kicked from the supergroup chat\"}", + ApiError::BotKickedFromSupergroup, + ), + ("{\"data\": \"Forbidden: user is deactivated\"}", ApiError::UserDeactivated), + ( + "{\"data\": \"Unauthorized: bot can't initiate conversation with a user\"}", + ApiError::CantInitiateConversation, + ), + ( + "{\"data\": \"Unauthorized: bot can't send messages to bots\"}", + ApiError::CantTalkWithBots, + ), + ("{\"data\": \"Bad Request: wrong HTTP URL\"}", ApiError::WrongHttpUrl), + ( + "{\"data\": \"Conflict: terminated by other getUpdates request; make sure that \ + only one bot instance is running\"}", + ApiError::TerminatedByOtherGetUpdates, + ), + ("{\"data\": \"Bad Request: invalid file id\"}", ApiError::FileIdInvalid), + ("{\"data\": \"Request Entity Too Large\"}", ApiError::RequestEntityTooLarge), + ("{\"data\": \"RandomError\"}", ApiError::Unknown("RandomError".to_string())), + ]; + + #[derive(Deserialize, Debug)] + struct Res { + data: T, + } + + for (data, expected) in cases { + let raw = serde_json::from_str::>(data).unwrap().data; + let parsed = serde_json::from_str::>(data).unwrap().data; + assert_eq!(&parsed, expected); + + let expected_error_message = match parsed { + ApiError::Unknown(_) => { + format!("Unknown error: \"{raw}\"") + } + _ => raw, + }; + assert_eq!(parsed.to_string(), expected_error_message); + } + } +} diff --git a/crates/teloxide/tests/errors.rs b/crates/teloxide/tests/errors.rs deleted file mode 100644 index f0edcf78..00000000 --- a/crates/teloxide/tests/errors.rs +++ /dev/null @@ -1,212 +0,0 @@ -use serde::Deserialize; - -#[test] -fn custom_result() { - use teloxide_core::ApiError; - - let cases = &[ - ("{\"data\": \"Forbidden: bot was blocked by the user\"}", ApiError::BotBlocked), - ("{\"data\": \"Unauthorized\"}", ApiError::NotFound), - ( - "{\"data\": \"Bad Request: message is not modified: specified new message content and \ - reply markup are exactly the same as a current content and reply markup of the \ - message\"}", - ApiError::MessageNotModified, - ), - ("{\"data\": \"Bad Request: MESSAGE_ID_INVALID\"}", ApiError::MessageIdInvalid), - ( - "{\"data\": \"Bad Request: message to forward not found\"}", - ApiError::MessageToForwardNotFound, - ), - ( - "{\"data\": \"Bad Request: message to delete not found\"}", - ApiError::MessageToDeleteNotFound, - ), - ("{\"data\": \"Bad Request: message text is empty\"}", ApiError::MessageTextIsEmpty), - ("{\"data\": \"Bad Request: message can't be edited\"}", ApiError::MessageCantBeEdited), - ("{\"data\": \"Bad Request: message can't be deleted\"}", ApiError::MessageCantBeDeleted), - ("{\"data\": \"Bad Request: message to edit not found\"}", ApiError::MessageToEditNotFound), - ("{\"data\": \"Bad Request: reply message not found\"}", ApiError::MessageToReplyNotFound), - ( - "{\"data\": \"Bad Request: message identifier is not specified\"}", - ApiError::MessageIdentifierNotSpecified, - ), - ("{\"data\": \"Bad Request: message is too long\"}", ApiError::MessageIsTooLong), - ("{\"data\": \"Bad Request: MESSAGE_TOO_LONG\"}", ApiError::EditedMessageIsTooLong), - ( - "{\"data\": \"Bad Request: Too much messages to send as an album\"}", - ApiError::ToMuchMessages, - ), - ("{\"data\": \"Bad Request: RESULTS_TOO_MUCH\"}", ApiError::TooMuchInlineQueryResults), - ( - "{\"data\": \"Bad Request: poll has already been closed\"}", - ApiError::PollHasAlreadyClosed, - ), - ( - "{\"data\": \"Bad Request: poll must have at least 2 option\"}", - ApiError::PollMustHaveMoreOptions, - ), - ( - "{\"data\": \"Bad Request: poll can't have more than 10 options\"}", - ApiError::PollCantHaveMoreOptions, - ), - ( - "{\"data\": \"Bad Request: poll options must be non-empty\"}", - ApiError::PollOptionsMustBeNonEmpty, - ), - ( - "{\"data\": \"Bad Request: poll question must be non-empty\"}", - ApiError::PollQuestionMustBeNonEmpty, - ), - ( - "{\"data\": \"Bad Request: poll options length must not exceed 100\"}", - ApiError::PollOptionsLengthTooLong, - ), - ( - "{\"data\": \"Bad Request: poll question length must not exceed 255\"}", - ApiError::PollQuestionLengthTooLong, - ), - ( - "{\"data\": \"Bad Request: message with poll to stop not found\"}", - ApiError::MessageWithPollNotFound, - ), - ("{\"data\": \"Bad Request: message is not a poll\"}", ApiError::MessageIsNotAPoll), - ("{\"data\": \"Bad Request: chat not found\"}", ApiError::ChatNotFound), - ("{\"data\": \"Bad Request: user not found\"}", ApiError::UserNotFound), - ( - "{\"data\": \"Bad Request: chat description is not modified\"}", - ApiError::ChatDescriptionIsNotModified, - ), - ( - "{\"data\": \"Bad Request: query is too old and response timeout expired or query id \ - is invalid\"}", - ApiError::InvalidQueryId, - ), - ("{\"data\": \"Bad Request: BUTTON_URL_INVALID\"}", ApiError::ButtonUrlInvalid), - ("{\"data\": \"Bad Request: BUTTON_DATA_INVALID\"}", ApiError::ButtonDataInvalid), - ( - "{\"data\": \"Bad Request: can't parse inline keyboard button: Text buttons are \ - unallowed in the inline keyboard\"}", - ApiError::TextButtonsAreUnallowed, - ), - ("{\"data\": \"Bad Request: wrong file id\"}", ApiError::WrongFileId), - ( - "{\"data\": \"Bad Request: wrong file identifier/HTTP URL specified\"}", - ApiError::WrongFileIdOrUrl, - ), - ( - "{\"data\": \"Bad Request: failed to get HTTP URL content\"}", - ApiError::FailedToGetUrlContent, - ), - ("{\"data\": \"Bad Request: group is deactivated\"}", ApiError::GroupDeactivated), - ("{\"data\": \"Bad Request: IMAGE_PROCESS_FAILED\"}", ApiError::ImageProcessFailed), - ( - "{\"data\": \"Bad Request: Photo should be uploaded as an InputFile\"}", - ApiError::PhotoAsInputFileRequired, - ), - ("{\"data\": \"Bad Request: STICKERSET_INVALID\"}", ApiError::InvalidStickersSet), - ( - "{\"data\": \"Bad Request: sticker set name is already occupied\"}", - ApiError::StickerSetNameOccupied, - ), - ("{\"data\": \"Bad Request: USER_IS_BOT\"}", ApiError::StickerSetOwnerIsBot), - ( - "{\"data\": \"Bad Request: invalid sticker set name is specified\"}", - ApiError::InvalidStickerName, - ), - ( - "{\"data\": \"Bad Request: not enough rights to pin a message\"}", - ApiError::NotEnoughRightsToPinMessage, - ), - ( - "{\"data\": \"Bad Request: not enough rights to manage pinned messages in the chat\"}", - ApiError::NotEnoughRightsToManagePins, - ), - ( - "{\"data\": \"Bad Request: not enough rights to change chat permissions\"}", - ApiError::NotEnoughRightsToChangeChatPermissions, - ), - ( - "{\"data\": \"Bad Request: method is available only for supergroups and channel\"}", - ApiError::MethodNotAvailableInPrivateChats, - ), - ("{\"data\": \"Bad Request: can't demote chat creator\"}", ApiError::CantDemoteChatCreator), - ("{\"data\": \"Bad Request: can't restrict self\"}", ApiError::CantRestrictSelf), - ( - "{\"data\": \"Bad Request: not enough rights to restrict/unrestrict chat member\"}", - ApiError::NotEnoughRightsToRestrict, - ), - ( - "{\"data\": \"Bad Request: need administrator rights in the channel chat\"}", - ApiError::NotEnoughRightsToPostMessages, - ), - ( - "{\"data\": \"Bad Request: bad webhook: HTTPS url must be provided for webhook\"}", - ApiError::WebhookRequireHttps, - ), - ( - "{\"data\": \"Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, \ - 443 or 8443\"}", - ApiError::BadWebhookPort, - ), - ( - "{\"data\": \"Bad Request: bad webhook: Failed to resolve host: Name or service not \ - known\"}", - ApiError::UnknownHost, - ), - ("{\"data\": \"Bad Request: can't parse URL\"}", ApiError::CantParseUrl), - ( - "{\"data\": \"Bad Request: can't parse entities\"}", - ApiError::CantParseEntities( - "Bad Request: can't parse entities: SomeRandomString".to_owned(), - ), - ), - ( - "{\"data\": \"can't use getUpdates method while webhook is active\"}", - ApiError::CantGetUpdates, - ), - ("{\"data\": \"Unauthorized: bot was kicked from a chat\"}", ApiError::BotKicked), - ( - "{\"data\": \"Forbidden: bot was kicked from the supergroup chat\"}", - ApiError::BotKickedFromSupergroup, - ), - ("{\"data\": \"Forbidden: user is deactivated\"}", ApiError::UserDeactivated), - ( - "{\"data\": \"Unauthorized: bot can't initiate conversation with a user\"}", - ApiError::CantInitiateConversation, - ), - ( - "{\"data\": \"Unauthorized: bot can't send messages to bots\"}", - ApiError::CantTalkWithBots, - ), - ("{\"data\": \"Bad Request: wrong HTTP URL\"}", ApiError::WrongHttpUrl), - ( - "{\"data\": \"Conflict: terminated by other getUpdates request; make sure that only \ - one bot instance is running\"}", - ApiError::TerminatedByOtherGetUpdates, - ), - ("{\"data\": \"Bad Request: invalid file id\"}", ApiError::FileIdInvalid), - ("{\"data\": \"Request Entity Too Large\"}", ApiError::RequestEntityTooLarge), - ("{\"data\": \"RandomError\"}", ApiError::Unknown("RandomError".to_string())), - ]; - - #[derive(Deserialize, Debug)] - struct Res { - data: T, - } - - for (data, expected) in cases { - let raw = serde_json::from_str::>(data).unwrap().data; - let parsed = serde_json::from_str::>(data).unwrap().data; - assert_eq!(&parsed, expected); - - let expected_error_message = match parsed { - ApiError::Unknown(_) => { - format!("Unknown error: \"{raw}\"") - } - _ => raw, - }; - assert_eq!(parsed.to_string(), expected_error_message); - } -} - From 94733cbcd6a659e66bc4a698469184bc79dd849c Mon Sep 17 00:00:00 2001 From: puh Date: Thu, 30 Mar 2023 20:20:45 +0300 Subject: [PATCH 4/4] changelog --- crates/teloxide-core/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index 42fec72a..280f96a1 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -22,6 +22,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [pr850]: https://github.com/teloxide/teloxide/pull/850 +### Fixed + +- Deserialization of `ApiError::CantParseEntities` ([#839][pr839]) + +[pr839]: https://github.com/teloxide/teloxide/pull/839 + ## 0.9.1 - 2023-02-15 ### Fixed