From f4a41c047dbd79bec19b8181d679339b76658d8e Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 26 Aug 2026 15:27:30 +0600 Subject: [PATCH] Preserve UniqueGiftInfo constructor compatibility --- .../types/gifts/GiftSentOrReceivedEvent.kt | 102 +++++++++--------- .../tgbotapi/types/GeneralBotApi103Test.kt | 91 ++++++++++++++++ 2 files changed, 142 insertions(+), 51 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/gifts/GiftSentOrReceivedEvent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/gifts/GiftSentOrReceivedEvent.kt index 496de7b5a8..0898fc0d95 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/gifts/GiftSentOrReceivedEvent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/gifts/GiftSentOrReceivedEvent.kt @@ -298,12 +298,6 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { override val gift: Gift.Unique, @SerialName(originField) override val originTyped: Origin? = null, - @SerialName(textField) - override val text: String? = null, - @SerialName(entitiesField) - private val entities: RawMessageEntities? = null, - @SerialName(isPrivateField) - override val isPrivate: Boolean = false, @Deprecated("Use lastResaleCurrency and lastResaleAmount instead") @SerialName(lastResaleStarCountField) override val lastResaleStarCount: Int? = null, @@ -314,7 +308,13 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { @SerialName(transferStarCountField) override val transferStarCount: Int? = null, @SerialName(nextTransferDateField) - override val nextTransferDate: TelegramDate? = null + override val nextTransferDate: TelegramDate? = null, + @SerialName(textField) + override val text: String? = null, + @SerialName(entitiesField) + private val entities: RawMessageEntities? = null, + @SerialName(isPrivateField) + override val isPrivate: Boolean = false ) : UniqueGift { override val ownedGiftId: GiftId? get() = null @@ -329,25 +329,25 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { constructor( gift: Gift.Unique, origin: String?, - text: String? = null, - entities: RawMessageEntities? = null, - isPrivate: Boolean = false, lastResaleStarCount: Int? = null, lastResaleCurrency: Currency? = null, lastResaleAmount: Long? = null, transferStarCount: Int? = null, - nextTransferDate: TelegramDate? = null + nextTransferDate: TelegramDate? = null, + text: String? = null, + entities: RawMessageEntities? = null, + isPrivate: Boolean = false ) : this( - gift, - origin ?.let { Origin.fromString(it) }, - text, - entities, - isPrivate, - lastResaleStarCount, - lastResaleCurrency, - lastResaleAmount, - transferStarCount, - nextTransferDate + gift = gift, + originTyped = origin ?.let { Origin.fromString(it) }, + lastResaleStarCount = lastResaleStarCount, + lastResaleCurrency = lastResaleCurrency, + lastResaleAmount = lastResaleAmount, + transferStarCount = transferStarCount, + nextTransferDate = nextTransferDate, + text = text, + entities = entities, + isPrivate = isPrivate ) } @@ -359,12 +359,6 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { override val ownedGiftId: GiftId, @SerialName(originField) override val originTyped: Origin? = null, - @SerialName(textField) - override val text: String? = null, - @SerialName(entitiesField) - private val entities: RawMessageEntities? = null, - @SerialName(isPrivateField) - override val isPrivate: Boolean = false, @Deprecated("Use lastResaleCurrency and lastResaleAmount instead") @SerialName(lastResaleStarCountField) override val lastResaleStarCount: Int? = null, @@ -375,7 +369,13 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { @SerialName(transferStarCountField) override val transferStarCount: Int? = null, @SerialName(nextTransferDateField) - override val nextTransferDate: TelegramDate? = null + override val nextTransferDate: TelegramDate? = null, + @SerialName(textField) + override val text: String? = null, + @SerialName(entitiesField) + private val entities: RawMessageEntities? = null, + @SerialName(isPrivateField) + override val isPrivate: Boolean = false ) : UniqueGift, GiftSentOrReceivedEvent.ReceivedInBusinessAccount { @Transient override val origin: String? = originTyped ?.string @@ -388,26 +388,26 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { gift: Gift.Unique, ownedGiftId: GiftId, origin: String? = null, - text: String? = null, - entities: RawMessageEntities? = null, - isPrivate: Boolean = false, lastResaleStarCount: Int? = null, lastResaleCurrency: Currency? = null, lastResaleAmount: Long? = null, transferStarCount: Int? = null, - nextTransferDate: TelegramDate? = null + nextTransferDate: TelegramDate? = null, + text: String? = null, + entities: RawMessageEntities? = null, + isPrivate: Boolean = false ) : this( gift = gift, ownedGiftId = ownedGiftId, originTyped = origin ?.let { Origin.fromString(it) }, - text = text, - entities = entities, - isPrivate = isPrivate, lastResaleStarCount = lastResaleStarCount, lastResaleCurrency = lastResaleCurrency, lastResaleAmount = lastResaleAmount, transferStarCount = transferStarCount, - nextTransferDate = nextTransferDate + nextTransferDate = nextTransferDate, + text = text, + entities = entities, + isPrivate = isPrivate ) } @@ -420,12 +420,6 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { val ownedGiftId: GiftId? = null, @SerialName(originField) val origin: Origin? = null, - @SerialName(textField) - val text: String? = null, - @SerialName(entitiesField) - val entities: RawMessageEntities? = null, - @SerialName(isPrivateField) - val isPrivate: Boolean = false, @SerialName(lastResaleStarCountField) val lastResaleStarCount: Int? = null, @SerialName(lastResaleCurrencyField) @@ -435,7 +429,13 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { @SerialName(transferStarCountField) val transferStarCount: Int? = null, @SerialName(nextTransferDateField) - val nextTransferDate: TelegramDate? = null + val nextTransferDate: TelegramDate? = null, + @SerialName(textField) + val text: String? = null, + @SerialName(entitiesField) + val entities: RawMessageEntities? = null, + @SerialName(isPrivateField) + val isPrivate: Boolean = false ) override val descriptor: SerialDescriptor @@ -456,14 +456,14 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { Common( gift = surrogate.gift, originTyped = surrogate.origin, - text = surrogate.text, - entities = surrogate.entities, - isPrivate = surrogate.isPrivate, lastResaleStarCount = surrogate.lastResaleStarCount, lastResaleCurrency = surrogate.lastResaleCurrency, lastResaleAmount = surrogate.lastResaleAmount, transferStarCount = surrogate.transferStarCount, - nextTransferDate = surrogate.nextTransferDate + nextTransferDate = surrogate.nextTransferDate, + text = surrogate.text, + entities = surrogate.entities, + isPrivate = surrogate.isPrivate ) } else -> { @@ -471,14 +471,14 @@ sealed interface GiftSentOrReceivedEvent : CommonEvent { gift = surrogate.gift, ownedGiftId = surrogate.ownedGiftId, originTyped = surrogate.origin, - text = surrogate.text, - entities = surrogate.entities, - isPrivate = surrogate.isPrivate, lastResaleStarCount = surrogate.lastResaleStarCount, lastResaleCurrency = surrogate.lastResaleCurrency, lastResaleAmount = surrogate.lastResaleAmount, transferStarCount = surrogate.transferStarCount, - nextTransferDate = surrogate.nextTransferDate + nextTransferDate = surrogate.nextTransferDate, + text = surrogate.text, + entities = surrogate.entities, + isPrivate = surrogate.isPrivate ) } } diff --git a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/GeneralBotApi103Test.kt b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/GeneralBotApi103Test.kt index 5475954d19..2a2adf843a 100644 --- a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/GeneralBotApi103Test.kt +++ b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/GeneralBotApi103Test.kt @@ -5,12 +5,14 @@ import dev.inmo.tgbotapi.requests.send.SendRichMessageDraft import dev.inmo.tgbotapi.types.gifts.GiftSentOrReceivedEvent import dev.inmo.tgbotapi.types.communities.CommunityId import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage +import dev.inmo.tgbotapi.types.message.textsources.boldTextSource import dev.inmo.tgbotapi.types.rich.InputRichMessageHTML import dev.inmo.tgbotapi.types.update.MessageGenerationStoppedUpdate import dev.inmo.tgbotapi.types.update.MessageUpdate import dev.inmo.tgbotapi.types.update.abstracts.UpdateSerializerWithoutSerialization import dev.inmo.tgbotapi.utils.nonstrictJsonFormat import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonObject import kotlin.test.Test @@ -71,4 +73,93 @@ class GeneralBotApi103Test { assertEquals(true, uniqueGift.isPrivate) assertEquals(1, uniqueGift.textSources.size) } + + @Test + fun `unique gift info preserves positional prefixes and round trips appended text fields`() { + val uniqueGift = nonstrictJsonFormat.decodeFromString( + GiftSentOrReceivedEvent.UniqueGift, + """{"gift":{"base_name":"Base","name":"unique","number":1,"model":{"name":"Model","sticker":{"file_id":"model-file","file_unique_id":"model-unique","type":"regular","width":1,"height":1},"rarity_per_mille":1},"symbol":{"name":"Symbol","sticker":{"file_id":"symbol-file","file_unique_id":"symbol-unique","type":"regular","width":1,"height":1},"rarity_per_mille":1},"backdrop":{"name":"Backdrop","colors":{"center_color":1,"edge_color":2,"symbol_color":3,"text_color":4},"rarity_per_mille":1}}}""" + ) + + val commonPrimary = GiftSentOrReceivedEvent.UniqueGift.Common( + uniqueGift.gift, + GiftSentOrReceivedEvent.UniqueGift.Origin.Upgrade, + 1, + "TON", + 2L, + 3, + TelegramDate.Start + ) + val commonSecondary = GiftSentOrReceivedEvent.UniqueGift.Common( + uniqueGift.gift, + "transfer", + 4, + "USD", + 5L, + 6, + TelegramDate.Start + ) + val businessPrimary = GiftSentOrReceivedEvent.UniqueGift.ReceivedInBusinessAccount( + uniqueGift.gift, + GiftId("owned-primary"), + GiftSentOrReceivedEvent.UniqueGift.Origin.Resale, + 7, + "EUR", + 8L, + 9, + TelegramDate.Start + ) + val businessSecondary = GiftSentOrReceivedEvent.UniqueGift.ReceivedInBusinessAccount( + uniqueGift.gift, + GiftId("owned-secondary"), + "offer", + 10, + "XTR", + 11L, + 12, + TelegramDate.Start + ) + + assertEquals(3, commonPrimary.transferStarCount) + assertEquals(6, commonSecondary.transferStarCount) + assertEquals(9, businessPrimary.transferStarCount) + assertEquals(12, businessSecondary.transferStarCount) + + val publicFactoryCommon = GiftSentOrReceivedEvent.UniqueGift( + uniqueGift.gift, + "upgrade", + null, + 13 + ) + val publicFactoryBusiness = GiftSentOrReceivedEvent.UniqueGift( + uniqueGift.gift, + "resale", + GiftId("owned-factory"), + 14 + ) + + assertEquals( + 13, + assertIs(publicFactoryCommon).transferStarCount + ) + assertEquals( + 14, + assertIs(publicFactoryBusiness).transferStarCount + ) + + val withAppendedFields = GiftSentOrReceivedEvent.UniqueGift( + gift = uniqueGift.gift, + text = "bold", + textSources = listOf(boldTextSource("bold")), + isPrivate = true + ) + val roundTripped = nonstrictJsonFormat.decodeFromString( + GiftSentOrReceivedEvent.UniqueGift, + nonstrictJsonFormat.encodeToString(GiftSentOrReceivedEvent.UniqueGift, withAppendedFields) + ) + + assertEquals("bold", roundTripped.text) + assertEquals(true, roundTripped.isPrivate) + assertEquals(listOf(boldTextSource("bold")), roundTripped.textSources) + } }