aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/test/kotlin/model
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/base/src/test/kotlin/model')
-rw-r--r--plugins/base/src/test/kotlin/model/ClassesTest.kt533
-rw-r--r--plugins/base/src/test/kotlin/model/CommentTest.kt332
-rw-r--r--plugins/base/src/test/kotlin/model/FunctionsTest.kt396
-rw-r--r--plugins/base/src/test/kotlin/model/InheritorsTest.kt95
-rw-r--r--plugins/base/src/test/kotlin/model/JavaTest.kt346
-rw-r--r--plugins/base/src/test/kotlin/model/PackagesTest.kt134
-rw-r--r--plugins/base/src/test/kotlin/model/PropertyTest.kt265
7 files changed, 2101 insertions, 0 deletions
diff --git a/plugins/base/src/test/kotlin/model/ClassesTest.kt b/plugins/base/src/test/kotlin/model/ClassesTest.kt
new file mode 100644
index 00000000..5dc8812e
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/ClassesTest.kt
@@ -0,0 +1,533 @@
+package model
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.links.sureClassNames
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.KotlinModifier.*
+import org.junit.jupiter.api.Assertions.assertNull
+import org.junit.jupiter.api.Test
+import utils.AbstractModelTest
+import utils.assertNotNull
+import utils.name
+import utils.supers
+
+
+class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "classes") {
+
+ @Test
+ fun emptyClass() {
+ inlineModelTest(
+ """
+ |class Klass {}"""
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ children counts 4
+ }
+ }
+ }
+
+ @Test
+ fun emptyObject() {
+ inlineModelTest(
+ """
+ |object Obj {}
+ """
+ ) {
+ with((this / "classes" / "Obj").cast<DObject>()) {
+ name equals "Obj"
+ children counts 3
+ }
+ }
+ }
+
+ @Test
+ fun classWithConstructor() {
+ inlineModelTest(
+ """
+ |class Klass(name: String)
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ children counts 4
+
+ with(constructors.firstOrNull().assertNotNull("Constructor")) {
+ visibility.values allEquals KotlinVisibility.Public
+ parameters counts 1
+ with(parameters.firstOrNull().assertNotNull("Constructor parameter")) {
+ name equals "name"
+ type.name equals "String"
+ }
+ }
+
+ }
+ }
+ }
+
+ @Test
+ fun classWithFunction() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | fun fn() {}
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ children counts 5
+
+ with((this / "fn").cast<DFunction>()) {
+ type.name equals "Unit"
+ parameters counts 0
+ visibility.values allEquals KotlinVisibility.Public
+ }
+ }
+ }
+ }
+
+ @Test
+ fun classWithProperty() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | val name: String = ""
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ children counts 5
+
+ with((this / "name").cast<DProperty>()) {
+ name equals "name"
+ // TODO property name
+ }
+ }
+ }
+ }
+
+ @Test
+ fun classWithCompanionObject() {
+ inlineModelTest(
+ """
+ |class Klass() {
+ | companion object {
+ | val x = 1
+ | fun foo() {}
+ | }
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ children counts 5
+
+ with((this / "Companion").cast<DObject>()) {
+ name equals "Companion"
+ children counts 5
+
+ with((this / "x").cast<DProperty>()) {
+ name equals "x"
+ }
+
+ with((this / "foo").cast<DFunction>()) {
+ name equals "foo"
+ parameters counts 0
+ type.name equals "Unit"
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun dataClass() {
+ inlineModelTest(
+ """
+ |data class Klass() {}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ visibility.values allEquals KotlinVisibility.Public
+ with(extra[AdditionalModifiers]!!.content.entries.single().value.assertNotNull("Extras")) {
+ this counts 1
+ first() equals ExtraModifiers.KotlinOnlyModifiers.Data
+ }
+ }
+ }
+ }
+
+ @Test
+ fun sealedClass() {
+ inlineModelTest(
+ """
+ |sealed class Klass() {}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ modifier.values.forEach { it equals Sealed }
+ }
+ }
+ }
+
+ @Test
+ fun annotatedClassWithAnnotationParameters() {
+ inlineModelTest(
+ """
+ |@Deprecated("should no longer be used") class Foo() {}
+ """
+ ) {
+ with((this / "classes" / "Foo").cast<DClass>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(first()) {
+ dri.classNames equals "Deprecated"
+ params.entries counts 1
+ (params["message"].assertNotNull("message") as StringValue).value equals "\"should no longer be used\""
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun notOpenClass() {
+ inlineModelTest(
+ """
+ |open class C() {
+ | open fun f() {}
+ |}
+ |
+ |class D() : C() {
+ | override fun f() {}
+ |}
+ """
+ ) {
+ val C = (this / "classes" / "C").cast<DClass>()
+ val D = (this / "classes" / "D").cast<DClass>()
+
+ with(C) {
+ modifier.values.forEach { it equals Open }
+ with((this / "f").cast<DFunction>()) {
+ modifier.values.forEach { it equals Open }
+ }
+ }
+ with(D) {
+ modifier.values.forEach { it equals Final }
+ with((this / "f").cast<DFunction>()) {
+ modifier.values.forEach { it equals Open }
+ }
+ D.supertypes.flatMap { it.component2() }.firstOrNull()?.dri equals C.dri
+ }
+ }
+ }
+
+ @Test
+ fun indirectOverride() {
+ inlineModelTest(
+ """
+ |abstract class C() {
+ | abstract fun foo()
+ |}
+ |
+ |abstract class D(): C()
+ |
+ |class E(): D() {
+ | override fun foo() {}
+ |}
+ """
+ ) {
+ val C = (this / "classes" / "C").cast<DClass>()
+ val D = (this / "classes" / "D").cast<DClass>()
+ val E = (this / "classes" / "E").cast<DClass>()
+
+ with(C) {
+ modifier.values.forEach { it equals Abstract }
+ ((this / "foo").cast<DFunction>()).modifier.values.forEach { it equals Abstract }
+ }
+
+ with(D) {
+ modifier.values.forEach { it equals Abstract }
+ }
+
+ with(E) {
+ modifier.values.forEach { it equals Final }
+
+ }
+ D.supers.single().dri equals C.dri
+ E.supers.single().dri equals D.dri
+ }
+ }
+
+ @Test
+ fun innerClass() {
+ inlineModelTest(
+ """
+ |class C {
+ | inner class D {}
+ |}
+ """
+ ) {
+ with((this / "classes" / "C").cast<DClass>()) {
+
+ with((this / "D").cast<DClass>()) {
+ with(extra[AdditionalModifiers]!!.content.entries.single().value.assertNotNull("AdditionalModifiers")) {
+ this counts 1
+ first() equals ExtraModifiers.KotlinOnlyModifiers.Inner
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun companionObjectExtension() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | companion object Default {}
+ |}
+ |
+ |/**
+ | * The def
+ | */
+ |val Klass.Default.x: Int get() = 1
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+
+ with((this / "Default").cast<DObject>()) {
+ name equals "Default"
+ // TODO extensions
+ }
+ }
+ }
+ }
+
+// @Test fun companionObjectExtension() {
+// checkSourceExistsAndVerifyModel("testdata/classes/companionObjectExtension.kt", defaultModelConfig) { model ->
+// val pkg = model.members.single()
+// val cls = pkg.members.single { it.name == "Foo" }
+// val extensions = cls.extensions.filter { it.kind == NodeKind.CompanionObjectProperty }
+// assertEquals(1, extensions.size)
+// }
+// }
+
+ @Test
+ fun secondaryConstructor() {
+ inlineModelTest(
+ """
+ |class C() {
+ | /** This is a secondary constructor. */
+ | constructor(s: String): this() {}
+ |}
+ """
+ ) {
+ with((this / "classes" / "C").cast<DClass>()) {
+ name equals "C"
+ constructors counts 2
+
+ constructors.map { it.name } allEquals "<init>"
+
+ with(constructors.find { it.parameters.isNullOrEmpty() } notNull "C()") {
+ parameters counts 0
+ }
+
+ with(constructors.find { it.parameters.isNotEmpty() } notNull "C(String)") {
+ parameters counts 1
+ with(parameters.firstOrNull() notNull "Constructor parameter") {
+ name equals "s"
+ type.name equals "String"
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun sinceKotlin() {
+ inlineModelTest(
+ """
+ |/**
+ | * Useful
+ | */
+ |@SinceKotlin("1.1")
+ |class C
+ """
+ ) {
+ with((this / "classes" / "C").cast<DClass>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(first()) {
+ dri.classNames equals "SinceKotlin"
+ params.entries counts 1
+ (params["version"].assertNotNull("version") as StringValue).value equals "\"1.1\""
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun privateCompanionObject() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | private companion object {
+ | fun fn() {}
+ | val a = 0
+ | }
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ assertNull(companion, "Companion should not be visible by default")
+ }
+ }
+ }
+
+ @Test
+ fun companionObject() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | companion object {
+ | fun fn() {}
+ | val a = 0
+ | }
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<DClass>()) {
+ name equals "Klass"
+ with((this / "Companion").cast<DObject>()) {
+ name equals "Companion"
+ visibility.values allEquals KotlinVisibility.Public
+
+ with((this / "fn").cast<DFunction>()) {
+ name equals "fn"
+ parameters counts 0
+ receiver equals null
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun annotatedClass() {
+ inlineModelTest(
+ """@Suppress("abc") class Foo() {}"""
+ ) {
+ with((this / "classes" / "Foo").cast<DClass>()) {
+ with(extra[Annotations]?.content?.values?.firstOrNull()?.firstOrNull().assertNotNull("annotations")) {
+ dri.toString() equals "kotlin/Suppress///PointingToDeclaration/"
+ (params["names"].assertNotNull("param") as ArrayValue).value equals listOf(StringValue("\"abc\""))
+ }
+ }
+ }
+ }
+
+ @Test
+ fun javaAnnotationClass() {
+ inlineModelTest(
+ """
+ |import java.lang.annotation.Retention
+ |import java.lang.annotation.RetentionPolicy
+ |
+ |@Retention(RetentionPolicy.SOURCE)
+ |public annotation class throws()
+ """
+ ) {
+ with((this / "classes" / "throws").cast<DAnnotation>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(first()) {
+ dri.classNames equals "Retention"
+ params["value"].assertNotNull("value") equals EnumValue(
+ "RetentionPolicy.SOURCE",
+ DRI("java.lang.annotation", "RetentionPolicy.SOURCE")
+ )
+ }
+ }
+ }
+ }
+ }
+
+ @Test fun genericAnnotationClass() {
+ inlineModelTest(
+ """annotation class Foo<A,B,C,D:Number>() {}"""
+ ) {
+ with((this / "classes" / "Foo").cast<DAnnotation>()){
+ generics.map { it.name to it.bounds.first().name } equals listOf("A" to "Any", "B" to "Any", "C" to "Any", "D" to "Number")
+ }
+ }
+ }
+
+ @Test fun nestedGenericClasses(){
+ inlineModelTest(
+ """
+ |class Outer<OUTER> {
+ | inner class Inner<INNER, T : OUTER> { }
+ |}
+ """.trimMargin()
+ ){
+ with((this / "classes" / "Outer").cast<DClass>()){
+ val inner = classlikes.single().cast<DClass>()
+ inner.generics.map { it.name to it.bounds.first().name } equals listOf("INNER" to "Any", "T" to "OUTER")
+ }
+ }
+ }
+
+ @Test fun allImplementedInterfaces() {
+ inlineModelTest(
+ """
+ | interface Highest { }
+ | open class HighestImpl: Highest { }
+ | interface Lower { }
+ | interface LowerImplInterface: Lower { }
+ | class Tested : HighestImpl(), LowerImplInterface { }
+ """.trimIndent()
+ ){
+ with((this / "classes" / "Tested").cast<DClass>()){
+ extra[ImplementedInterfaces]?.interfaces?.entries?.single()?.value?.map { it.sureClassNames }?.sorted() equals listOf("Highest", "Lower", "LowerImplInterface").sorted()
+ }
+ }
+ }
+
+ @Test fun multipleClassInheritance() {
+ inlineModelTest(
+ """
+ | open class A { }
+ | open class B: A() { }
+ | class Tested : B() { }
+ """.trimIndent()
+ ) {
+ with((this / "classes" / "Tested").cast<DClass>()) {
+ supertypes.entries.single().value.map { it.dri.sureClassNames }.single() equals "B"
+ }
+ }
+ }
+
+ @Test fun multipleClassInheritanceWithInterface(){
+ inlineModelTest(
+ """
+ | open class A { }
+ | open class B: A() { }
+ | interface X { }
+ | interface Y : X { }
+ | class Tested : B(), Y { }
+ """.trimIndent()
+ ){
+ with((this / "classes" / "Tested").cast<DClass>()) {
+ supertypes.entries.single().value.map { it.dri.sureClassNames to it.kind }.sortedBy { it.first } equals listOf("B" to KotlinClassKindTypes.CLASS, "Y" to KotlinClassKindTypes.INTERFACE)
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/model/CommentTest.kt b/plugins/base/src/test/kotlin/model/CommentTest.kt
new file mode 100644
index 00000000..c1da8ee0
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/CommentTest.kt
@@ -0,0 +1,332 @@
+package model
+
+import org.jetbrains.dokka.model.DProperty
+import org.jetbrains.dokka.model.doc.CustomTagWrapper
+import org.jetbrains.dokka.model.doc.Text
+import org.junit.jupiter.api.Test
+import utils.*
+
+class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comment") {
+
+ @Test
+ fun codeBlockComment() {
+ inlineModelTest(
+ """
+ |/**
+ | * ```brainfuck
+ | * ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
+ | * ```
+ | */
+ |val prop1 = ""
+ |
+ |
+ |/**
+ | * ```
+ | * a + b - c
+ | * ```
+ | */
+ |val prop2 = ""
+ """
+ ) {
+ with((this / "comment" / "prop1").cast<DProperty>()) {
+ name equals "prop1"
+ with(this.docs().firstOrNull()?.root.assertNotNull("Code")) {
+ (children.firstOrNull() as? Text)
+ ?.body equals "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
+
+ params["lang"] equals "brainfuck"
+ }
+ }
+ with((this / "comment" / "prop2").cast<DProperty>()) {
+ name equals "prop2"
+ comments() equals "a + b - c"
+ }
+ }
+ }
+
+ @Test
+ fun emptyDoc() {
+ inlineModelTest(
+ """
+ val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ name equals "property"
+ comments() equals ""
+ }
+ }
+ }
+
+ @Test
+ fun emptyDocButComment() {
+ inlineModelTest(
+ """
+ |/* comment */
+ |val property = "test"
+ |fun tst() = property
+ """
+ ) {
+ val p = this
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals ""
+ }
+ }
+ }
+
+ @Test
+ fun multilineDoc() {
+ inlineModelTest(
+ """
+ |/**
+ | * doc1
+ | *
+ | * doc2
+ | * doc3
+ | */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "doc1\ndoc2 doc3"
+ }
+ }
+ }
+
+ @Test
+ fun multilineDocWithComment() {
+ inlineModelTest(
+ """
+ |/**
+ | * doc1
+ | *
+ | * doc2
+ | * doc3
+ | */
+ |// comment
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "doc1\ndoc2 doc3"
+ }
+ }
+ }
+
+ @Test
+ fun oneLineDoc() {
+ inlineModelTest(
+ """
+ |/** doc */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "doc"
+ }
+ }
+ }
+
+ @Test
+ fun oneLineDocWithComment() {
+ inlineModelTest(
+ """
+ |/** doc */
+ |// comment
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "doc"
+ }
+ }
+ }
+
+ @Test
+ fun oneLineDocWithEmptyLine() {
+ inlineModelTest(
+ """
+ |/** doc */
+ |
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "doc"
+ }
+ }
+ }
+
+ @Test
+ fun emptySection() {
+ inlineModelTest(
+ """
+ |/**
+ | * Summary
+ | * @one
+ | */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "Summary\none: []"
+ docs().find { it is CustomTagWrapper && it.name == "one" }.let {
+ with(it.assertNotNull("'one' entry")) {
+ root.children counts 0
+ root.params.keys counts 0
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun quotes() {
+ inlineModelTest(
+ """
+ |/** it's "useful" */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals """it's "useful""""
+ }
+ }
+ }
+
+ @Test
+ fun section1() {
+ inlineModelTest(
+ """
+ |/**
+ | * Summary
+ | * @one section one
+ | */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "Summary\none: [section one]"
+ }
+ }
+ }
+
+
+ @Test
+ fun section2() {
+ inlineModelTest(
+ """
+ |/**
+ | * Summary
+ | * @one section one
+ | * @two section two
+ | */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "Summary\none: [section one]\ntwo: [section two]"
+ }
+ }
+ }
+
+ @Test
+ fun multilineSection() {
+ inlineModelTest(
+ """
+ |/**
+ | * Summary
+ | * @one
+ | * line one
+ | * line two
+ | */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ comments() equals "Summary\none: [line one line two]"
+ }
+ }
+ }
+
+// @Test todo
+ fun directive() {
+ inlineModelTest(
+ """
+ |/**
+ | * Summary
+ | *
+ | * @sample example1
+ | * @sample example2
+ | * @sample X.example3
+ | * @sample X.Y.example4
+ | */
+ |val property = "test"
+ |
+ |fun example1(node: String) = if (true) {
+ | println(property)
+ |}
+ |
+ |fun example2(node: String) {
+ | if (true) {
+ | println(property)
+ | }
+ |}
+ |
+ |class X {
+ | fun example3(node: String) {
+ | if (true) {
+ | println(property)
+ | }
+ | }
+ |
+ | class Y {
+ | fun example4(node: String) {
+ | if (true) {
+ | println(property)
+ | }
+ | }
+ | }
+ |}
+ """
+ ) {
+ with((this / "comment" / "property").cast<DProperty>()) {
+ this
+ }
+ }
+ }
+
+
+// @Test fun directive() {
+// checkSourceExistsAndVerifyModel("testdata/comments/directive.kt", defaultModelConfig) { model ->
+// with(model.members.single().members.first()) {
+// assertEquals("Summary", content.summary.toTestString())
+// with (content.description) {
+// assertEqualsIgnoringSeparators("""
+// |[code lang=kotlin]
+// |if (true) {
+// | println(property)
+// |}
+// |[/code]
+// |[code lang=kotlin]
+// |if (true) {
+// | println(property)
+// |}
+// |[/code]
+// |[code lang=kotlin]
+// |if (true) {
+// | println(property)
+// |}
+// |[/code]
+// |[code lang=kotlin]
+// |if (true) {
+// | println(property)
+// |}
+// |[/code]
+// |""".trimMargin(), toTestString())
+// }
+// }
+// }
+// }
+
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/model/FunctionsTest.kt b/plugins/base/src/test/kotlin/model/FunctionsTest.kt
new file mode 100644
index 00000000..c96e7df6
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/FunctionsTest.kt
@@ -0,0 +1,396 @@
+package model
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.*
+import org.junit.jupiter.api.Test
+import utils.AbstractModelTest
+import utils.assertNotNull
+import utils.comments
+import utils.name
+
+class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "function") {
+
+ @Test
+ fun function() {
+ inlineModelTest(
+ """
+ |/**
+ | * Function fn
+ | */
+ |fun fn() {}
+ """
+ ) {
+ with((this / "function" / "fn").cast<DFunction>()) {
+ name equals "fn"
+ type.name equals "Unit"
+ this.children.assertCount(0, "Function children: ")
+ }
+ }
+ }
+
+ @Test
+ fun overloads() {
+ inlineModelTest(
+ """
+ |/**
+ | * Function fn
+ | */
+ |fun fn() {}
+ | /**
+ | * Function fn(Int)
+ | */
+ |fun fn(i: Int) {}
+ """
+ ) {
+ with((this / "function").cast<DPackage>()) {
+ val fn1 = functions.find {
+ it.name == "fn" && it.parameters.isNullOrEmpty()
+ }.assertNotNull("fn()")
+ val fn2 = functions.find {
+ it.name == "fn" && it.parameters.isNotEmpty()
+ }.assertNotNull("fn(Int)")
+
+ with(fn1) {
+ name equals "fn"
+ parameters.assertCount(0)
+ }
+
+ with(fn2) {
+ name equals "fn"
+ parameters.assertCount(1)
+ parameters.first().type.name equals "Int"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun functionWithReceiver() {
+ inlineModelTest(
+ """
+ |/**
+ | * Function with receiver
+ | */
+ |fun String.fn() {}
+ |
+ |/**
+ | * Function with receiver
+ | */
+ |fun String.fn(x: Int) {}
+ """
+ ) {
+ with((this / "function").cast<DPackage>()) {
+ val fn1 = functions.find {
+ it.name == "fn" && it.parameters.isNullOrEmpty()
+ }.assertNotNull("fn()")
+ val fn2 = functions.find {
+ it.name == "fn" && it.parameters.count() == 1
+ }.assertNotNull("fn(Int)")
+
+ with(fn1) {
+ name equals "fn"
+ parameters counts 0
+ receiver.assertNotNull("fn() receiver")
+ }
+
+ with(fn2) {
+ name equals "fn"
+ parameters counts 1
+ receiver.assertNotNull("fn(Int) receiver")
+ parameters.first().type.name equals "Int"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun functionWithParams() {
+ inlineModelTest(
+ """
+ |/**
+ | * Multiline
+ | *
+ | * Function
+ | * Documentation
+ | */
+ |fun function(/** parameter */ x: Int) {
+ |}
+ """
+ ) {
+ with((this / "function" / "function").cast<DFunction>()) {
+ comments() equals "Multiline\nFunction Documentation"
+
+ name equals "function"
+ parameters counts 1
+ parameters.firstOrNull().assertNotNull("Parameter: ").also {
+ it.name equals "x"
+ it.type.name equals "Int"
+ it.comments() equals "parameter"
+ }
+
+ type.assertNotNull("Return type: ").name equals "Unit"
+ }
+ }
+ }
+
+ @Test
+ fun functionWithNotDocumentedAnnotation() {
+ inlineModelTest(
+ """
+ |@Suppress("FOO") fun f() {}
+ """
+ ) {
+ with((this / "function" / "f").cast<DFunction>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(first()) {
+ dri.classNames equals "Suppress"
+ params.entries counts 1
+ (params["names"].assertNotNull("param") as ArrayValue).value equals listOf(StringValue("\"FOO\""))
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun inlineFunction() {
+ inlineModelTest(
+ """
+ |inline fun f(a: () -> String) {}
+ """
+ ) {
+ with((this / "function" / "f").cast<DFunction>()) {
+ extra[AdditionalModifiers]!!.content.entries.single().value counts 1
+ extra[AdditionalModifiers]!!.content.entries.single().value exists ExtraModifiers.KotlinOnlyModifiers.Inline
+ }
+ }
+ }
+
+ @Test
+ fun suspendFunction() {
+ inlineModelTest(
+ """
+ |suspend fun f() {}
+ """
+ ) {
+ with((this / "function" / "f").cast<DFunction>()) {
+ extra[AdditionalModifiers]!!.content.entries.single().value counts 1
+ extra[AdditionalModifiers]!!.content.entries.single().value exists ExtraModifiers.KotlinOnlyModifiers.Suspend
+ }
+ }
+ }
+
+ @Test
+ fun suspendInlineFunctionOrder() {
+ inlineModelTest(
+ """
+ |suspend inline fun f(a: () -> String) {}
+ """
+ ) {
+ with((this / "function" / "f").cast<DFunction>()) {
+ extra[AdditionalModifiers]!!.content.entries.single().value counts 2
+ extra[AdditionalModifiers]!!.content.entries.single().value exists ExtraModifiers.KotlinOnlyModifiers.Suspend
+ extra[AdditionalModifiers]!!.content.entries.single().value exists ExtraModifiers.KotlinOnlyModifiers.Inline
+ }
+ }
+ }
+
+ @Test
+ fun inlineSuspendFunctionOrderChanged() {
+ inlineModelTest(
+ """
+ |inline suspend fun f(a: () -> String) {}
+ """
+ ) {
+ with((this / "function" / "f").cast<DFunction>()) {
+ with(extra[AdditionalModifiers]!!.content.entries.single().value.assertNotNull("AdditionalModifiers")) {
+ this counts 2
+ this exists ExtraModifiers.KotlinOnlyModifiers.Suspend
+ this exists ExtraModifiers.KotlinOnlyModifiers.Inline
+ }
+ }
+ }
+ }
+
+ @Test
+ fun functionWithAnnotatedParam() {
+ inlineModelTest(
+ """
+ |@Target(AnnotationTarget.VALUE_PARAMETER)
+ |@Retention(AnnotationRetention.SOURCE)
+ |@MustBeDocumented
+ |public annotation class Fancy
+ |
+ |fun function(@Fancy notInlined: () -> Unit) {}
+ """
+ ) {
+ with((this / "function" / "Fancy").cast<DAnnotation>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 3
+ with(map { it.dri.classNames to it }.toMap()) {
+ with(this["Target"].assertNotNull("Target")) {
+ (params["allowedTargets"].assertNotNull("allowedTargets") as ArrayValue).value equals listOf(
+ EnumValue(
+ "AnnotationTarget.VALUE_PARAMETER",
+ DRI("kotlin.annotation", "AnnotationTarget.VALUE_PARAMETER")
+ )
+ )
+ }
+ with(this["Retention"].assertNotNull("Retention")) {
+ (params["value"].assertNotNull("value") as EnumValue) equals EnumValue(
+ "AnnotationRetention.SOURCE",
+ DRI("kotlin.annotation", "AnnotationRetention.SOURCE")
+ )
+ }
+ this["MustBeDocumented"].assertNotNull("MustBeDocumented").params.entries counts 0
+ }
+ }
+
+ }
+ with((this / "function" / "function" / "notInlined").cast<DParameter>()) {
+ with(this.extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(first()) {
+ dri.classNames equals "Fancy"
+ params.entries counts 0
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun functionWithNoinlineParam() {
+ inlineModelTest(
+ """
+ |fun f(noinline notInlined: () -> Unit) {}
+ """
+ ) {
+ with((this / "function" / "f" / "notInlined").cast<DParameter>()) {
+ extra[AdditionalModifiers]!!.content.entries.single().value counts 1
+ extra[AdditionalModifiers]!!.content.entries.single().value exists ExtraModifiers.KotlinOnlyModifiers.NoInline
+ }
+ }
+ }
+
+ @Test
+ fun annotatedFunctionWithAnnotationParameters() {
+ inlineModelTest(
+ """
+ |@Target(AnnotationTarget.VALUE_PARAMETER)
+ |@Retention(AnnotationRetention.SOURCE)
+ |@MustBeDocumented
+ |public annotation class Fancy(val size: Int)
+ |
+ |@Fancy(1) fun f() {}
+ """
+ ) {
+ with((this / "function" / "Fancy").cast<DAnnotation>()) {
+ constructors counts 1
+ with(constructors.first()) {
+ parameters counts 1
+ with(parameters.first()) {
+ type.name equals "Int"
+ name equals "size"
+ }
+ }
+
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 3
+ with(map { it.dri.classNames to it }.toMap()) {
+ with(this["Target"].assertNotNull("Target")) {
+ (params["allowedTargets"].assertNotNull("allowedTargets") as ArrayValue).value equals listOf(
+ EnumValue(
+ "AnnotationTarget.VALUE_PARAMETER",
+ DRI("kotlin.annotation", "AnnotationTarget.VALUE_PARAMETER")
+ )
+ )
+ }
+ with(this["Retention"].assertNotNull("Retention")) {
+ (params["value"].assertNotNull("value") as EnumValue) equals EnumValue(
+ "AnnotationRetention.SOURCE",
+ DRI("kotlin.annotation", "AnnotationRetention.SOURCE")
+ )
+ }
+ this["MustBeDocumented"].assertNotNull("MustBeDocumented").params.entries counts 0
+ }
+ }
+
+ }
+ with((this / "function" / "f").cast<DFunction>()) {
+ with(this.extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(this.first()) {
+ dri.classNames equals "Fancy"
+ params.entries counts 1
+ (params["size"] as StringValue).value equals "1"
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun functionWithDefaultStringParameter() {
+ inlineModelTest(
+ """
+ |/src/main/kotlin/function/Test.kt
+ |package function
+ |fun f(x: String = "") {}
+ """
+ ) {
+ with((this / "function" / "f").cast<DFunction>()) {
+ parameters.forEach { p ->
+ p.name equals "x"
+ p.type.name.assertNotNull("Parameter type: ") equals "String"
+ p.extra[DefaultValue]?.value equals "\"\""
+ }
+ }
+ }
+ }
+
+ @Test
+ fun functionWithDefaultFloatParameter() {
+ inlineModelTest(
+ """
+ |/src/main/kotlin/function/Test.kt
+ |package function
+ |fun f(x: Float = 3.14f) {}
+ """
+ ) {
+ with((this / "function" / "f").cast<DFunction>()) {
+ parameters.forEach { p ->
+ p.name equals "x"
+ p.type.name.assertNotNull("Parameter type: ") equals "Float"
+ p.extra[DefaultValue]?.value equals "3.14f"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun sinceKotlin() {
+ inlineModelTest(
+ """
+ |/**
+ | * Quite useful [String]
+ | */
+ |@SinceKotlin("1.1")
+ |fun f(): String = "1.1 rulezz"
+ """
+ ) {
+ with((this / "function" / "f").cast<DFunction>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(first()) {
+ dri.classNames equals "SinceKotlin"
+ params.entries counts 1
+ (params["version"].assertNotNull("version") as StringValue).value equals "\"1.1\""
+ }
+ }
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/model/InheritorsTest.kt b/plugins/base/src/test/kotlin/model/InheritorsTest.kt
new file mode 100644
index 00000000..503cf50c
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/InheritorsTest.kt
@@ -0,0 +1,95 @@
+package model
+
+import org.jetbrains.dokka.CoreExtensions
+import org.jetbrains.dokka.Platform
+import org.jetbrains.dokka.base.transformers.documentables.InheritorsExtractorTransformer
+import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo
+import org.jetbrains.dokka.model.DInterface
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Disabled
+import org.junit.jupiter.api.Test
+import utils.AbstractModelTest
+import utils.assertNotNull
+
+class InheritorsTest : AbstractModelTest("/src/main/kotlin/inheritors/Test.kt", "inheritors") {
+
+ object InheritorsPlugin : DokkaPlugin() {
+ val inheritors by extending {
+ CoreExtensions.documentableTransformer with InheritorsExtractorTransformer()
+ }
+ }
+
+ @Disabled("reenable after fixing subtypes")
+ @Test
+ fun simple() {
+ inlineModelTest(
+ """|interface A{}
+ |class B() : A {}
+ """.trimMargin(),
+ pluginsOverrides = listOf(InheritorsPlugin)
+ ) {
+ with((this / "inheritors" / "A").cast<DInterface>()) {
+ val map = extra[InheritorsInfo].assertNotNull("InheritorsInfo").value
+ with(map.keys.also { it counts 1 }.find { it.analysisPlatform == Platform.jvm }.assertNotNull("jvm key").let { map[it]!! }
+ ) {
+ this counts 1
+ first().classNames equals "B"
+ }
+ }
+ }
+ }
+
+ @Disabled("reenable after fixing subtypes")
+ @Test
+ fun multiplatform() {
+ val configuration = dokkaConfiguration {
+ sourceSets {
+ sourceSet {
+ sourceRoots = listOf("common/src/", "jvm/src/")
+ analysisPlatform = "jvm"
+ }
+ sourceSet {
+ sourceRoots = listOf("common/src/", "js/src/")
+ analysisPlatform = "js"
+ }
+ }
+ }
+
+ testInline(
+ """
+ |/common/src/main/kotlin/inheritors/Test.kt
+ |package inheritors
+ |interface A{}
+ |/jvm/src/main/kotlin/inheritors/Test.kt
+ |package inheritors
+ |class B() : A {}
+ |/js/src/main/kotlin/inheritors/Test.kt
+ |package inheritors
+ |class B() : A {}
+ |class C() : A {}
+ """.trimMargin(),
+ configuration,
+ cleanupOutput = false,
+ pluginOverrides = listOf(InheritorsPlugin)
+ ) {
+ documentablesTransformationStage = { m ->
+ with((m / "inheritors" / "A").cast<DInterface>()) {
+ val map = extra[InheritorsInfo].assertNotNull("InheritorsInfo").value
+ with(map.keys.also { it counts 2 }) {
+ with(find { it.analysisPlatform == Platform.jvm }.assertNotNull("jvm key").let { map[it]!! }) {
+ this counts 1
+ first().classNames equals "B"
+ }
+ with(find { it.analysisPlatform == Platform.js }.assertNotNull("js key").let { map[it]!! }) {
+ this counts 2
+ val classes = listOf("B", "C")
+ assertTrue(all { classes.contains(it.classNames) }, "One of subclasses missing in js" )
+ }
+ }
+
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/base/src/test/kotlin/model/JavaTest.kt b/plugins/base/src/test/kotlin/model/JavaTest.kt
new file mode 100644
index 00000000..1f042304
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/JavaTest.kt
@@ -0,0 +1,346 @@
+package model
+
+import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.links.sureClassNames
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.doc.Param
+import org.jetbrains.dokka.model.doc.Text
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+import utils.AbstractModelTest
+import utils.assertNotNull
+import utils.name
+
+class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") {
+
+ @Test
+ fun function() {
+ inlineModelTest(
+ """
+ |class Test {
+ | /**
+ | * Summary for Function
+ | * @param name is String parameter
+ | * @param value is int parameter
+ | */
+ | public void fn(String name, int value) {}
+ |}
+ """
+ ) {
+ with((this / "java" / "Test").cast<DClass>()) {
+ name equals "Test"
+ children counts 1
+ with((this / "fn").cast<DFunction>()) {
+ name equals "fn"
+ val params = parameters.map { it.documentation.values.first().children.first() as Param }
+ params.mapNotNull { it.firstChildOfTypeOrNull<Text>()?.body } equals listOf("is String parameter", "is int parameter")
+ }
+ }
+ }
+ }
+
+ @Test fun allImplementedInterfacesInJava() {
+ inlineModelTest(
+ """
+ |interface Highest { }
+ |interface Lower extends Highest { }
+ |class Extendable { }
+ |class Tested extends Extendable implements Lower { }
+ """){
+ with((this / "java" / "Tested").cast<DClass>()){
+ extra[ImplementedInterfaces]?.interfaces?.entries?.single()?.value?.map { it.sureClassNames }?.sorted() equals listOf("Highest", "Lower").sorted()
+ }
+ }
+ }
+
+ @Test fun multipleClassInheritanceWithInterface() {
+ inlineModelTest(
+ """
+ |interface Highest { }
+ |interface Lower extends Highest { }
+ |class Extendable { }
+ |class Tested extends Extendable implements Lower { }
+ """){
+ with((this / "java" / "Tested").cast<DClass>()) {
+ supertypes.entries.single().value.map { it.dri.sureClassNames to it.kind }.sortedBy { it.first } equals listOf("Extendable" to JavaClassKindTypes.CLASS, "Lower" to JavaClassKindTypes.INTERFACE)
+ }
+ }
+ }
+
+ @Test // todo
+ fun memberWithModifiers() {
+ inlineModelTest(
+ """
+ |class Test {
+ | /**
+ | * Summary for Function
+ | * @param name is String parameter
+ | * @param value is int parameter
+ | */
+ | public void fn(String name, int value) {}
+ |}
+ """
+ ) {
+ with((this / "java" / "Test" / "fn").cast<DFunction>()) {
+ this
+ }
+ }
+ }
+
+ @Test
+ fun superClass() {
+ inlineModelTest(
+ """
+ |public class Foo extends Exception implements Cloneable {}
+ """
+ ) {
+ with((this / "java" / "Foo").cast<DClass>()) {
+ val sups = listOf("Exception", "Cloneable")
+ assertTrue(
+ sups.all { s -> supertypes.values.flatten().any { it.dri.classNames == s } })
+ "Foo must extend ${sups.joinToString(", ")}"
+ }
+ }
+ }
+
+ @Test
+ fun arrayType() {
+ inlineModelTest(
+ """
+ |class Test {
+ | public String[] arrayToString(int[] data) {
+ | return null;
+ | }
+ |}
+ """
+ ) {
+ with((this / "java" / "Test").cast<DClass>()) {
+ name equals "Test"
+ children counts 1
+
+ with((this / "arrayToString").cast<DFunction>()) {
+ name equals "arrayToString"
+ type.name equals "Array"
+ with(parameters.firstOrNull().assertNotNull("parameters")) {
+ name equals "data"
+ type.name equals "Array"
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun typeParameter() {
+ inlineModelTest(
+ """
+ |class Foo<T extends Comparable<T>> {
+ | public <E> E foo();
+ |}
+ """
+ ) {
+ with((this / "java" / "Foo").cast<DClass>()) {
+ generics counts 1
+ }
+ }
+ }
+
+ @Test
+ fun constructors() {
+ inlineModelTest(
+ """
+ |class Test {
+ | public Test() {}
+ |
+ | public Test(String s) {}
+ |}
+ """
+ ) {
+ with((this / "java" / "Test").cast<DClass>()) {
+ name equals "Test"
+
+ constructors counts 2
+ constructors.find { it.parameters.isNullOrEmpty() }.assertNotNull("Test()")
+
+ with(constructors.find { it.parameters.isNotEmpty() }.assertNotNull("Test(String)")) {
+ parameters.firstOrNull()?.type?.name equals "String"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun innerClass() {
+ inlineModelTest(
+ """
+ |class InnerClass {
+ | public class D {}
+ |}
+ """
+ ) {
+ with((this / "java" / "InnerClass").cast<DClass>()) {
+ children counts 1
+ with((this / "D").cast<DClass>()) {
+ name equals "D"
+ children counts 0
+ }
+ }
+ }
+ }
+
+ @Test
+ fun varargs() {
+ inlineModelTest(
+ """
+ |class Foo {
+ | public void bar(String... x);
+ |}
+ """
+ ) {
+ with((this / "java" / "Foo").cast<DClass>()) {
+ name equals "Foo"
+ children counts 1
+
+ with((this / "bar").cast<DFunction>()) {
+ name equals "bar"
+ with(parameters.firstOrNull().assertNotNull("parameter")) {
+ name equals "x"
+ type.name equals "Array"
+ }
+ }
+ }
+ }
+ }
+
+ @Test // todo
+ fun fields() {
+ inlineModelTest(
+ """
+ |class Test {
+ | public int i;
+ | public static final String s;
+ |}
+ """
+ ) {
+ with((this / "java" / "Test").cast<DClass>()) {
+ children counts 2
+
+ with((this / "i").cast<DProperty>()) {
+ getter equals null
+ setter equals null
+ }
+
+ with((this / "s").cast<DProperty>()) {
+ getter equals null
+ setter equals null
+ }
+ }
+ }
+ }
+
+ @Test
+ fun staticMethod() {
+ inlineModelTest(
+ """
+ |class C {
+ | public static void foo() {}
+ |}
+ """
+ ) {
+ with((this / "java" / "C" / "foo").cast<DFunction>()) {
+ with(extra[AdditionalModifiers]!!.content.entries.single().value.assertNotNull("AdditionalModifiers")) {
+ this counts 1
+ first() equals ExtraModifiers.JavaOnlyModifiers.Static
+ }
+ }
+ }
+ }
+
+ @Test
+ fun annotatedAnnotation() {
+ inlineModelTest(
+ """
+ |import java.lang.annotation.*;
+ |
+ |@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
+ |public @interface Attribute {
+ | String value() default "";
+ |}
+ """
+ ) {
+ with((this / "java" / "Attribute").cast<DAnnotation>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ with(single()) {
+ dri.classNames equals "Target"
+ (params["value"].assertNotNull("value") as ArrayValue).value equals listOf(
+ EnumValue("ElementType.FIELD", DRI("java.lang.annotation", "ElementType")),
+ EnumValue("ElementType.TYPE", DRI("java.lang.annotation", "ElementType")),
+ EnumValue("ElementType.METHOD", DRI("java.lang.annotation", "ElementType"))
+ )
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun javaLangObject() {
+ inlineModelTest(
+ """
+ |class Test {
+ | public Object fn() { return null; }
+ |}
+ """
+ ) {
+ with((this / "java" / "Test" / "fn").cast<DFunction>()) {
+ assertTrue(type is JavaObject)
+ }
+ }
+ }
+
+ @Test
+ fun enumValues() {
+ inlineModelTest(
+ """
+ |enum E {
+ | Foo
+ |}
+ """
+ ) {
+ with((this / "java" / "E").cast<DEnum>()) {
+ name equals "E"
+ entries counts 1
+
+ with((this / "Foo").cast<DEnumEntry>()) {
+ name equals "Foo"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun inheritorLinks() {
+ inlineModelTest(
+ """
+ |public class InheritorLinks {
+ | public static class Foo {}
+ |
+ | public static class Bar extends Foo {}
+ |}
+ """
+ ) {
+ with((this / "java" / "InheritorLinks").cast<DClass>()) {
+ val dri = (this / "Bar").assertNotNull("Foo dri").dri
+ with((this / "Foo").cast<DClass>()) {
+ with(extra[InheritorsInfo].assertNotNull("InheritorsInfo")) {
+ with(value.values.flatten().distinct()) {
+ this counts 1
+ first() equals dri
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/base/src/test/kotlin/model/PackagesTest.kt b/plugins/base/src/test/kotlin/model/PackagesTest.kt
new file mode 100644
index 00000000..86222d95
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/PackagesTest.kt
@@ -0,0 +1,134 @@
+package model
+
+import org.jetbrains.dokka.model.DPackage
+import org.junit.jupiter.api.Test
+import utils.AbstractModelTest
+
+class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "packages") {
+
+ @Test
+ fun rootPackage() {
+ inlineModelTest(
+ """
+ |
+ """.trimIndent(),
+ prependPackage = false,
+ configuration = dokkaConfiguration {
+ sourceSets {
+ sourceSet {
+ sourceRoots = listOf("src/main/kotlin")
+ displayName = "JVM"
+ }
+ }
+ }
+ ) {
+ with((this / "[JVM root]").cast<DPackage>()) {
+ name equals "[JVM root]"
+ children counts 0
+ }
+ }
+ }
+
+ @Test
+ fun simpleNamePackage() {
+ inlineModelTest(
+ """
+ |package simple
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ with((this / "simple").cast<DPackage>()) {
+ name equals "simple"
+ children counts 0
+ }
+ }
+ }
+
+ @Test
+ fun dottedNamePackage() {
+ inlineModelTest(
+ """
+ |package dot.name
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ with((this / "dot.name").cast<DPackage>()) {
+ name equals "dot.name"
+ children counts 0
+ }
+ }
+
+ }
+
+ @Test
+ fun multipleFiles() {
+ inlineModelTest(
+ """
+ |package dot.name
+ |/src/main/kotlin/packages/Test2.kt
+ |package simple
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ children counts 2
+ with((this / "dot.name").cast<DPackage>()) {
+ name equals "dot.name"
+ children counts 0
+ }
+ with((this / "simple").cast<DPackage>()) {
+ name equals "simple"
+ children counts 0
+ }
+ }
+ }
+
+ @Test
+ fun multipleFilesSamePackage() {
+ inlineModelTest(
+ """
+ |package simple
+ |/src/main/kotlin/packages/Test2.kt
+ |package simple
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ children counts 1
+ with((this / "simple").cast<DPackage>()) {
+ name equals "simple"
+ children counts 0
+ }
+ }
+ }
+
+ @Test
+ fun classAtPackageLevel() {
+ inlineModelTest(
+ """
+ |package simple.name
+ |
+ |class Foo {}
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ with((this / "simple.name").cast<DPackage>()) {
+ name equals "simple.name"
+ children counts 1
+ }
+ }
+ }
+
+ // todo
+// @Test fun suppressAtPackageLevel() {
+// verifyModel(
+// ModelConfig(
+// roots = arrayOf(KotlinSourceRoot("testdata/packages/classInPackage.kt", false)),
+// perPackageOptions = listOf(
+// PackageOptionsImpl(prefix = "simple.name", suppress = true)
+// ),
+// analysisPlatform = analysisPlatform
+// )
+// ) { model ->
+// assertEquals(0, model.members.count())
+// }
+// }
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/model/PropertyTest.kt b/plugins/base/src/test/kotlin/model/PropertyTest.kt
new file mode 100644
index 00000000..af952b43
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/PropertyTest.kt
@@ -0,0 +1,265 @@
+package model
+
+import org.jetbrains.dokka.model.*
+import org.junit.jupiter.api.Test
+import utils.AbstractModelTest
+import utils.assertNotNull
+import utils.name
+
+class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "property") {
+
+ @Test
+ fun valueProperty() {
+ inlineModelTest(
+ """
+ |val property = "test""""
+ ) {
+ with((this / "property" / "property").cast<DProperty>()) {
+ name equals "property"
+ children counts 0
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "String"
+ }
+ type.name equals "String"
+ }
+ }
+ }
+
+ @Test
+ fun variableProperty() {
+ inlineModelTest(
+ """
+ |var property = "test"
+ """
+ ) {
+ with((this / "property" / "property").cast<DProperty>()) {
+ name equals "property"
+ children counts 0
+ setter.assertNotNull("Setter")
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "String"
+ }
+ type.name equals "String"
+ }
+ }
+ }
+
+ @Test
+ fun valuePropertyWithGetter() {
+ inlineModelTest(
+ """
+ |val property: String
+ | get() = "test"
+ """
+ ) {
+ with((this / "property" / "property").cast<DProperty>()) {
+ name equals "property"
+ children counts 0
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "String"
+ }
+ type.name equals "String"
+ }
+ }
+ }
+
+ @Test
+ fun variablePropertyWithAccessors() {
+ inlineModelTest(
+ """
+ |var property: String
+ | get() = "test"
+ | set(value) {}
+ """
+ ) {
+ with((this / "property" / "property").cast<DProperty>()) {
+ name equals "property"
+ children counts 0
+ setter.assertNotNull("Setter")
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "String"
+ }
+ visibility.values allEquals KotlinVisibility.Public
+ }
+ }
+ }
+
+ @Test
+ fun propertyWithReceiver() {
+ inlineModelTest(
+ """
+ |val String.property: Int
+ | get() = size() * 2
+ """
+ ) {
+ with((this / "property" / "property").cast<DProperty>()) {
+ name equals "property"
+ children counts 0
+ with(receiver.assertNotNull("property receiver")) {
+ name equals null
+ type.name equals "String"
+ }
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "Int"
+ }
+ visibility.values allEquals KotlinVisibility.Public
+ }
+ }
+ }
+
+ @Test
+ fun propertyOverride() {
+ inlineModelTest(
+ """
+ |open class Foo() {
+ | open val property: Int get() = 0
+ |}
+ |class Bar(): Foo() {
+ | override val property: Int get() = 1
+ |}
+ """
+ ) {
+ with((this / "property").cast<DPackage>()) {
+ with((this / "Foo" / "property").cast<DProperty>()) {
+ name equals "property"
+ children counts 0
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "Int"
+ }
+ }
+ with((this / "Bar" / "property").cast<DProperty>()) {
+ name equals "property"
+ children counts 0
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "Int"
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun sinceKotlin() {
+ inlineModelTest(
+ """
+ |/**
+ | * Quite useful [String]
+ | */
+ |@SinceKotlin("1.1")
+ |val prop: String = "1.1 rulezz"
+ """
+ ) {
+ with((this / "property" / "prop").cast<DProperty>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(first()) {
+ dri.classNames equals "SinceKotlin"
+ params.entries counts 1
+ (params["version"].assertNotNull("version") as StringValue).value equals "\"1.1\""
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun annotatedProperty() {
+ inlineModelTest(
+ """
+ |@Strictfp var property = "test"
+ """,
+ configuration = dokkaConfiguration {
+ sourceSets {
+ sourceSet {
+ sourceRoots = listOf("src/")
+ classpath = listOfNotNull(jvmStdlibPath)
+ }
+ }
+ }
+ ) {
+ with((this / "property" / "property").cast<DProperty>()) {
+ with(extra[Annotations]!!.content.entries.single().value.assertNotNull("Annotations")) {
+ this counts 1
+ with(first()) {
+ dri.classNames equals "Strictfp"
+ params.entries counts 0
+ }
+ }
+ }
+ }
+ }
+
+ @Test fun genericTopLevelExtensionProperty(){
+ inlineModelTest(
+ """ | val <T : Number> List<T>.sampleProperty: T
+ | get() { TODO() }
+ """.trimIndent()
+ ){
+ with((this / "property" / "sampleProperty").cast<DProperty>()) {
+ name equals "sampleProperty"
+ with(receiver.assertNotNull("Property receiver")) {
+ type.name equals "List"
+ }
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "T"
+ }
+ setter equals null
+ generics counts 1
+ generics.forEach {
+ it.name equals "T"
+ it.bounds.first().name equals "Number"
+ }
+ visibility.values allEquals KotlinVisibility.Public
+ }
+ }
+ }
+
+ @Test fun genericExtensionPropertyInClass(){
+ inlineModelTest(
+ """ | package test
+ | class XD<T> {
+ | var List<T>.sampleProperty: T
+ | get() { TODO() }
+ | set(value) { TODO() }
+ | }
+ """.trimIndent()
+ ){
+ with((this / "property" / "XD" / "sampleProperty").cast<DProperty>()) {
+ name equals "sampleProperty"
+ children counts 0
+ with(receiver.assertNotNull("Property receiver")) {
+ type.name equals "List"
+ }
+ with(getter.assertNotNull("Getter")) {
+ type.name equals "T"
+ }
+ with(setter.assertNotNull("Setter")){
+ type.name equals "Unit"
+ }
+ generics counts 0
+ visibility.values allEquals KotlinVisibility.Public
+ }
+ }
+ }
+// @Test
+// fun annotatedProperty() {
+// checkSourceExistsAndVerifyModel(
+// "testdata/properties/annotatedProperty.kt",
+// modelConfig = ModelConfig(
+// analysisPlatform = analysisPlatform,
+// withKotlinRuntime = true
+// )
+// ) { model ->
+// with(model.members.single().members.single()) {
+// Assert.assertEquals(1, annotations.count())
+// with(annotations[0]) {
+// Assert.assertEquals("Strictfp", name)
+// Assert.assertEquals(Content.Empty, content)
+// Assert.assertEquals(NodeKind.Annotation, kind)
+// }
+// }
+// }
+// }
+//
+//}
+}