From 70dc7f56bc6e1c08d094378d920426359e9b44e1 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Tue, 23 Feb 2021 23:54:32 -0800 Subject: [PATCH] clues: Fix three step cryptic clue getLocations NPE Prior to this commit, ThreeStepCrypticClue simply returned a concatenation of the active step locations without filtering the mapped locations in any way. This could lead to NPEs in the plugin as some cryptic clues have null locations for steps which have no specific location or have a variable location. This commit addresses this by making CrypticClue's location field `@Nullable`, filtering null locations from ThreeStepCrypticClue's getLocations stream, and by adding a test to ensure ThreeStepCrypticClue's getLocations method cannot yield any null entries in its return value. --- .../plugins/cluescrolls/clues/CrypticClue.java | 3 ++- .../cluescrolls/clues/ThreeStepCrypticClue.java | 2 ++ .../clues/ThreeStepCrypticClueTest.java | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index 3cde11fec9..5f9a99deee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -330,6 +330,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc private final String text; private final String npc; private final int objectId; + @Nullable private final WorldPoint location; private final String solution; @Nullable @@ -371,7 +372,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc this(text, npc, objectId, location, solution, null); } - private CrypticClue(String text, String npc, int objectId, WorldPoint location, String solution, @Nullable String questionText) + private CrypticClue(String text, String npc, int objectId, @Nullable WorldPoint location, String solution, @Nullable String questionText) { this.text = text; this.npc = npc; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClue.java index 52c78d94c8..9672d4b351 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClue.java @@ -30,6 +30,7 @@ import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import lombok.Getter; import lombok.RequiredArgsConstructor; import net.runelite.api.InventoryID; @@ -167,6 +168,7 @@ public class ThreeStepCrypticClue extends ClueScroll implements TextClueScroll, return clueSteps.stream() .filter(s -> !s.getValue()) .map(s -> s.getKey().getLocation()) + .filter(Objects::nonNull) .toArray(WorldPoint[]::new); } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java index a3ca74a577..f9ed47a555 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java @@ -24,6 +24,10 @@ */ package net.runelite.client.plugins.cluescrolls.clues; +import com.google.common.base.Joiner; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.util.Text; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import org.junit.Test; @@ -34,4 +38,17 @@ public class ThreeStepCrypticClueTest { assertNull(ThreeStepCrypticClue.forText("", "")); } + + @Test + public void nonNullLocations() + { + final String clueText = Joiner.on("

").join(CrypticClue.CLUES.stream().map(CrypticClue::getText).toArray()); + final ThreeStepCrypticClue clue = ThreeStepCrypticClue.forText(Text.sanitizeMultilineText(clueText).toLowerCase(), clueText); + + assertNotNull(clue); + for (final WorldPoint location : clue.getLocations()) + { + assertNotNull(location); + } + } }