diff --git a/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java b/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java index 483330ce3..01e963206 100644 --- a/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java +++ b/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java @@ -173,6 +173,7 @@ private TextReplacementRenderer() { } if (children != null) { children.add(replaced); + first = false; } } } else { diff --git a/api/src/test/java/net/kyori/adventure/text/TextAssertions.java b/api/src/test/java/net/kyori/adventure/text/TextAssertions.java index d7071db64..0a8ee1255 100644 --- a/api/src/test/java/net/kyori/adventure/text/TextAssertions.java +++ b/api/src/test/java/net/kyori/adventure/text/TextAssertions.java @@ -26,10 +26,12 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import net.kyori.examination.string.MultiLineStringExaminer; +import org.junit.jupiter.api.Assertions; public final class TextAssertions { private static final Set DECORATIONS = ImmutableSet.copyOf(TextDecoration.values()); @@ -51,8 +53,24 @@ public static void assertDecorations(final Style style, final Set decorations, final TextDecoration.State state) { if (!decorations.isEmpty()) { for (final TextDecoration decoration : decorations) { - assertEquals(state, style.decoration(decoration)); + Assertions.assertEquals(state, style.decoration(decoration)); } } } + + public static void assertEquals(final Component expected, final Component actual) { + Assertions.assertEquals(prettyPrint(expected), prettyPrint(actual)); + } + + public static void assertEquals(final Component expected, final Component actual, final String message) { + Assertions.assertEquals(prettyPrint(expected), prettyPrint(actual), message); + } + + public static void assertEquals(final Component expected, final Component actual, final Supplier message) { + Assertions.assertEquals(prettyPrint(expected), prettyPrint(actual), message); + } + + private static final String prettyPrint(final Component component) { + return component.examine(MultiLineStringExaminer.simpleEscaping()).collect(Collectors.joining("\n")); + } } diff --git a/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java b/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java index f39cc94e5..b22676747 100644 --- a/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java +++ b/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java @@ -258,4 +258,25 @@ void testFullMatchReplaceWithStyle() { final Component expected = Component.text("world", NamedTextColor.RED, TextDecoration.BOLD); assertEquals(expected, replaced); } + + // https://github.com/KyoriPowered/adventure/issues/618 + @Test + void testDoesNotDuplicateComponents() { + final Component original = Component.text() + .content("%n") + .append(Component.text("duplicate me"), Component.text("b%n")) + .build(); + + final Component replaced = original.replaceText(c -> c.matchLiteral("%n").replacement("*")); + + final Component expected = Component.text() + .content("*") + .append( + Component.text("duplicate me"), + Component.text("b").append(Component.text("*")) + ) + .build(); + + TextAssertions.assertEquals(expected, replaced); + } }