From dd3b4d8f8b55be827f7a25778ef19703c134c8c3 Mon Sep 17 00:00:00 2001 From: Simon Vergauwen Date: Wed, 11 Aug 2021 20:08:58 +0200 Subject: [PATCH] Propagate Ank changes to Dokka, and parallelise processor --- build.gradle.kts | 6 +- sample/build.gradle.kts | 3 +- sample/src/main/kotlin/example.kt | 16 +-- settings.gradle.kts | 2 +- .../com/github/nomisrev/ank/AnkDokkaPlugin.kt | 68 +++------ .../kotlin/com/github/nomisrev/ank/debug.kt | 45 ++++++ .../kotlin/com/github/nomisrev/ank/dokka.kt | 130 ++++++++++++++++++ .../kotlin/com/github/nomisrev/ank/domain.kt | 47 ++++++- .../kotlin/com/github/nomisrev/ank/engine.kt | 56 +++++++- .../kotlin/com/github/nomisrev/ank/predef.kt | 17 ++- .../kotlin/com/github/nomisrev/ank/testing.kt | 27 ++++ .../kotlin/template/MyAwesomePluginTest.kt | 7 +- 12 files changed, 347 insertions(+), 77 deletions(-) create mode 100644 src/main/kotlin/com/github/nomisrev/ank/debug.kt create mode 100644 src/main/kotlin/com/github/nomisrev/ank/dokka.kt create mode 100644 src/main/kotlin/com/github/nomisrev/ank/testing.kt diff --git a/build.gradle.kts b/build.gradle.kts index f8f1000..45463d5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "com.nomisrev" -version = "1.0-SNAPSHOT" +version = "1.1-SNAPSHOT" repositories { mavenCentral() @@ -22,6 +22,10 @@ dependencies { compileOnly("org.jetbrains.dokka:dokka-core:$dokkaVersion") implementation("org.jetbrains.dokka:dokka-base:$dokkaVersion") + implementation("io.arrow-kt:arrow-core:0.13.2") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1") + implementation("io.arrow-kt:arrow-fx-coroutines:0.13.2") + runtimeOnly(kotlin("reflect")) runtimeOnly(kotlin("script-runtime")) runtimeOnly("org.jetbrains.kotlin:kotlin-script-runtime:1.5.0") { isTransitive = false } diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index cc3934e..05f31ad 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -20,7 +20,8 @@ dependencies { implementation("io.arrow-kt:arrow-fx-coroutines:0.13.2") implementation("io.kotest:kotest-property:4.6.1") implementation("io.kotest:kotest-assertions-core:4.6.1") - dokkaHtmlPlugin("org.example:awesome-dokka-plugin:1.0-SNAPSHOT") + + dokkaHtmlPlugin("com.nomisrev:ank-dokka-plugin:1.1-SNAPSHOT") } tasks.withType().configureEach { diff --git a/sample/src/main/kotlin/example.kt b/sample/src/main/kotlin/example.kt index 96dd8f7..b9219ce 100644 --- a/sample/src/main/kotlin/example.kt +++ b/sample/src/main/kotlin/example.kt @@ -28,23 +28,11 @@ fun exampleException(): Unit = Unit */ fun exampleReplace(): Unit = Unit -///** -// * This function is documented, and Ank can correctly handle the exception -// * -// * ```java:ank -// * public String hello(String name) { -// * return "Hello " + name + "!" -// * } -// * -// * hello("Λrrow") -// * ``` -// */ -//fun exampleJava(): Unit = Unit - /** * This function is documented, and I have access to my classpath from docs + * Since it's silent, it doesn't add `// Either.Right(1)` as output. * - * ```kotlin:ank + * ```kotlin:ank:silent * import arrow.core.Either * * Either.Right(1) diff --git a/settings.gradle.kts b/settings.gradle.kts index bf8583b..3d0461d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,2 +1,2 @@ -rootProject.name = "awesome-dokka-plugin" +rootProject.name = "ank-dokka-plugin" include("sample") diff --git a/src/main/kotlin/com/github/nomisrev/ank/AnkDokkaPlugin.kt b/src/main/kotlin/com/github/nomisrev/ank/AnkDokkaPlugin.kt index d1a75d7..d782f8a 100644 --- a/src/main/kotlin/com/github/nomisrev/ank/AnkDokkaPlugin.kt +++ b/src/main/kotlin/com/github/nomisrev/ank/AnkDokkaPlugin.kt @@ -1,10 +1,10 @@ package com.github.nomisrev.ank +import arrow.fx.coroutines.parTraverse +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.model.doc.Br -import org.jetbrains.dokka.model.doc.CodeBlock -import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer @@ -17,63 +17,29 @@ class AnkDokkaPlugin : DokkaPlugin() { } /** - * => Every module can have its own classpath (ONLY WORKS FOR JVM due to ScriptEngine) - * => Every KDoc belongs to a File which has a path, can we figure this out? - * => This doesn't replace KotlinX Knit, so don't support MARKDOWN for now. * => Properly log errors through DokkaLogger */ private class AnkCompiler(private val ctx: DokkaContext) : PreMergeDocumentableTransformer { - // Could we optimise with `suspend` and running in parallel? - override fun invoke(modules: List): List = - modules.also { - ctx.logger.error(colored(ANSI_PURPLE, "Λnk Dokka Plugin is running")) + override fun invoke(modules: List): List = runBlocking(Dispatchers.Default) { + ctx.logger.warn(colored(ANSI_PURPLE, "Λnk Dokka Plugin is running")) - val classpath = modules.flatMap { it.sourceSets.firstOrNull()?.classpath.orEmpty() } + // Shall we process all packages in parallel?? + modules.parTraverse { module -> + val classpath = module.sourceSets.firstOrNull()?.classpath.orEmpty() .map { it.toURI().toURL().toString() } - Engine.compileCode(it.allSnippets(), classpath) - } -} - - + Engine.createEngine(classpath).use { engine -> + val packages = + module.packages.parTraverseCodeBlock(module) { module, `package`, documentable, node, wrapper, codeBlock -> + Snippet(module, `package`, documentable, node, wrapper, codeBlock)?.let { + Engine.compileCode(engine, it) + }?.toCodeBlock() + } -private fun CodeBlock.asStringOrNull(): String? = - buildString { - children.forEach { tag -> - when (tag) { - is Text -> append(tag.body) - Br -> append("\n") - else -> return null + module.copy(packages = packages) } - } - } -private fun List.allSnippets(): List = - flatMap { module -> - module.packages.flatMap { `package` -> - `package`.children.flatMap { documentable -> - documentable.documentation.values.flatMap { node -> - node.children.flatMap { tagWrapper -> - tagWrapper.children.mapNotNull { docTag -> - (docTag as? CodeBlock)?.let { code -> - code.params["lang"]?.let { fence -> - fenceRegexStart.matchEntire(fence)?.let { match -> - docTag.asStringOrNull()?.let { rawCode -> - val lang = match.groupValues[1].trim() - val path = """ - Module: ${module.name} - package: ${`package`.packageName} - KDoc of: $documentable - """.trimIndent() - Snippet(path, fence, lang, rawCode) - } - } - } - } - } - } - } - } } } +} diff --git a/src/main/kotlin/com/github/nomisrev/ank/debug.kt b/src/main/kotlin/com/github/nomisrev/ank/debug.kt new file mode 100644 index 0000000..07c9f67 --- /dev/null +++ b/src/main/kotlin/com/github/nomisrev/ank/debug.kt @@ -0,0 +1,45 @@ +package com.github.nomisrev.ank + +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.model.doc.CodeBlock + +// Get all codeBlocks => write some dump version +private fun List.allCodeBlocks(): List = + flatMap { module -> + module.packages.flatMap { `package` -> + `package`.children.flatMap { documentable -> + documentable.documentation.values.flatMap { node -> + node.children.flatMap { tagWrapper -> + tagWrapper.children.mapNotNull { docTag -> + (docTag as? CodeBlock) + } + } + } + } + } + } + +private fun List.allSnippets(): List = + flatMap { module -> + module.packages.flatMap { `package` -> + `package`.children.flatMap { documentable -> + documentable.documentation.values.flatMap { node -> + node.children.flatMap { wrapper -> + wrapper.children.mapNotNull { docTag -> + (docTag as? CodeBlock)?.let { code -> + code.params["lang"]?.let { fence -> + fenceRegexStart.matchEntire(fence)?.let { match -> + docTag.asStringOrNull()?.let { rawCode -> + val lang = match.groupValues[1].trim() + val path = SnippetPath(module, `package`, documentable, node, wrapper, code) + Snippet(path, fence, lang, rawCode) + } + } + } + } + } + } + } + } + } + } diff --git a/src/main/kotlin/com/github/nomisrev/ank/dokka.kt b/src/main/kotlin/com/github/nomisrev/ank/dokka.kt new file mode 100644 index 0000000..8f60036 --- /dev/null +++ b/src/main/kotlin/com/github/nomisrev/ank/dokka.kt @@ -0,0 +1,130 @@ +package com.github.nomisrev.ank + +import arrow.fx.coroutines.parTraverse +import org.jetbrains.dokka.model.DAnnotation +import org.jetbrains.dokka.model.DClass +import org.jetbrains.dokka.model.DClasslike +import org.jetbrains.dokka.model.DEnum +import org.jetbrains.dokka.model.DInterface +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.model.DObject +import org.jetbrains.dokka.model.DPackage +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.SourceSetDependent +import org.jetbrains.dokka.model.doc.Author +import org.jetbrains.dokka.model.doc.CodeBlock +import org.jetbrains.dokka.model.doc.CodeInline +import org.jetbrains.dokka.model.doc.Constructor +import org.jetbrains.dokka.model.doc.CustomDocTag +import org.jetbrains.dokka.model.doc.CustomTagWrapper +import org.jetbrains.dokka.model.doc.Deprecated +import org.jetbrains.dokka.model.doc.Description +import org.jetbrains.dokka.model.doc.DocTag +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Param +import org.jetbrains.dokka.model.doc.Property +import org.jetbrains.dokka.model.doc.Receiver +import org.jetbrains.dokka.model.doc.Return +import org.jetbrains.dokka.model.doc.Sample +import org.jetbrains.dokka.model.doc.See +import org.jetbrains.dokka.model.doc.Since +import org.jetbrains.dokka.model.doc.Suppress +import org.jetbrains.dokka.model.doc.TagWrapper +import org.jetbrains.dokka.model.doc.Throws +import org.jetbrains.dokka.model.doc.Version + + +/** + * This methods gives you all info available for a detected `CodeBlock`. + * It **does not** filter the list, but if you return a non-null value it will + * update the existing value in the [DModule] + */ +suspend fun List.parTraverseCodeBlock( + dModule: DModule, + transform: (module: DModule, `package`: DPackage, documentable: Documentable, node: DocumentationNode, wrapper: TagWrapper, CodeBlock) -> CodeBlock? +): List = parTraverse { `package` -> + `package`.copy( + properties = `package`.properties.map { property -> + property.copy(documentation = property.documentation.process(dModule, `package`, property, transform)) + }, + functions = `package`.functions.map { function -> + function.copy(documentation = function.documentation.process(dModule, `package`, function, transform)) + }, + classlikes = `package`.classlikes.map { it.process(dModule, `package`, transform) }, + typealiases = `package`.typealiases.map { typeAlias -> + typeAlias.copy(documentation = typeAlias.documentation.process(dModule, `package`, typeAlias, transform)) + } + ) +} + +private fun DClasslike.process( + module: DModule, + `package`: DPackage, + transform: (module: DModule, `package`: DPackage, documentable: Documentable, node: DocumentationNode, wrapper: TagWrapper, CodeBlock) -> CodeBlock? +): DClasslike = + when (this) { + is DClass -> copy(documentation = documentation.process(module, `package`, this, transform)) + is DEnum -> copy(documentation = documentation.process(module, `package`, this, transform)) + is DInterface -> copy(documentation = documentation.process(module, `package`, this, transform)) + is DObject -> copy(documentation = documentation.process(module, `package`, this, transform)) + is DAnnotation -> copy(documentation = documentation.process(module, `package`, this, transform)) + } + +private fun SourceSetDependent.process( + module: DModule, + `package`: DPackage, + documentable: Documentable, + transform: (module: DModule, `package`: DPackage, documentable: Documentable, node: DocumentationNode, wrapper: TagWrapper, code: CodeBlock) -> CodeBlock? +): SourceSetDependent = + mapValues { (_, node) -> node.process(module, `package`, documentable, node, transform) } + +private fun DocumentationNode.process( + module: DModule, + `package`: DPackage, + documentable: Documentable, + node: DocumentationNode, + transform: (module: DModule, `package`: DPackage, documentable: Documentable, node: DocumentationNode, wrapper: TagWrapper, code: CodeBlock) -> CodeBlock? +): DocumentationNode = + copy(children = children.map { + when (it) { + is See -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Param -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Throws -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Sample -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Property -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is CustomTagWrapper -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Description -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Author -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Version -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Since -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Return -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Receiver -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Constructor -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Deprecated -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + is Suppress -> it.copy(root = it.root.process(module, `package`, documentable, node, it, transform)) + } + }) + +private fun DocTag.process( + module: DModule, + `package`: DPackage, + documentable: Documentable, + node: DocumentationNode, + wrapper: TagWrapper, + transform: (module: DModule, `package`: DPackage, documentable: Documentable, node: DocumentationNode, wrapper: TagWrapper, code: CodeBlock) -> CodeBlock? +): DocTag = + when (this) { + is CodeBlock -> transform(module, `package`, documentable, node, wrapper, this) ?: this + is CodeInline -> this + is CustomDocTag -> copy(children = children.map { + it.process( + module, + `package`, + documentable, + node, + wrapper, + transform + ) + }) + else -> this + } diff --git a/src/main/kotlin/com/github/nomisrev/ank/domain.kt b/src/main/kotlin/com/github/nomisrev/ank/domain.kt index e5cdcbd..49d416a 100644 --- a/src/main/kotlin/com/github/nomisrev/ank/domain.kt +++ b/src/main/kotlin/com/github/nomisrev/ank/domain.kt @@ -1,5 +1,14 @@ package com.github.nomisrev.ank +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.model.DPackage +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.doc.Br +import org.jetbrains.dokka.model.doc.CodeBlock +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.TagWrapper +import org.jetbrains.dokka.model.doc.Text + public const val AnkBlock: String = ":ank" public const val AnkSilentBlock: String = ":ank:silent" public const val AnkReplaceBlock: String = ":ank:replace" @@ -10,8 +19,17 @@ public const val AnkPlaygroundExtension: String = ":ank:playground:extension" public val fenceRegexStart = "(.*)$AnkBlock.*".toRegex() +data class SnippetPath( + val module: DModule, + val `package`: DPackage, + val documentable: Documentable, + val node: DocumentationNode, + val tagWrapper: TagWrapper, + val codeBlock: CodeBlock +) + public data class Snippet( - val path: String, + val path: SnippetPath, val fence: String, val lang: String, val code: String, @@ -21,4 +39,29 @@ public data class Snippet( val isReplace: Boolean = fence.contains(AnkReplaceBlock) val isFail: Boolean = fence.contains(AnkFailBlock) val isPlayground: Boolean = fence.contains(AnkPlayground) -} \ No newline at end of file + + fun toCodeBlock(): CodeBlock = + CodeBlock( + code.lines().flatMap { listOf(Text(it), Br) }, + mapOf("lang" to fence) + ) +} + +fun Snippet( + module: DModule, + `package`: DPackage, + documentable: Documentable, + node: DocumentationNode, + wrapper: TagWrapper, + code: CodeBlock +): Snippet? = + code.params["lang"]?.let { fence -> + fenceRegexStart.matchEntire(fence)?.let { match -> + code.asStringOrNull()?.let { rawCode -> + val lang = match.groupValues[1].trim() + val path = + SnippetPath(module, `package`, documentable, node, wrapper, code) + Snippet(path, fence, lang, rawCode) + } + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/github/nomisrev/ank/engine.kt b/src/main/kotlin/com/github/nomisrev/ank/engine.kt index c6a502f..49c0632 100644 --- a/src/main/kotlin/com/github/nomisrev/ank/engine.kt +++ b/src/main/kotlin/com/github/nomisrev/ank/engine.kt @@ -1,5 +1,8 @@ package com.github.nomisrev.ank +import arrow.fx.coroutines.Resource +import arrow.fx.coroutines.release +import arrow.fx.coroutines.resource import java.io.PrintWriter import java.io.StringWriter import java.net.URL @@ -9,6 +12,7 @@ import java.util.concurrent.ConcurrentMap import javax.script.ScriptContext import javax.script.ScriptEngine import javax.script.ScriptEngineManager +import org.jetbrains.dokka.plugability.DokkaContext /** * Engine which can compile & evaluate code. @@ -22,10 +26,41 @@ object Engine { // Maintains a cache with the classpath as KEY, and a set of ScriptEngines for that classpath (Java & Kotlin). private val engineCache: ConcurrentMap, Map> = ConcurrentHashMap() + private val singleEngineCache: ConcurrentMap, ScriptEngine> = ConcurrentHashMap() // Mappings between fence lang, and extension names private val extensionMappings: Map = mapOf("java" to "java", "kotlin" to "kts") + public fun compileCode(engine: ScriptEngine, snip: Snippet): Snippet { + val result = try { + engine.eval(snip.code) + } catch (e: Exception) { + if (snip.isFail) { + val sw = StringWriter() + val pw = PrintWriter(sw) + e.printStackTrace(pw) + snip.copy(result = sw.toString()) + } else { + throw CompilationException( + snip, e, msg = "\n" + """ + | ${snip.path} + | + |``` + |${snip.code} + |``` + |${colored(ANSI_RED, e.localizedMessage)} + """.trimMargin() + ) + } + } + + return when { + result == null || snip.isSilent || snip.isFail -> snip + snip.isReplace -> snip.copy(code = result.toString()) + else -> snip.copy(code = snip.code + "\n" + "// ${result.toString().replace("\n", "\n// ")}") + } + } + /** * Compiles a [List] of [Snippet]s for a given `classpath`. * The classpath should be formatted as `file://...` with the URI to the local jars. @@ -44,7 +79,7 @@ object Engine { val originalClassLoader = Thread.currentThread().contextClassLoader Thread.currentThread().contextClassLoader = classLoader - val engineCache = getEngineCache(snippets, classLoader, compilerArgs) + val engineCache = createEngine(snippets, classLoader, compilerArgs) // run each snipped and handle its result return snippets.mapIndexed { i, snip -> @@ -96,8 +131,25 @@ object Engine { } } + fun createEngine(classpath: List): Resource = + (resource { + val classLoader = classLoader(classpath) + + // We need to get the original contextClassLoader which Dokka uses to run, and store it + // Then we need to set the contextClassloader so the engine can correctly define the compilation classpath + // We do this **whilst** decoupling the classLoader for the ScriptEngine with the classLoader of Dokka. + // This is because Dokka shadows some of the Kotlin compiler dependencies, having them mixed results in incorrect state + val originalClassLoader = Thread.currentThread().contextClassLoader + Thread.currentThread().contextClassLoader = classLoader + val manager = ScriptEngineManager(classLoader) + Pair(manager.getEngineByExtension("kts"), originalClassLoader) + } release { (_, originalClassLoader) -> + // When we're done, we reset back to the original classLoader + Thread.currentThread().contextClassLoader = originalClassLoader + }).map { (engine, _) -> engine } + // Gets the engine cache for a given classpath - private fun getEngineCache( + private fun createEngine( snippets: List, classLoader: URLClassLoader?, compilerArgs: List diff --git a/src/main/kotlin/com/github/nomisrev/ank/predef.kt b/src/main/kotlin/com/github/nomisrev/ank/predef.kt index 5d03885..05c77db 100644 --- a/src/main/kotlin/com/github/nomisrev/ank/predef.kt +++ b/src/main/kotlin/com/github/nomisrev/ank/predef.kt @@ -1,5 +1,9 @@ package com.github.nomisrev.ank +import org.jetbrains.dokka.model.doc.Br +import org.jetbrains.dokka.model.doc.CodeBlock +import org.jetbrains.dokka.model.doc.Text + public const val ANSI_RESET: String = "\u001B[0m" public const val ANSI_BLACK: String = "\u001B[30m" public const val ANSI_RED: String = "\u001B[31m" @@ -22,4 +26,15 @@ public val AnkHeader: String = | +#+ +#+ +#+ +#+#+# +#+ +#+ | #+# #+# #+# #+#+# #+# #+# | ### ### ### #### ### ### - """.trimMargin() \ No newline at end of file + """.trimMargin() + +fun CodeBlock.asStringOrNull(): String? = + buildString { + children.forEach { tag -> + when (tag) { + is Text -> append(tag.body) + Br -> append("\n") + else -> return null + } + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/github/nomisrev/ank/testing.kt b/src/main/kotlin/com/github/nomisrev/ank/testing.kt new file mode 100644 index 0000000..87293a6 --- /dev/null +++ b/src/main/kotlin/com/github/nomisrev/ank/testing.kt @@ -0,0 +1,27 @@ +package com.github.nomisrev.ank + +import arrow.core.Either +import kotlinx.coroutines.runBlocking + +/** + * If a user writes a snippet that returns `TestResult`, + * then we can collect all `TestResult` and create a test-report from it. + * + * Alternatively, we could perhaps automatically pick up tests if they're written under + * + * ```kotlin:ank:test + * + * And then we could **ignore** the output, but inject a `TestCollector` into the `script` of the user, + * and collect it's output at the end `collector.result()`. + * + * This way the user can write multiple tests in a single snippet. + */ +data class TestResult(val result: Either, val name: String) + +operator fun String.invoke(f: suspend () -> Any?): TestResult = + test(this, f) + +fun test(name: String, f: suspend () -> Any?): TestResult = + runBlocking { + TestResult(Either.catch { f() }, name) + } \ No newline at end of file diff --git a/src/test/kotlin/template/MyAwesomePluginTest.kt b/src/test/kotlin/template/MyAwesomePluginTest.kt index 41c9c44..8ff7ea4 100644 --- a/src/test/kotlin/template/MyAwesomePluginTest.kt +++ b/src/test/kotlin/template/MyAwesomePluginTest.kt @@ -1,6 +1,5 @@ package template -import junit.framework.Assert.assertNotNull import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.Test @@ -17,7 +16,7 @@ class MyAwesomePluginTest : BaseAbstractTest() { fun `my awesome plugin should find packages and classes`() { testInline( """ - |/src/main/kotlin/sample/Test.kt + |/src/main/kotlin/sample/testing.kt |package sample |/** * has KDoc @@ -39,8 +38,8 @@ class MyAwesomePluginTest : BaseAbstractTest() { val testedPackage = module.packages.find { it.name == "sample" } val testedClass = testedPackage?.classlikes?.find { it.name == "TestingIsEasy" } - assertNotNull(testedPackage) - assertNotNull(testedClass) + requireNotNull(testedPackage) + requireNotNull(testedClass) } } }