Skip to content

Commit 2a805bd

Browse files
committed
Added client test for the Chat Box peripheral
1 parent 321ab7e commit 2a805bd

File tree

8 files changed

+500
-1
lines changed

8 files changed

+500
-1
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ minecraft {
171171
property 'forge.logging.console.level', 'debug'
172172
property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest'
173173
property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath
174+
property 'advancedperipheralstest.tags', 'common,client'
174175

175176
args "--mixin.config=ccgametest.mixins.json"
176177
args "--mixin.config=advancedperipheralstest.mixins.json"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package dan200.computercraft.gametest.core;
2+
3+
import com.google.common.collect.Lists;
4+
import net.minecraft.client.gui.components.toasts.Toast;
5+
import net.minecraftforge.api.distmarker.Dist;
6+
import net.minecraftforge.client.event.ToastAddEvent;
7+
import net.minecraftforge.eventbus.api.SubscribeEvent;
8+
import net.minecraftforge.fml.common.Mod;
9+
10+
import java.util.List;
11+
12+
@Mod.EventBusSubscriber(modid = TestMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT)
13+
public class ClientTestEvents {
14+
public static final List<Toast> toasts = Lists.newArrayList();
15+
16+
@SubscribeEvent
17+
public static void onToast(ToastAddEvent event) {
18+
toasts.add(event.getToast());
19+
}
20+
21+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package de.srendi.advancedperipherals.test
2+
3+
import net.minecraft.client.Minecraft
4+
import net.minecraft.gametest.framework.GameTestAssertException
5+
import net.minecraft.gametest.framework.GameTestHelper
6+
import net.minecraft.network.chat.Component
7+
import java.util.function.Predicate
8+
9+
fun GameTestHelper.chatContains(filter: Predicate<Component>) = Minecraft.getInstance().gui.chat.allMessages.any { filter.test(it.content) }
10+
11+
fun GameTestHelper.assertChatContains(component: Component) {
12+
if (!chatContains { it == component }) {
13+
throw GameTestAssertException("Expected chat to contain $component")
14+
}
15+
}
16+
17+
fun GameTestHelper.assertChatContains(filter: Predicate<Component>) {
18+
if (!chatContains(filter)) {
19+
throw GameTestAssertException("Expected chat to contain message matching filter")
20+
}
21+
}
22+
23+
fun GameTestHelper.assertChatNotContains(component: Component) {
24+
if (chatContains { it == component }) {
25+
throw GameTestAssertException("Expected chat to not contain $component")
26+
}
27+
}
28+
29+
fun GameTestHelper.assertChatNotContains(filter: Predicate<Component>) {
30+
if (chatContains(filter)) {
31+
throw GameTestAssertException("Expected chat to not contain message matching filter")
32+
}
33+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package de.srendi.advancedperipherals.test
2+
3+
import dan200.computercraft.gametest.api.*
4+
import dan200.computercraft.gametest.api.Timeouts.SECOND
5+
import dan200.computercraft.gametest.core.ClientTestEvents
6+
import net.minecraft.ChatFormatting
7+
import net.minecraft.client.Minecraft
8+
import net.minecraft.client.gui.components.toasts.SystemToast
9+
import net.minecraft.core.BlockPos
10+
import net.minecraft.gametest.framework.GameTestHelper
11+
import net.minecraft.network.chat.ClickEvent
12+
import net.minecraft.network.chat.Component
13+
import java.util.function.BiPredicate
14+
15+
@GameTestHolder
16+
class ChatBoxTest {
17+
18+
private fun getFormattedMessage(bracketColor: String, openBracket: Char, closeBracket: Char, prefix: String, message: String): Component {
19+
return Component.literal("$bracketColor$openBracket§r")
20+
.append(prefix)
21+
.append("$bracketColor$closeBracket§r ")
22+
.append(
23+
Component.literal("Red ").withStyle(ChatFormatting.RED)
24+
.append(Component.literal("Bold ").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.WHITE))
25+
.append(Component.literal("Click ").withStyle(ChatFormatting.UNDERLINE).withStyle(ChatFormatting.WHITE)
26+
.withStyle { it.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, "https://advancedperipherals.madefor.cc/")) })
27+
.append(Component.literal(message).withStyle(ChatFormatting.ITALIC).withStyle(ChatFormatting.AQUA))
28+
)
29+
}
30+
31+
private fun getFormattedToast(bracketColor: ChatFormatting?, openBracket: Char, closeBracket: Char, prefix: String, message: String): List<Component> {
32+
val prefixComponents = if (bracketColor != null) {
33+
listOf(
34+
Component.literal("$openBracket").withStyle(bracketColor),
35+
Component.literal(prefix),
36+
Component.literal("$closeBracket").withStyle(bracketColor),
37+
Component.literal(" ")
38+
)
39+
} else {
40+
listOf(
41+
Component.literal("$openBracket$prefix$closeBracket ")
42+
)
43+
}
44+
45+
return prefixComponents + listOf(
46+
Component.literal("Red ").withStyle(ChatFormatting.RED),
47+
Component.literal("Bold ").withStyle(ChatFormatting.WHITE).withStyle(ChatFormatting.BOLD),
48+
Component.literal("Click ").withStyle(ChatFormatting.WHITE).withStyle(ChatFormatting.UNDERLINE)
49+
.withStyle { it.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, "https://advancedperipherals.madefor.cc/")) },
50+
Component.literal(message).withStyle(ChatFormatting.AQUA).withStyle(ChatFormatting.ITALIC)
51+
)
52+
}
53+
54+
private fun containsToast(filter: BiPredicate<Component, List<Component>>): Boolean {
55+
return ClientTestEvents.toasts.filterIsInstance<SystemToast>().any {
56+
val sink = ComponentFormattedCharSink()
57+
it.messageLines.forEachIndexed { index, line ->
58+
line.accept(sink)
59+
if (index < it.messageLines.size - 1) {
60+
sink.accept(0, sink.currentStyle!!, ' '.code)
61+
}
62+
}
63+
64+
filter.test(it.title, sink.getComponents())
65+
}
66+
}
67+
68+
private fun assertContainsToast(title: Component, components: List<Component>) {
69+
if (!containsToast { toastTitle, toastComponents -> toastTitle == title && toastComponents == components }) {
70+
throw AssertionError("Toast with title $title and components $components not found")
71+
}
72+
}
73+
74+
private fun assertNotContainsToast(title: Component, components: List<Component>) {
75+
if (containsToast { toastTitle, toastComponents -> toastTitle == title && toastComponents == components }) {
76+
throw AssertionError("Toast with title $title and components $components found")
77+
}
78+
}
79+
80+
private fun assertNotContainsToast(filter: BiPredicate<Component, List<Component>>) {
81+
if (containsToast(filter)) {
82+
throw AssertionError("Toast matching filter found")
83+
}
84+
}
85+
86+
@ClientGameTest(timeoutTicks = 60 * SECOND)
87+
fun chatBox(context: GameTestHelper) = context.sequence {
88+
thenExecute { context.positionAt(BlockPos(2, 6, 2), 90f) }
89+
thenOnClient {
90+
Minecraft.getInstance().gui.chat.clearMessages(false)
91+
ClientTestEvents.toasts.clear()
92+
}
93+
thenComputerOk()
94+
thenOnClient {
95+
// sendMessage
96+
context.assertChatContains(Component.literal("[§r").append("AP").append("]§r ").append("Default message"))
97+
context.assertChatContains(Component.literal("[§r").append("GameTest").append("]§r ").append("Message with prefix"))
98+
context.assertChatContains(Component.literal("<§r").append("GameTest").append(">§r ").append("Message with brackets"))
99+
context.assertChatContains(Component.literal("§a<§r").append("GameTest").append("§a>§r ").append("Message with bracket color"))
100+
context.assertChatNotContains(Component.literal("§a<§r").append("GameTest").append("§a>§r ").append("Message with short range"))
101+
context.assertChatNotContains { it.toString().contains("Message with invalid brackets") }
102+
103+
// sendMessageToPlayer
104+
context.assertChatContains(Component.literal("[§r").append("AP").append("]§r ").append("Default message to player"))
105+
context.assertChatContains(Component.literal("[§r").append("GameTest").append("]§r ").append("Message with prefix to player"))
106+
context.assertChatContains(Component.literal("<§r").append("GameTest").append(">§r ").append("Message with brackets to player"))
107+
context.assertChatContains(Component.literal("§a<§r").append("GameTest").append("§a>§r ").append("Message with bracket color to player"))
108+
context.assertChatNotContains(Component.literal("§a<§r").append("GameTest").append("§a>§r ").append("Message with short range to player"))
109+
context.assertChatNotContains { it.toString().contains("Message with invalid brackets to player") }
110+
context.assertChatNotContains(Component.literal("[§r").append("AP").append("]§r ").append("Default message to invalid player"))
111+
112+
// sendFormattedMessage
113+
context.assertChatContains(getFormattedMessage("", '[', ']', "AP", "Default formatted message"))
114+
context.assertChatContains(getFormattedMessage("", '[', ']', "GameTest", "Formatted message with prefix"))
115+
context.assertChatContains(getFormattedMessage("", '<', '>', "GameTest", "Formatted message with brackets"))
116+
context.assertChatContains(getFormattedMessage("§a", '<', '>', "GameTest", "Formatted message with bracket color"))
117+
context.assertChatNotContains(getFormattedMessage("§a", '<', '>', "GameTest", "Formatted message with short range"))
118+
context.assertChatNotContains { it.toString().contains("Formatted message with invalid brackets") }
119+
120+
// sendFormattedMessageToPlayer
121+
context.assertChatContains(getFormattedMessage("", '[', ']', "AP", "Default formatted message to player"))
122+
context.assertChatContains(getFormattedMessage("", '[', ']', "GameTest", "Formatted message with prefix to player"))
123+
context.assertChatContains(getFormattedMessage("", '<', '>', "GameTest", "Formatted message with brackets to player"))
124+
context.assertChatContains(getFormattedMessage("§a", '<', '>', "GameTest", "Formatted message with bracket color to player"))
125+
context.assertChatNotContains(getFormattedMessage("§a", '<', '>', "GameTest", "Formatted message with short range to player"))
126+
context.assertChatNotContains { it.toString().contains("Formatted message with invalid brackets to player") }
127+
context.assertChatNotContains(getFormattedMessage("", '[', ']', "AP", "Default formatted message to invalid player"))
128+
129+
// sendToastToPlayer
130+
val defaultToastTitle = Component.literal("Toast Title")
131+
assertContainsToast(defaultToastTitle, listOf(Component.literal("[AP] Default toast to player")))
132+
assertContainsToast(defaultToastTitle, listOf(Component.literal("[GameTest] Toast with prefix to player")))
133+
assertContainsToast(defaultToastTitle, listOf(Component.literal("<GameTest> Toast with brackets to player")))
134+
assertContainsToast(defaultToastTitle, listOf(
135+
Component.literal("<").withStyle(ChatFormatting.GREEN),
136+
Component.literal("GameTest"),
137+
Component.literal(">").withStyle(ChatFormatting.GREEN),
138+
Component.literal(" Toast with bracket color to player")
139+
))
140+
assertNotContainsToast(defaultToastTitle, listOf(
141+
Component.literal("<").withStyle(ChatFormatting.GREEN),
142+
Component.literal("GameTest"),
143+
Component.literal(">").withStyle(ChatFormatting.GREEN),
144+
Component.literal(" Toast with short range to player")
145+
))
146+
assertNotContainsToast { title, components -> title == defaultToastTitle && components.any { it.toString().contains("Toast with invalid brackets to player") } }
147+
assertNotContainsToast(defaultToastTitle, listOf(Component.literal("[AP] Default toast to invalid player")))
148+
149+
// sendFormattedToastToPlayer
150+
val formattedToastTitle = Component.literal("Formatted Toast Title").withStyle(ChatFormatting.DARK_PURPLE)
151+
assertContainsToast(formattedToastTitle, getFormattedToast(null, '[', ']', "AP", "Default formatted toast to player"))
152+
assertContainsToast(formattedToastTitle, getFormattedToast(null, '[', ']', "GameTest", "Formatted toast with prefix to player"))
153+
assertContainsToast(formattedToastTitle, getFormattedToast(null, '<', '>', "GameTest", "Formatted toast with brackets to player"))
154+
assertContainsToast(formattedToastTitle, getFormattedToast(ChatFormatting.GREEN, '<', '>', "GameTest", "Formatted toast with bracket color to player"))
155+
assertNotContainsToast(formattedToastTitle, getFormattedToast(ChatFormatting.GREEN, '<', '>', "GameTest", "Formatted toast with short range to player"))
156+
assertNotContainsToast { title, components -> title == formattedToastTitle && components.any { it.toString().contains("Formatted toast with invalid brackets to player") } }
157+
assertNotContainsToast(formattedToastTitle, getFormattedToast(null, '[', ']', "AP", "Default formatted toast to invalid player"))
158+
}
159+
}
160+
161+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package de.srendi.advancedperipherals.test
2+
3+
import net.minecraft.network.chat.Component
4+
import net.minecraft.network.chat.Style
5+
import net.minecraft.util.FormattedCharSink
6+
7+
class ComponentFormattedCharSink : FormattedCharSink {
8+
var currentStyle: Style? = null;
9+
private var currentText: String = "";
10+
private val components = mutableListOf<Component>();
11+
12+
override fun accept(pPositionInCurrentSequence: Int, pStyle: Style, pCodePoint: Int): Boolean {
13+
if (currentStyle?.equals(pStyle) == false) {
14+
if (currentText.isNotEmpty()) {
15+
components.add(Component.literal(currentText).withStyle(simplifyStyle(currentStyle!!)))
16+
currentText = ""
17+
}
18+
}
19+
20+
currentStyle = pStyle
21+
currentText += String(Character.toChars(pCodePoint))
22+
23+
return true
24+
}
25+
26+
fun getComponents(): List<Component>{
27+
if (currentText.isNotEmpty()) {
28+
components.add(Component.literal(currentText).withStyle(simplifyStyle(currentStyle!!)))
29+
currentText = ""
30+
}
31+
32+
return components
33+
}
34+
35+
private fun simplifyStyle(style: Style): Style {
36+
return style
37+
.withBold(if (style.isBold) true else null)
38+
.withItalic(if (style.isItalic) true else null)
39+
.withUnderlined(if (style.isUnderlined) true else null)
40+
.withStrikethrough(if (style.isStrikethrough) true else null)
41+
.withObfuscated(if (style.isObfuscated) true else null)
42+
}
43+
44+
}

src/testMod/resources/META-INF/accesstransformer.cfg

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ public net.minecraft.gametest.framework.GameTestHelper m_177448_()Lnet/minecraft
44
public net.minecraft.gametest.framework.GameTestHelper f_127595_ # testInfo
55

66
public net.minecraft.gametest.framework.GameTestSequence f_127774_ # parent
7-
public net.minecraft.gametest.framework.MultipleTestTracker f_127798_ # tests
7+
public net.minecraft.gametest.framework.MultipleTestTracker f_127798_ # tests
8+
9+
public net.minecraft.client.gui.components.ChatComponent f_93760_ # allMessages
10+
public net.minecraft.client.gui.components.toasts.SystemToast f_94821_ # title
11+
public net.minecraft.client.gui.components.toasts.SystemToast f_94822_ # messageLines

0 commit comments

Comments
 (0)