diff options
-rw-r--r-- | plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt | 15 | ||||
-rw-r--r-- | plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt | 96 |
2 files changed, 100 insertions, 11 deletions
diff --git a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt index 43ffff85..48e44f5f 100644 --- a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt @@ -105,14 +105,23 @@ open class DokkaLocationProvider( companion object { internal val reservedFilenames = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out") + //Taken from: https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names + internal val reservedCharacters = setOf('|', '>', '<', '*', ':', '"', '?', '%') internal fun identifierToFilename(name: String): String { if (name.isEmpty()) return "--root--" - val escaped = name.replace("[<>]".toRegex(), "-") - val lowercase = escaped.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() } - return if (lowercase in reservedFilenames) "--$lowercase--" else lowercase + return sanitizeFileName(name, reservedFilenames, reservedCharacters) } } } +internal fun sanitizeFileName(name: String, reservedFileNames: Set<String>, reservedCharacters: Set<Char>): String { + val lowercase = name.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() } + val withoutReservedFileNames = if (lowercase in reservedFileNames) "--$lowercase--" else lowercase + return reservedCharacters.fold(withoutReservedFileNames){ + acc, character -> + if(character in acc) acc.replace(character.toString(), "[${character.toInt()}]") + else acc + } +} diff --git a/plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt index 89161080..6426c0e1 100644 --- a/plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt +++ b/plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt @@ -2,21 +2,26 @@ package locationProvider import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider +import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest import org.junit.jupiter.api.Assertions.assertNotEquals import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import kotlin.test.assertEquals +import kotlin.test.assertNotNull -class DefaultLocationProviderTest: AbstractCoreTest() { - @Test - fun `#644 same directory for module and package`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } +class DefaultLocationProviderTest : AbstractCoreTest() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") } } + } + @Test + fun `#644 same directory for module and package`() { testInline( """ |/src/main/kotlin/basic/Test.kt @@ -38,4 +43,79 @@ class DefaultLocationProviderTest: AbstractCoreTest() { } } } + + @Test + fun `should escape illegal pipe character in file name`() { + /* + Currently even kotlin doesn't escape pipe characters in file names so it is impossible to have a + class named || on windows + */ + testInline( + """ + |/src/main/kotlin/basic/Test.kt + | + |class Test { + | fun `||`() { } + |} + """.trimMargin(), + configuration + ) { + var context: DokkaContext? = null + pluginsSetupStage = { + context = it + } + + pagesGenerationStage = { module -> + val lp = DokkaLocationProvider(module, context!!) + val functionWithPipes = module.dfs { it.name == "||" } + assertNotNull(functionWithPipes, "Failed to find a page for a function named ||") + assertEquals(lp.resolve(functionWithPipes), "[root]/-test/[124][124].html") + } + } + } + + @ParameterizedTest + @MethodSource + fun runEscapeTestForCharacter(data: TestData) { + testInline( + """ + |/src/main/kotlin/basic/Test.kt + | + |class Test { + | fun `${data.tested}`() { } + |} + """.trimMargin(), + configuration + ) { + var context: DokkaContext? = null + pluginsSetupStage = { + context = it + } + + pagesGenerationStage = { module -> + val lp = DokkaLocationProvider(module, context!!) + val functionWithPipes = module.dfs { it.name == "${data.tested}" } + assertNotNull(functionWithPipes, "Failed to find a page for a function named ${data.tested}") + assertEquals(lp.resolve(functionWithPipes), "[root]/-test/${data.expectedReplacement}.html") + } + } + } + + data class TestData(val tested: Char, val expectedReplacement: String) + + companion object TestDataSources { + @JvmStatic + fun runEscapeTestForCharacter(): List<TestData> = listOf( + '|' to "[124]", + '>' to "[62]", + '<' to "[60]", + '*' to "[42]", + ':' to "[58]", + '"' to "[34]", + '?' to "[63]", + '%' to "[37]" + ).map { + TestData(it.first, it.second) + } + } } |