diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/ReplaceRomanNumerals.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/ReplaceRomanNumerals.kt index 8f59492a758f..469637e8c9b0 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/ReplaceRomanNumerals.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/ReplaceRomanNumerals.kt @@ -46,7 +46,7 @@ object ReplaceRomanNumerals { "§o§a✔ §.* (?[IVXLCDM]+)§r", "§5§o§7Purchase §a.* (?[IVXLCDM]+) §7.*", "§5§o(?:§7)§.(?[IVXLCDM]+).*", - ".*Heart of the Mountain (?[IVXLCDM]+) ?.*" + ".*Heart of the Mountain (?[IVXLCDM]+) ?.*", ) /** @@ -96,17 +96,20 @@ object ReplaceRomanNumerals { if (allowedPatterns.matches(this)) replace() else this } - fun replaceLine(line: String): String { - if (!isEnabled()) return line + fun replaceLine(line: String, checkIfEnabled: Boolean = true): String { + if (checkIfEnabled && !isEnabled()) return line return cachedStrings.getOrPut(line) { line.replace() } } - private fun String.replace() = splitRegex.findAll(this).map { it.value }.joinToString("") { - it.takeIf { it.isValidRomanNumeral() && it.removeFormatting().romanToDecimal() != 2000 }?.coloredRomanToDecimal() ?: it - } + private fun String.replace() = splitRegex + .findAll(this) + .map { it.value } + .joinToString("") { part -> + part.takeIf { it.isValidRomanNumeral() }?.coloredRomanToDecimal() ?: part + } private fun String.removeFormatting() = removeColor().replace(",", "") diff --git a/src/test/java/at/hannibal2/skyhanni/test/ReplaceRomanNumeralsTest.kt b/src/test/java/at/hannibal2/skyhanni/test/ReplaceRomanNumeralsTest.kt new file mode 100644 index 000000000000..4ff530f67de1 --- /dev/null +++ b/src/test/java/at/hannibal2/skyhanni/test/ReplaceRomanNumeralsTest.kt @@ -0,0 +1,58 @@ +package at.hannibal2.skyhanni.test + +import at.hannibal2.skyhanni.features.misc.ReplaceRomanNumerals +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class ReplaceRomanNumeralsTest { + + @Test + fun `Regular words shouldn't be modified`() { + Assertions.assertEquals("hello", "hello".transformLine()) + } + + @Test + fun `'I' should never be converted`() { + Assertions.assertEquals("I", "I".transformLine()) + } + + @Test + fun `Single Roman numeral should be converted`() { + Assertions.assertEquals("5", "V".transformLine()) + } + + @Test + fun `Multiple Roman numerals separated by spaces should be converted`() { + Assertions.assertEquals("5 10 world", "V X world".transformLine()) + } + + @Test + fun `Roman numeral next to punctuation should be converted`() { + Assertions.assertEquals("5!", "V!".transformLine()) + Assertions.assertEquals("hello 14 you?", "hello XIV you?".transformLine()) + } + + @Test + fun `Mixed with color codes should be converted`() { + Assertions.assertEquals("§c5!", "§cV!".transformLine()) + Assertions.assertEquals("hello 2 is this 5 you?", "hello II is this V you?".transformLine()) + } + + @Test + fun `Invalid Roman numeral sequences are left unchanged`() { + Assertions.assertEquals("IIII", "IIII".transformLine()) + } + + @Test + fun `Sequences with punctuation and color codes interspersed should be converted`() { + Assertions.assertEquals("§d5 world", "§dV world".transformLine()) + Assertions.assertEquals("hello 10 and then 1 more", "hello X and then I more".transformLine()) + } + + @Test + fun `Mixed complexity should be converted`() { + Assertions.assertEquals("Today 2023 was great!", "Today MMXXIII was great!".transformLine()) + } + + private fun String.transformLine(): String = ReplaceRomanNumerals.replaceLine(this, checkIfEnabled = false) +} diff --git a/versions/1.8.9/detekt/baseline.xml b/versions/1.8.9/detekt/baseline.xml index e9400d2a9066..8aaa504bc449 100644 --- a/versions/1.8.9/detekt/baseline.xml +++ b/versions/1.8.9/detekt/baseline.xml @@ -55,6 +55,7 @@ MemberNameEqualsClassName:FirstMinionTier.kt$FirstMinionTier$fun firstMinionTier( otherItems: Map<NEUInternalName, Int>, minions: MutableMap<String, NEUInternalName>, tierOneMinions: MutableList<NEUInternalName>, tierOneMinionsDone: MutableSet<NEUInternalName>, ) MemberNameEqualsClassName:LastServers.kt$LastServers$private val lastServers = mutableMapOf<String, SimpleTimeMark>() MemberNameEqualsClassName:PestSpawn.kt$PestSpawn$private fun pestSpawn(amount: Int, plotNames: List<String>, unknownAmount: Boolean) + MemberNameEqualsClassName:ReplaceRomanNumerals.kt$ReplaceRomanNumerals$fun replaceRomanNumerals(string: String): String MemberNameEqualsClassName:Shimmy.kt$Shimmy.Companion$private fun shimmy(source: Any?, fieldName: String): Any? MemberNameEqualsClassName:TestBingo.kt$TestBingo$var testBingo = false MemberNameEqualsClassName:Text.kt$Text$fun text(text: String, init: IChatComponent.() -> Unit = {}) @@ -72,7 +73,6 @@ NoNameShadowing:Renderable.kt$Renderable.Companion.<no name provided>$posY NoNameShadowing:Renderable.kt$Renderable.Companion.<no name provided>${ it.value?.contains(textInput.textBox, ignoreCase = true) ?: true } NoNameShadowing:RenderableUtils.kt$RenderableUtils${ it != null } - NoNameShadowing:ReplaceRomanNumerals.kt$ReplaceRomanNumerals${ it.isValidRomanNumeral() && it.removeFormatting().romanToDecimal() != 2000 } NoNameShadowing:RepoManager.kt$RepoManager${ unsuccessfulConstants.add(it) } NoNameShadowing:RepoPatternManager.kt$RepoPatternManager${ it == '.' } NoNameShadowing:Shimmy.kt$Shimmy.Companion$source @@ -231,10 +231,6 @@ RepoPatternRegexTest:ScoreboardPattern.kt$ScoreboardPattern$by dungeonSb.pattern( "keys", "Keys: §.■ §.[✗✓] §.■ §a.x", ) RepoPatternRegexTest:ScoreboardPattern.kt$ScoreboardPattern$by dungeonSb.pattern( "teammates", "(?:§.)*(?<classAbbv>\\[\\w]) (?:§.)*(?<username>\\w{2,16}) (?:(?:§.)*(?<classLevel>\\[Lvl?(?<level>[\\w,.]+)?]?)|(?:§.)*(?<health>[\\w,.]+)(?:§.)*.?)", ) RepoPatternRegexTest:ShowMotesNpcSellPrice.kt$ShowMotesNpcSellPrice$by RepoPattern.pattern( "rift.everywhere.burger", ".*(?:§\\w)+You have (?:§\\w)+(?<amount>\\d) Grubber Stacks.*" ) - RepoPatternRegexTest:SkillAPI.kt$SkillAPI$by patternGroup.pattern( "skill", "\\+(?<gained>[\\d.,]+) (?<skillName>\\w+) \\((?<current>[\\d.,]+)/(?<needed>[\\d.,]+)\\)", ) - RepoPatternRegexTest:SkillAPI.kt$SkillAPI$by patternGroup.pattern( "skill.multiplier", "\\+(?<gained>[\\d.,]+) (?<skillName>.+) \\((?<current>[\\d.,]+)/(?<needed>[\\d,.]+[kmb])\\)", ) - RepoPatternRegexTest:SkillAPI.kt$SkillAPI$by patternGroup.pattern( "skill.percent", "\\+(?<gained>[\\d.,]+) (?<skillName>.+) \\((?<progress>[\\d.]+)%\\)", ) - RepoPatternRegexTest:SkillAPI.kt$SkillAPI$by patternGroup.pattern( "skill.tab", " (?<type>\\w+)(?: (?<level>\\d+))?: §r§a(?<progress>[0-9.]+)%", ) RepoPatternRegexTest:SkillAPI.kt$SkillAPI$by patternGroup.pattern( "skill.tab.max", " (?<type>\\w+) (?<level>\\d+): §r§c§lMAX", ) RepoPatternRegexTest:SkillAPI.kt$SkillAPI$by patternGroup.pattern( "skill.tab.nopercent", " §r§a(?<type>\\w+)(?: (?<level>\\d+))?: §r§e(?<current>[0-9,.]+)§r§6/§r§e(?<needed>[0-9kmb]+)", ) RepoPatternRegexTest:SkillExperience.kt$SkillExperience$by patternGroup.pattern( "actionbar", ".*§3\\+.* (?<skill>.*) \\((?<overflow>.*)/(?<needed>.*)\\).*" )