From eacdfed97a3fa73dba605b8b272fba997a3b6e02 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 26 Dec 2020 23:42:44 +0800 Subject: [PATCH] Fix serialization --- .../kotlin/message/MessageSerializer.kt | 42 ++++++++++-- .../commonMain/kotlin/message/data/Message.kt | 18 +++-- .../kotlin/message/data/MessageChain.kt | 40 ++++++++++- .../kotlin/message/data/MessageSource.kt | 4 +- mirai-core/src/commonMain/kotlin/MiraiImpl.kt | 47 ++++--------- .../kotlin/message/incomingSourceImpl.kt | 12 ++++ .../kotlin/message/offlineSourceImpl.kt | 66 +++++++++++++++++++ .../kotlin/network/protocol/data/proto/Msg.kt | 45 ++++++++++++- .../message/data/MessageSerializationTest.kt | 55 +++++++++++++--- 9 files changed, 268 insertions(+), 61 deletions(-) diff --git a/mirai-core-api/src/commonMain/kotlin/message/MessageSerializer.kt b/mirai-core-api/src/commonMain/kotlin/message/MessageSerializer.kt index 2204f5678..0ab4937d6 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/MessageSerializer.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/MessageSerializer.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.message import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.modules.PolymorphicModuleBuilder @@ -21,6 +22,7 @@ import kotlinx.serialization.modules.polymorphic import net.mamoe.mirai.Mirai import net.mamoe.mirai.message.data.* import net.mamoe.mirai.utils.MiraiExperimentalApi +import net.mamoe.mirai.utils.MiraiInternalApi import kotlin.reflect.KClass @MiraiExperimentalApi @@ -34,9 +36,12 @@ public interface MessageSerializer { public fun clearRegisteredSerializers() } -internal object MessageSourceSerializer : KSerializer { +@MiraiInternalApi +public open class MessageSourceSerializerImpl(serialName: String) : KSerializer { + public companion object : MessageSourceSerializerImpl("net.mamoe.mirai.message.data.MessageSource") + @Serializable - class SerialData( + internal class SerialData( val kind: MessageSourceKind, val bot: Long, val ids: IntArray, @@ -47,7 +52,17 @@ internal object MessageSourceSerializer : KSerializer { val originalMessage: MessageChain, ) - override val descriptor: SerialDescriptor = SerialData.serializer().descriptor + override val descriptor: SerialDescriptor = buildClassSerialDescriptor(serialName) { + val desc = SerialData.serializer().descriptor + repeat(SerialData.serializer().descriptor.elementsCount) { index -> + element( + desc.getElementName(index), + desc.getElementDescriptor(index), + desc.getElementAnnotations(index), + desc.isElementOptional(index) + ) + } + } // buildClassSerialDescriptor("MessageSource") { // element("bot", Long.serializer().descriptor) // element("ids", ArraySerializer(Int.serializer()).descriptor) @@ -96,7 +111,6 @@ private val builtInSerializersModule by lazy { contextual(CustomMessage::class, CustomMessage.serializer()) contextual(CustomMessageMetadata::class, CustomMessageMetadata.serializer()) contextual(Face::class, Face.serializer()) - contextual(MessageSource::class, MessageSource.serializer()) contextual(Image::class, Image.Serializer) contextual(PlainText::class, PlainText.serializer()) contextual(QuoteReply::class, QuoteReply.serializer()) @@ -117,8 +131,12 @@ private val builtInSerializersModule by lazy { contextual(FlashImage::class, FlashImage.serializer()) fun PolymorphicModuleBuilder.singleMessageSubclasses() { + // subclass(MessageSource::class, MessageSource.serializer()) } + // contextual(MessageSource::class, MessageSource.serializer()) + polymorphicDefault(MessageSource::class) { MessageSource.serializer() } + fun PolymorphicModuleBuilder.messageMetadataSubclasses() { subclass(MessageSource::class, MessageSource.serializer()) subclass(QuoteReply::class, QuoteReply.serializer()) @@ -148,7 +166,14 @@ private val builtInSerializersModule by lazy { subclass(FlashImage::class, FlashImage.serializer()) } + contextual(Message::class, Message.Serializer) + // contextual(SingleMessage::class, SingleMessage.Serializer) contextual(MessageChain::class, MessageChain.Serializer) + contextual(MessageChainImpl::class, MessageChainImpl.serializer()) + + polymorphic(MessageChain::class) { + subclass(MessageChainImpl::class, MessageChainImpl.serializer()) + } polymorphicDefault(MessageChain::class) { MessageChainImpl.serializer() } polymorphic(AbstractServiceMessage::class) { @@ -156,9 +181,15 @@ private val builtInSerializersModule by lazy { subclass(ForwardMessageInternal::class, ForwardMessageInternal.serializer()) } + // polymorphic(SingleMessage::class) { + // subclass(MessageSource::class, MessageSource.serializer()) + // default { + // Message.Serializer.serializersModule.getPolymorphic(Message::class, it) + // } + // } + polymorphicDefault(Image::class) { Image.Serializer } - contextual(Message::class, Message.Serializer) // polymorphic(Message::class) { // subclass(PlainText::class, PlainText.serializer()) // } @@ -166,6 +197,7 @@ private val builtInSerializersModule by lazy { messageContentSubclasses() messageMetadataSubclasses() singleMessageSubclasses() + subclass(MessageChainImpl::class, MessageChainImpl.serializer()) } //contextual(SingleMessage::class, SingleMessage.Serializer) diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/Message.kt b/mirai-core-api/src/commonMain/kotlin/message/data/Message.kt index 46ad95a9e..c09305913 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/Message.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/Message.kt @@ -209,8 +209,12 @@ public interface Message { // must be interface. Don't consider any changes. */ @JvmOverloads @JvmStatic - public fun deserializeFromJsonString(string: String, json: Json = Json.Default): Message = - json.decodeFromString(Serializer, string) + public fun deserializeFromJsonString( + string: String, + json: Json = Json { serializersModule = Serializer.serializersModule } + ): Message { + return json.decodeFromString(Serializer, string) + } /** * 将 [Message] 序列化为 JSON 字符串. @@ -218,8 +222,9 @@ public interface Message { // must be interface. Don't consider any changes. */ @JvmOverloads @JvmStatic - public fun Message.serializeToJsonString(json: Json = Json.Default): String = - json.encodeToString(Serializer, this) + public fun Message.serializeToJsonString( + json: Json = Json { serializersModule = Serializer.serializersModule } + ): String = json.encodeToString(Serializer, this) /** * 将 [Message] 序列化为指定格式的字符串. @@ -320,9 +325,10 @@ public inline operator fun Message.times(count: Int): MessageChain = this.repeat /** * 单个消息元素. 与之相对的是 [MessageChain], 是多个 [SingleMessage] 的集合. */ -@Serializable(SingleMessage.Serializer::class) +// @Serializable(SingleMessage.Serializer::class) public interface SingleMessage : Message { - public object Serializer : KSerializer by PolymorphicSerializer(SingleMessage::class) + // @kotlinx.serialization.Serializer(forClass = SingleMessage::class) + // public object Serializer : KSerializer by PolymorphicSerializer(SingleMessage::class) } /** diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt b/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt index 6a4dff71e..f0914ac4f 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt @@ -13,12 +13,12 @@ package net.mamoe.mirai.message.data -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable +import kotlinx.serialization.* import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.Json import net.mamoe.mirai.event.events.MessageEvent import net.mamoe.mirai.message.code.CodableMessage import net.mamoe.mirai.message.data.MessageSource.Key.quote @@ -104,6 +104,42 @@ public interface MessageChain : Message, List, RandomAccess, Coda override fun appendMiraiCode(builder: StringBuilder) { forEach { it.safeCast()?.appendMiraiCode(builder) } } + + public companion object { + /** + * 从 JSON 字符串解析 [MessageChain] + * @see serializeToJsonString + */ + @JvmOverloads + @JvmStatic + public fun deserializeFromJsonString( + string: String, + json: Json = Json { serializersModule = Message.Serializer.serializersModule } + ): MessageChain { + return json.decodeFromString(Serializer, string) + } + + /** + * 将 [MessageChain] 序列化为 JSON 字符串. + * @see deserializeFromJsonString + */ + @JvmOverloads + @JvmStatic + public fun MessageChain.serializeToJsonString( + json: Json = Json { serializersModule = Message.Serializer.serializersModule } + ): String = json.encodeToString(Message.Serializer, this) + + /** + * 将 [MessageChain] 序列化为指定格式的字符串. + * + * @see serializeToJsonString + * @see StringFormat.encodeToString + */ + @ExperimentalSerializationApi + @JvmStatic + public fun MessageChain.serializeToString(format: StringFormat): String = + format.encodeToString(Serializer, this) + } } // region accessors diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt b/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt index 095db54a1..a9a196eb3 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt @@ -25,7 +25,7 @@ import net.mamoe.mirai.contact.* import net.mamoe.mirai.event.events.MessageEvent import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt.Companion.recall -import net.mamoe.mirai.message.MessageSourceSerializer +import net.mamoe.mirai.message.MessageSourceSerializerImpl import net.mamoe.mirai.message.data.MessageSource.Key.isAboutFriend import net.mamoe.mirai.message.data.MessageSource.Key.isAboutGroup import net.mamoe.mirai.message.data.MessageSource.Key.isAboutTemp @@ -69,7 +69,7 @@ import net.mamoe.mirai.utils.safeCast * * @see buildMessageSource 构造一个 [OfflineMessageSource] */ -@Serializable(MessageSourceSerializer::class) +@Serializable(MessageSourceSerializerImpl.Companion::class) public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle { @ExperimentalMessageKey public final override val key: MessageKey diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index 596d23e06..bb0cdc12a 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt @@ -25,7 +25,6 @@ import net.mamoe.mirai.internal.contact.* import net.mamoe.mirai.internal.message.* import net.mamoe.mirai.internal.network.highway.HighwayHelper import net.mamoe.mirai.internal.network.protocol.data.jce.SvcDevLoginInfo -import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.network.protocol.data.proto.LongMsg import net.mamoe.mirai.internal.network.protocol.packet.chat.* import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.PttStore @@ -40,7 +39,6 @@ import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2 import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource -import java.util.concurrent.atomic.AtomicBoolean import kotlin.math.absoluteValue import kotlin.random.Random @@ -54,6 +52,15 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { Message.Serializer.registerSerializer(OfflineGroupImage::class, OfflineGroupImage.serializer()) Message.Serializer.registerSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer()) Message.Serializer.registerSerializer(MarketFaceImpl::class, MarketFaceImpl.serializer()) + Message.Serializer.registerSerializer( + OfflineMessageSourceImplData::class, + OfflineMessageSourceImplData.serializer() + ) + + Message.Serializer.registerSerializer( + MessageSourceFromGroupImpl::class, + MessageSourceFromGroupImpl.serializer() + ) } } @@ -843,38 +850,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { time: Int, internalIds: IntArray, originalMessage: MessageChain - ): OfflineMessageSource { - return object : OfflineMessageSource(), MessageSourceInternal { - override val kind: MessageSourceKind get() = kind - override val ids: IntArray get() = ids - override val botId: Long get() = botId - override val time: Int get() = time - override val fromId: Long get() = fromUin - override val targetId: Long get() = targetUin - override val originalMessage: MessageChain get() = originalMessage - override val sequenceIds: IntArray = ids - override val internalIds: IntArray = internalIds - - @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) - - override fun toJceData(): ImMsgBody.SourceMsg { - return ImMsgBody.SourceMsg( - origSeqs = sequenceIds, - senderUin = fromUin, - toUin = 0, - flag = 1, - elems = originalMessage.toRichTextElems( - null, //forGroup = kind == MessageSourceKind.GROUP, - withGeneralFlags = false - ), - type = 0, - time = time, - pbReserve = EMPTY_BYTE_ARRAY, - srcMsg = EMPTY_BYTE_ARRAY - ) - } - } - } + ): OfflineMessageSource = OfflineMessageSourceImplData( + kind, ids, botId, time, fromUin, targetUin, originalMessage, internalIds + ) } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt index ba9f88c09..3d1c903ac 100644 --- a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt +++ b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt @@ -11,6 +11,8 @@ package net.mamoe.mirai.internal.message +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Member @@ -22,6 +24,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.internal.utils._miraiContentToString import net.mamoe.mirai.internal.utils.io.serialization.toByteArray +import net.mamoe.mirai.message.MessageSourceSerializerImpl import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageSource @@ -32,12 +35,17 @@ import net.mamoe.mirai.utils.mapToIntArray import java.util.concurrent.atomic.AtomicBoolean internal interface MessageSourceInternal { + @Transient val sequenceIds: IntArray + + @Transient val internalIds: IntArray // randomId @Deprecated("don't use this internally. Use sequenceId or random instead.", level = DeprecationLevel.ERROR) + @Transient val ids: IntArray + @Transient val isRecalledOrPlanned: AtomicBoolean fun toJceData(): ImMsgBody.SourceMsg @@ -148,10 +156,14 @@ internal class MessageSourceFromTempImpl( override fun toJceData(): ImMsgBody.SourceMsg = jceData } +@Serializable(MessageSourceFromGroupImpl.Serializer::class) internal data class MessageSourceFromGroupImpl( override val bot: Bot, private val msg: List ) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal { + object Serializer : MessageSourceSerializerImpl("net.mamoe.mirai.internal.message.MessageSourceFromGroupImpl") + + @Transient override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq } override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random } diff --git a/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt index 8ad6f9e18..081118dfc 100644 --- a/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt +++ b/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt @@ -11,6 +11,8 @@ package net.mamoe.mirai.internal.message +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg @@ -22,6 +24,70 @@ import net.mamoe.mirai.message.data.OfflineMessageSource import net.mamoe.mirai.utils.mapToIntArray import java.util.concurrent.atomic.AtomicBoolean +@Serializable +internal data class OfflineMessageSourceImplData( + override val kind: MessageSourceKind, + override val ids: IntArray, + override val botId: Long, + override val time: Int, + override val fromId: Long, + override val targetId: Long, + override val originalMessage: MessageChain, + override val internalIds: IntArray, +) : OfflineMessageSource(), MessageSourceInternal { + override val sequenceIds: IntArray get() = ids + + @Transient + @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) + + override fun toJceData(): ImMsgBody.SourceMsg { + return ImMsgBody.SourceMsg( + origSeqs = sequenceIds, + senderUin = fromId, + toUin = 0, + flag = 1, + elems = originalMessage.toRichTextElems( + null, //forGroup = kind == MessageSourceKind.GROUP, + withGeneralFlags = false + ), + type = 0, + time = time, + pbReserve = net.mamoe.mirai.internal.EMPTY_BYTE_ARRAY, + srcMsg = net.mamoe.mirai.internal.EMPTY_BYTE_ARRAY + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as OfflineMessageSourceImplData + + if (kind != other.kind) return false + if (!ids.contentEquals(other.ids)) return false + if (botId != other.botId) return false + if (time != other.time) return false + if (fromId != other.fromId) return false + if (targetId != other.targetId) return false + if (originalMessage != other.originalMessage) return false + if (!internalIds.contentEquals(other.internalIds)) return false + + return true + } + + override fun hashCode(): Int { + var result = kind.hashCode() + result = 31 * result + ids.contentHashCode() + result = 31 * result + botId.hashCode() + result = 31 * result + time + result = 31 * result + fromId.hashCode() + result = 31 * result + targetId.hashCode() + result = 31 * result + originalMessage.hashCode() + result = 31 * result + internalIds.contentHashCode() + return result + } +} internal class OfflineMessageSourceImplByMsg( // from other sources' originalMessage diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt index 791138cac..2b4d22823 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt @@ -563,7 +563,7 @@ internal class ImMsgBody : ProtoBuf { ) : ProtoBuf @Serializable - internal class MarketFace( + internal data class MarketFace( @ProtoNumber(1) @JvmField val faceName: ByteArray = EMPTY_BYTE_ARRAY, @ProtoNumber(2) @JvmField val itemType: Int = 0, @ProtoNumber(3) @JvmField val faceInfo: Int = 0, @@ -577,7 +577,48 @@ internal class ImMsgBody : ProtoBuf { @ProtoNumber(11) @JvmField val imageHeight: Int = 0, @ProtoNumber(12) @JvmField val mobileParam: ByteArray = EMPTY_BYTE_ARRAY, @ProtoNumber(13) @JvmField val pbReserve: ByteArray = EMPTY_BYTE_ARRAY - ) : ProtoBuf + ) : ProtoBuf { + @Suppress("DuplicatedCode") + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MarketFace + + if (!faceName.contentEquals(other.faceName)) return false + if (itemType != other.itemType) return false + if (faceInfo != other.faceInfo) return false + if (!faceId.contentEquals(other.faceId)) return false + if (tabId != other.tabId) return false + if (subType != other.subType) return false + if (!key.contentEquals(other.key)) return false + if (!param.contentEquals(other.param)) return false + if (mediaType != other.mediaType) return false + if (imageWidth != other.imageWidth) return false + if (imageHeight != other.imageHeight) return false + if (!mobileParam.contentEquals(other.mobileParam)) return false + if (!pbReserve.contentEquals(other.pbReserve)) return false + + return true + } + + override fun hashCode(): Int { + var result = faceName.contentHashCode() + result = 31 * result + itemType + result = 31 * result + faceInfo + result = 31 * result + faceId.contentHashCode() + result = 31 * result + tabId + result = 31 * result + subType + result = 31 * result + key.contentHashCode() + result = 31 * result + param.contentHashCode() + result = 31 * result + mediaType + result = 31 * result + imageWidth + result = 31 * result + imageHeight + result = 31 * result + mobileParam.contentHashCode() + result = 31 * result + pbReserve.contentHashCode() + return result + } + } @Serializable internal class MarketTrans( diff --git a/mirai-core/src/jvmTest/kotlin/message/data/MessageSerializationTest.kt b/mirai-core/src/jvmTest/kotlin/message/data/MessageSerializationTest.kt index aa7886ab5..918d32ec3 100644 --- a/mirai-core/src/jvmTest/kotlin/message/data/MessageSerializationTest.kt +++ b/mirai-core/src/jvmTest/kotlin/message/data/MessageSerializationTest.kt @@ -13,17 +13,20 @@ import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.serializer import net.mamoe.mirai.Mirai +import net.mamoe.mirai.internal.message.MarketFaceImpl +import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.message.data.* import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import kotlin.test.assertEquals internal class MessageSerializationTest { - private val module = Message.Serializer.serializersModule - private val format = Json { - serializersModule = module - useArrayPolymorphism = false - } + private val module get() = Message.Serializer.serializersModule + private val format + get() = Json { + serializersModule = module + useArrayPolymorphism = false // ? + } private inline fun T.serialize(serializer: KSerializer = module.serializer()): String { return format.encodeToString(serializer, this) @@ -34,23 +37,57 @@ internal class MessageSerializationTest { } private inline fun testSerialization(t: T, serializer: KSerializer = module.serializer()) { + val deserialized = t.serialize(serializer).deserialize(serializer) assertEquals( t, - t.serialize(serializer).deserialize(serializer), - message = "serialized string: ${t.serialize(serializer)}" + deserialized, + message = "serialized string: ${t.serialize(serializer)}\ndeserialized string: ${ + deserialized.serialize( + serializer + ) + }\n" ) } + + private val image = Image("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai") private val testMessageContentInstances: Array = arrayOf( PlainText("test"), At(123456), AtAll, - Image("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai"), + image, + image.toForwardMessage(1L, "test"), + VipFace(VipFace.AiXin, 1), + PokeMessage.BaoBeiQiu, + Face(Face.AI_NI), + MarketFaceImpl(ImMsgBody.MarketFace()), + image.flash(), + ) + + private val emptySource = Mirai.constructMessageSource( + 1L, + MessageSourceKind.FRIEND, + 1, + 2, + intArrayOf(1), + 1, + intArrayOf(1), + messageChainOf() ) @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") private val testConstrainSingleMessageInstances: Array = arrayOf( - LongMessage("content", "resId") + LongMessage("content", "resId"), + Mirai.constructMessageSource( + 1L, + MessageSourceKind.FRIEND, + 1, + 2, + intArrayOf(1), + 1, + intArrayOf(1), + messageChainOf(emptySource, image) + ), ) companion object {