diff --git a/mirai-core-mock/src/contact/MockGroup.kt b/mirai-core-mock/src/contact/MockGroup.kt index 0c52e5b69..cb36df45c 100644 --- a/mirai-core-mock/src/contact/MockGroup.kt +++ b/mirai-core-mock/src/contact/MockGroup.kt @@ -17,7 +17,6 @@ import net.mamoe.mirai.contact.NormalMember import net.mamoe.mirai.data.GroupHonorType import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.broadcast -import net.mamoe.mirai.event.events.MemberHonorChangeEvent import net.mamoe.mirai.event.events.MemberJoinRequestEvent import net.mamoe.mirai.mock.MockBot import net.mamoe.mirai.mock.MockBotDSL @@ -51,6 +50,11 @@ public interface MockGroup : Group, MockContact, MockMsgSyncSupport { * @see changeHonorMember */ @MockBotDSL + @Deprecated( + "use active.changeHonorMember", + ReplaceWith(".active.changeHonorMember(member, honorType)"), + level = DeprecationLevel.ERROR + ) public val honorMembers: MutableMap /** @@ -61,10 +65,11 @@ public interface MockGroup : Group, MockContact, MockMsgSyncSupport { * 此外如果 [honorType] 是 [GroupHonorType.TALKATIVE], * 会额外广播 [net.mamoe.mirai.event.events.GroupTalkativeChangeEvent]. * - * 如果不需要广播事件, 可直接更改 [MockGroup.honorMembers] + * 如果不需要广播事件, 可直接使用 [MockGroupActive.mockSetHonorHistory] */ - @MockBotDSL - public fun changeHonorMember(member: MockNormalMember, honorType: GroupHonorType) + public fun changeHonorMember(member: MockNormalMember, honorType: GroupHonorType) { + active.changeHonorMember(member, honorType) + } /** * 获取群控制面板 diff --git a/mirai-core-mock/src/contact/active/MockGroupActive.kt b/mirai-core-mock/src/contact/active/MockGroupActive.kt index b30c8cfd5..706f419be 100644 --- a/mirai-core-mock/src/contact/active/MockGroupActive.kt +++ b/mirai-core-mock/src/contact/active/MockGroupActive.kt @@ -11,6 +11,9 @@ package net.mamoe.mirai.mock.contact.active import net.mamoe.mirai.contact.active.* import net.mamoe.mirai.data.GroupHonorType +import net.mamoe.mirai.event.events.MemberHonorChangeEvent +import net.mamoe.mirai.mock.MockBotDSL +import net.mamoe.mirai.mock.contact.MockNormalMember public interface MockGroupActive : GroupActive { /** @@ -39,4 +42,17 @@ public interface MockGroupActive : GroupActive { * @see queryActiveRank */ public fun mockSetRankRecords(list: List) + + /** + * 更改拥有群荣耀的群成员. + * + * 会自动广播 [MemberHonorChangeEvent.Achieve] 和 [MemberHonorChangeEvent.Lose] 等相关事件. + * + * 此外如果 [honorType] 是 [GroupHonorType.TALKATIVE], + * 会额外广播 [net.mamoe.mirai.event.events.GroupTalkativeChangeEvent]. + * + * 如果不需要广播事件, 可直接使用 [mockSetHonorHistory] + */ + @MockBotDSL + public fun changeHonorMember(member: MockNormalMember, honorType: GroupHonorType) } \ No newline at end of file diff --git a/mirai-core-mock/src/internal/contact/MockGroupImpl.kt b/mirai-core-mock/src/internal/contact/MockGroupImpl.kt index 280ec2949..b0be49d21 100644 --- a/mirai-core-mock/src/internal/contact/MockGroupImpl.kt +++ b/mirai-core-mock/src/internal/contact/MockGroupImpl.kt @@ -52,6 +52,11 @@ internal class MockGroupImpl( ) : AbstractMockContact( parentCoroutineContext, bot, id ), MockGroup { + @Deprecated( + "use active.changeHonorMember", + replaceWith = ReplaceWith(".active.changeHonorMember(member, honorType)"), + level = DeprecationLevel.ERROR + ) override val honorMembers: MutableMap = ConcurrentHashMap() private val txFileSystem by lazy { bot.mock().tmpResourceServer.mockServerFileDisk.newFsSystem() } @@ -61,17 +66,6 @@ internal class MockGroupImpl( override val active: MockGroupActive by lazy { MockGroupActiveImpl(this) } - override fun changeHonorMember(member: MockNormalMember, honorType: GroupHonorType) { - val onm = honorMembers[honorType] - honorMembers[honorType] = member - // reference net.mamoe.mirai.internal.network.notice.group.NoticePipelineContext.processGeneralGrayTip, GroupNotificationProcessor.kt#361L - if (honorType == GroupHonorType.TALKATIVE) { - if (onm != null) GroupTalkativeChangeEvent(this, member, onm).broadcastBlocking() - } - if (onm != null) MemberHonorChangeEvent.Lose(onm, honorType).broadcastBlocking() - MemberHonorChangeEvent.Achieve(member, honorType).broadcastBlocking() - } - override fun appendMember(mockMember: MemberInfo): MockGroup { addMember(mockMember) return this diff --git a/mirai-core-mock/src/internal/contact/active/MockGroupActive.kt b/mirai-core-mock/src/internal/contact/active/MockGroupActive.kt index b63b57fc2..e7fbd5539 100644 --- a/mirai-core-mock/src/internal/contact/active/MockGroupActive.kt +++ b/mirai-core-mock/src/internal/contact/active/MockGroupActive.kt @@ -12,14 +12,15 @@ package net.mamoe.mirai.mock.internal.contact.active import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asFlow import net.mamoe.mirai.contact.MemberPermission -import net.mamoe.mirai.contact.active.ActiveChart -import net.mamoe.mirai.contact.active.ActiveHonorList -import net.mamoe.mirai.contact.active.ActiveRankRecord -import net.mamoe.mirai.contact.active.ActiveRecord +import net.mamoe.mirai.contact.active.* import net.mamoe.mirai.contact.checkBotPermission import net.mamoe.mirai.data.GroupHonorType +import net.mamoe.mirai.event.events.GroupTalkativeChangeEvent +import net.mamoe.mirai.event.events.MemberHonorChangeEvent +import net.mamoe.mirai.mock.contact.MockNormalMember import net.mamoe.mirai.mock.contact.active.MockGroupActive import net.mamoe.mirai.mock.internal.contact.MockGroupImpl +import net.mamoe.mirai.mock.utils.broadcastBlocking import net.mamoe.mirai.utils.ConcurrentHashMap import net.mamoe.mirai.utils.JavaFriendlyAPI import net.mamoe.mirai.utils.asImmutable @@ -82,6 +83,33 @@ internal class MockGroupActiveImpl( private var honorHistories: MutableMap = ConcurrentHashMap() + @Suppress("INVISIBLE_MEMBER") // for ActiveHonorInfo + override fun changeHonorMember(member: MockNormalMember, honorType: GroupHonorType) { + val old = honorHistories[honorType] + + val info = ActiveHonorInfo(member.nameCard, member.id, member.avatarUrl, member, 0, 0, 0) + if (old == null) { + // if not history record found, add a new one with current honor member + honorHistories[honorType] = ActiveHonorList(honorType, info, emptyList()) + } else if (old.current?.memberId != info.memberId) { + honorHistories[honorType] = + ActiveHonorList(honorType, info, old.current?.let { + old.records.plus(it) + } ?: old.records) + if (old.current != null) { + if (honorType == GroupHonorType.TALKATIVE) { + GroupTalkativeChangeEvent( + this.group, + member, + old.current!!.member!! + ).broadcastBlocking() + } + MemberHonorChangeEvent.Lose(old.current!!.member!!, honorType).broadcastBlocking() + } + } + MemberHonorChangeEvent.Achieve(member, honorType).broadcastBlocking() + } + override suspend fun queryHonorHistory(type: GroupHonorType): ActiveHonorList { return honorHistories.getOrElse(type) { ActiveHonorList(type, null, listOf()) } } diff --git a/mirai-core-mock/test/mock/MockGroupTest.kt b/mirai-core-mock/test/mock/MockGroupTest.kt index 485068a98..df64c110e 100644 --- a/mirai-core-mock/test/mock/MockGroupTest.kt +++ b/mirai-core-mock/test/mock/MockGroupTest.kt @@ -163,25 +163,6 @@ internal class MockGroupTest : MockBotTestBase() { assertEquals(0, fsroot.listFilesCollection().size) } - @Test - internal fun testMemberHonorChangeEvent() = runTest { - runAndReceiveEventBroadcast { - val group = bot.addGroup(111, "aa") - val member1 = group.addMember(simpleMemberInfo(222, "bb", permission = MemberPermission.MEMBER)) - val member2 = group.addMember(simpleMemberInfo(333, "cc", permission = MemberPermission.MEMBER)) - group.honorMembers[GroupHonorType.TALKATIVE] = member1 - group.changeHonorMember(member2, GroupHonorType.TALKATIVE) - }.let { events -> - assertEquals(3, events.size) - assertIsInstance(events[0]) - assertIsInstance(events[1]) - assertEquals(222, events[1].cast().member.id) - assertIsInstance(events[2]) - assertEquals(GroupHonorType.TALKATIVE, events[2].cast().honorType) - assertEquals(333, events[2].cast().member.id) - } - } - @Test internal fun testGroupFileUpload() = runTest { val files = bot.addGroup(111, "aaa").files @@ -457,4 +438,108 @@ internal class MockGroupTest : MockBotTestBase() { } } } + + @Test + fun testHonorMember() = runTest { + val group = bot.addGroup(1, "") + val member1 = group.addMember(2, "") + val member2 = group.addMember(3, "") + assertEquals(emptyList(), group.active.queryHonorHistory(GroupHonorType.TALKATIVE).records) + + runAndReceiveEventBroadcast { + group.active.changeHonorMember(member1, GroupHonorType.TALKATIVE) + }.let { events -> + assertEquals(1, events.size) + assertIsInstance(events[0]) { + assertEquals(GroupHonorType.TALKATIVE, this.honorType) + assertEquals(member1, this.member) + assertEquals(group, this.group) + } + } + assertEquals(member1, group.active.queryHonorHistory(GroupHonorType.TALKATIVE).current!!.member!!) + assertEquals(emptyList(), group.active.queryHonorHistory(GroupHonorType.TALKATIVE).records) + + runAndReceiveEventBroadcast { + group.active.changeHonorMember(member2, GroupHonorType.TALKATIVE) + }.let { events -> + assertEquals(3, events.size) + assertIsInstance(events[0]) { + assertEquals(member2, this.now) + assertEquals(member1, this.previous) + assertEquals(group, this.group) + } + assertIsInstance(events[1]) { + assertEquals(GroupHonorType.TALKATIVE, this.honorType) + assertEquals(member1, this.member) + assertEquals(group, this.group) + } + assertIsInstance(events[2]) { + assertEquals(GroupHonorType.TALKATIVE, this.honorType) + assertEquals(member2, this.member) + assertEquals(group, this.group) + } + } + + assertEquals(member2, group.active.queryHonorHistory(GroupHonorType.TALKATIVE).current!!.member!!) + // it.member must exist + assertEquals( + listOf(member1), + group.active.queryHonorHistory(GroupHonorType.TALKATIVE).records.map { it.member!! }) + + runAndReceiveEventBroadcast { + group.active.changeHonorMember(member1, GroupHonorType.TALKATIVE) + }.let { events -> + assertEquals(3, events.size) + assertIsInstance(events[0]) { + assertEquals(member1, this.now) + assertEquals(member2, this.previous) + assertEquals(group, this.group) + } + assertIsInstance(events[1]) { + assertEquals(GroupHonorType.TALKATIVE, this.honorType) + assertEquals(member2, this.member) + assertEquals(group, this.group) + } + assertIsInstance(events[2]) { + assertEquals(GroupHonorType.TALKATIVE, this.honorType) + assertEquals(member1, this.member) + assertEquals(group, this.group) + } + } + assertEquals(member1, group.active.queryHonorHistory(GroupHonorType.TALKATIVE).current!!.member!!) + assertEquals( + listOf(member1, member2), + group.active.queryHonorHistory(GroupHonorType.TALKATIVE).records.map { it.member!! }) + + runAndReceiveEventBroadcast { + group.active.changeHonorMember(member1, GroupHonorType.BRONZE) + }.let { events -> + assertEquals(1, events.size) + assertIsInstance(events[0]) { + assertEquals(GroupHonorType.BRONZE, this.honorType) + assertEquals(member1, this.member) + assertEquals(group, this.group) + } + } + assertEquals(member1, group.active.queryHonorHistory(GroupHonorType.BRONZE).current!!.member!!) + assertEquals(emptyList(), group.active.queryHonorHistory(GroupHonorType.BRONZE).records) + + runAndReceiveEventBroadcast { + group.active.changeHonorMember(member2, GroupHonorType.BRONZE) + }.let { events -> + assertEquals(2, events.size) + assertIsInstance(events[0]) { + assertEquals(GroupHonorType.BRONZE, this.honorType) + assertEquals(member1, this.member) + assertEquals(group, this.group) + } + assertIsInstance(events[1]) { + assertEquals(GroupHonorType.BRONZE, this.honorType) + assertEquals(member2, this.member) + assertEquals(group, this.group) + } + } + assertEquals(member2, group.active.queryHonorHistory(GroupHonorType.BRONZE).current!!.member!!) + assertEquals(listOf(member1), group.active.queryHonorHistory(GroupHonorType.BRONZE).records.map { it.member!! }) + } } \ No newline at end of file