From 15ad3fbda61f69574d8567b4a357cb6d05d51529 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Fri, 27 Aug 2021 20:12:08 +0800
Subject: [PATCH] Add `BotInvitedJoinTest`

---
 .../components/NoticeProcessorPipeline.kt     |   6 +-
 .../processors/AbstractNoticeProcessorTest.kt |  30 +++-
 .../notice/processors/BotInvitedJoinTest.kt   | 152 ++++++++++++++++++
 3 files changed, 181 insertions(+), 7 deletions(-)
 create mode 100644 mirai-core/src/commonTest/kotlin/notice/processors/BotInvitedJoinTest.kt

diff --git a/mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt b/mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt
index 1b6e470df..5da5ab64c 100644
--- a/mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt
+++ b/mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt
@@ -42,6 +42,8 @@ internal typealias ProcessResult = Collection<Packet>
  * Centralized processor pipeline for [MessageSvcPbGetMsg] and [OnlinePushPbPushTransMsg]
  */
 internal interface NoticeProcessorPipeline {
+    val processors: Collection<NoticeProcessor>
+
     fun interface DisposableRegistry : Closeable {
         fun dispose()
 
@@ -193,11 +195,11 @@ private val traceLogging: MiraiLogger by lazy {
         .withSwitch(systemProp("mirai.network.notice.pipeline.log.full", false))
 }
 
-internal open class NoticeProcessorPipelineImpl private constructor() : NoticeProcessorPipeline {
+internal open class NoticeProcessorPipelineImpl protected constructor() : NoticeProcessorPipeline {
     /**
      * Must be ordered
      */
-    private val processors = ConcurrentLinkedQueue<NoticeProcessor>()
+    override val processors = ConcurrentLinkedQueue<NoticeProcessor>()
 
     override fun registerProcessor(processor: NoticeProcessor): NoticeProcessorPipeline.DisposableRegistry {
         processors.add(processor)
diff --git a/mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt b/mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt
index 20aaf3900..a5c22ef2e 100644
--- a/mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt
+++ b/mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt
@@ -9,6 +9,8 @@
 
 package net.mamoe.mirai.internal.notice.processors
 
+import kotlinx.serialization.SerializationStrategy
+import kotlinx.serialization.serializer
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.contact.*
@@ -22,14 +24,13 @@ import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
 import net.mamoe.mirai.internal.contact.info.GroupInfoImpl
 import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
 import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
-import net.mamoe.mirai.internal.network.components.LoggingPacketHandlerAdapter
+import net.mamoe.mirai.internal.network.components.*
 import net.mamoe.mirai.internal.network.components.NoticeProcessorPipeline.Companion.noticeProcessorPipeline
-import net.mamoe.mirai.internal.network.components.NoticeProcessorPipelineImpl
-import net.mamoe.mirai.internal.network.components.PacketLoggingStrategyImpl
-import net.mamoe.mirai.internal.network.components.ProcessResult
 import net.mamoe.mirai.internal.network.framework.AbstractNettyNHTest
 import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
+import net.mamoe.mirai.internal.utils.io.JceStruct
 import net.mamoe.mirai.internal.utils.io.ProtocolStruct
+import net.mamoe.mirai.internal.utils.io.serialization.tars.Tars
 import net.mamoe.mirai.utils.TypeSafeMap
 import net.mamoe.mirai.utils.cast
 import net.mamoe.mirai.utils.currentTimeSeconds
@@ -47,20 +48,39 @@ internal abstract class AbstractNoticeProcessorTest : AbstractNettyNHTest(), Gro
     protected object UseTestContext {
         val EMPTY_BYTE_ARRAY get() = net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY
         fun String.hexToBytes() = hexToUBytes().toByteArray()
+
+        internal inline fun <reified T : JceStruct> T.toByteArray(
+            serializer: SerializationStrategy<T> = serializer(),
+        ): ByteArray = Tars.UTF_8.encodeToByteArray(serializer, this)
+
     }
 
     protected suspend inline fun use(
         attributes: TypeSafeMap = TypeSafeMap(),
+        pipeline: NoticeProcessorPipeline = bot.components.noticeProcessorPipeline,
         block: UseTestContext.() -> ProtocolStruct
     ): ProcessResult {
         val handler = LoggingPacketHandlerAdapter(PacketLoggingStrategyImpl(bot), bot.logger)
-        return bot.components.noticeProcessorPipeline.process(bot, block(UseTestContext), attributes).also { list ->
+        return pipeline.process(bot, block(UseTestContext), attributes).also { list ->
             for (packet in list) {
                 handler.handlePacket(IncomingPacket("test", packet))
             }
         }
     }
 
+    protected suspend inline fun use(
+        attributes: TypeSafeMap = TypeSafeMap(),
+        crossinline createContext: NoticeProcessorPipelineImpl.(bot: QQAndroidBot, attributes: TypeSafeMap) -> NoticeProcessorPipelineImpl.ContextImpl,
+        block: UseTestContext.() -> ProtocolStruct
+    ): ProcessResult = use(attributes, pipeline = object : NoticeProcessorPipelineImpl() {
+        init {
+            bot.components.noticeProcessorPipeline.processors.forEach { registerProcessor(it) }
+        }
+
+        override fun createContext(bot: QQAndroidBot, attributes: TypeSafeMap): NoticePipelineContext =
+            createContext(this, bot, attributes)
+    }, block)
+
     fun setBot(id: Long): QQAndroidBot {
         bot = createBot(BotAccount(id, "a"))
         return bot
diff --git a/mirai-core/src/commonTest/kotlin/notice/processors/BotInvitedJoinTest.kt b/mirai-core/src/commonTest/kotlin/notice/processors/BotInvitedJoinTest.kt
new file mode 100644
index 000000000..e5f145f9b
--- /dev/null
+++ b/mirai-core/src/commonTest/kotlin/notice/processors/BotInvitedJoinTest.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2019-2021 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+@file:JvmBlockingBridge
+
+package net.mamoe.mirai.internal.notice.processors
+
+import net.mamoe.kjbb.JvmBlockingBridge
+import net.mamoe.mirai.contact.MemberPermission
+import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
+import net.mamoe.mirai.event.events.BotJoinGroupEvent
+import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.contact.GroupImpl
+import net.mamoe.mirai.internal.network.components.NoticeProcessorPipelineImpl
+import org.junit.jupiter.api.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertIs
+
+internal class BotInvitedJoinTest : AbstractNoticeProcessorTest() {
+    @Test
+    suspend fun `invited join`() {
+        suspend fun runTest() = use {
+
+            net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.StructMsg(
+                version = 1,
+                msgType = 2,
+                msgSeq = 1630,
+                msgTime = 1630,
+                reqUin = 1230,
+                msg = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsg(
+                    subType = 1,
+                    msgTitle = "邀请加群",
+                    msgDescribe = "邀请你加入 %group_name%",
+                    actions = mutableListOf(
+                        net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgAction(
+                            name = "拒绝",
+                            result = "已拒绝",
+                            actionInfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgActionInfo(
+                                type = 12,
+                                groupCode = 2230203,
+                            ),
+                            detailName = "拒绝",
+                        ), net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgAction(
+                            name = "同意",
+                            result = "已同意",
+                            actionInfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgActionInfo(
+                                type = 11,
+                                groupCode = 2230203,
+                            ),
+                            detailName = "同意",
+                        ), net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgAction(
+                            name = "忽略",
+                            result = "已忽略",
+                            actionInfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgActionInfo(
+                                type = 14,
+                                groupCode = 2230203,
+                            ),
+                            detailName = "忽略",
+                        )
+                    ),
+                    groupCode = 2230203,
+                    actionUin = 1230001,
+                    groupMsgType = 2,
+                    groupInviterRole = 1,
+                    groupInfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.GroupInfo(
+                        appPrivilegeFlag = 67698880,
+                    ),
+                    msgInviteExtinfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.MsgInviteExt(
+                    ),
+                    reqUinNick = "user3",
+                    groupName = "testtest",
+                    actionUinNick = "user1",
+                    groupExtFlag = 1075905600,
+                    actionUinQqNick = "user1",
+                    reqUinGender = 255,
+                    c2cInviteJoinGroupFlag = 1,
+                ),
+            )
+        }
+
+        setBot(1230003)
+
+        runTest().toList().run {
+            assertEquals(1, size, toString())
+            get(0).run {
+                assertIs<BotInvitedJoinGroupRequestEvent>(this)
+                assertEquals(1230001, invitorId)
+                assertEquals("user1", invitorNick)
+                assertEquals(2230203, groupId)
+                assertEquals("testtest", groupName)
+                assertEquals(1630, eventId)
+            }
+        }
+
+    }
+
+    @Test
+    suspend fun `invitation accepted`() {
+        suspend fun runTest() =
+            use(createContext = { bot, attributes ->
+                object : NoticeProcessorPipelineImpl.ContextImpl(bot, attributes) {
+                    override suspend fun QQAndroidBot.addNewGroupByUin(groupUin: Long): GroupImpl {
+                        assertEquals(204230203, groupUin) // uin of 2230203
+                        return bot.addGroup(2230203, 1230002, name = "testtest").apply {
+                            addMember(1230001, permission = MemberPermission.MEMBER)
+                        }
+                    }
+                }
+            }) {
+                net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm.Msg(
+                    msgHead = net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm.MsgHead(
+                        fromUin = 2230203,
+                        toUin = 1230003,
+                        msgType = 33,
+                        msgSeq = 61485,
+                        msgTime = 1630,
+                        msgUid = 1441,
+                        authUin = 1230003,
+                        authNick = "user3",
+                        extGroupKeyInfo = net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm.ExtGroupKeyInfo(
+                            curMaxSeq = 1631,
+                            curTime = 1630,
+                        ),
+                    ),
+                    contentHead = net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm.ContentHead(
+                    ),
+                    msgBody = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MsgBody(
+                        richText = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.RichText(
+                        ),
+                        msgContent = "00 22 07 BB 01 00 12 C4 B3 03 00 12 C4 B1 00 00 30 34 32 42 39 44 46 43 34 39 45 42 34 30 46 41 42 45 45 32 33 36 34 37 45 46 39 35 31 44 44 42 31 31 32 36 31 31 38 44 43 46 44 32 37 42 30 42 45".hexToBytes(),
+                    ),
+                )
+            }
+
+        setBot(1230003)
+
+        runTest().toList().run {
+            assertEquals(1, size, toString())
+            get(0).run {
+                assertIs<BotJoinGroupEvent.Invite>(this)
+                assertEquals(1230001, invitor.id)
+                assertEquals(2230203, group.id)
+            }
+        }
+    }
+}
\ No newline at end of file