@@ -104,14 +104,51 @@ void testRoundTripDoesNotProduceLiteralTags() {
104104 }
105105
106106 private static void collectBoldText (Component component , boolean inheritedBold , StringBuilder out ) {
107- TextDecoration .State state = component .decoration (TextDecoration .BOLD );
107+ collectDecoratedText (component , TextDecoration .BOLD , inheritedBold , out );
108+ }
109+
110+ private static void collectDecoratedText (Component component , TextDecoration deco , boolean inherited , StringBuilder out ) {
111+ TextDecoration .State state = component .decoration (deco );
108112 boolean effective = state == TextDecoration .State .TRUE
109- || (state == TextDecoration .State .NOT_SET && inheritedBold );
113+ || (state == TextDecoration .State .NOT_SET && inherited );
110114 if (component instanceof net .kyori .adventure .text .TextComponent text && effective ) {
111115 out .append (text .content ());
112116 }
113117 for (Component child : component .children ()) {
114- collectBoldText (child , effective , out );
118+ collectDecoratedText (child , deco , effective , out );
119+ }
120+ }
121+
122+ /**
123+ * The same round-trip leak that affected bold also affected italic, underlined, strikethrough,
124+ * and obfuscated, because Adventure's LegacyComponentSerializer never emits §r when *any*
125+ * decoration transitions from on to off across siblings. Verify each decoration in turn.
126+ */
127+ @ Test
128+ void testRoundTripNoDecorationLeaksAcrossSiblings () {
129+ TextDecoration [] decos = {
130+ TextDecoration .BOLD ,
131+ TextDecoration .ITALIC ,
132+ TextDecoration .UNDERLINED ,
133+ TextDecoration .STRIKETHROUGH ,
134+ TextDecoration .OBFUSCATED
135+ };
136+ String [] tags = {"bold" , "italic" , "underlined" , "strikethrough" , "obfuscated" };
137+
138+ for (int i = 0 ; i < decos .length ; i ++) {
139+ String tag = tags [i ];
140+ String original = "<green>before </green><red><" + tag + ">MID </" + tag + "></red><green>after</green>" ;
141+ Component comp = Util .parseMiniMessage (original );
142+ String legacy = Util .componentToLegacy (comp );
143+ Component finalComp = Util .parseMiniMessageOrLegacy (legacy );
144+
145+ String plainText = PlainTextComponentSerializer .plainText ().serialize (finalComp );
146+ assertEquals ("before MID after" , plainText , "plain text mismatch for " + tag );
147+
148+ StringBuilder decoratedText = new StringBuilder ();
149+ collectDecoratedText (finalComp , decos [i ], false , decoratedText );
150+ assertEquals ("MID " , decoratedText .toString (),
151+ tag + " should only apply to 'MID ', not leak into following segments" );
115152 }
116153 }
117154
0 commit comments