aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src
diff options
context:
space:
mode:
authorSzymon Świstun <sswistun@virtuslab.com>2020-02-26 11:52:03 +0100
committerKamil Doległo <kamilok1965@interia.pl>2020-02-28 16:37:40 +0100
commitcacf1e0c6cda4e42fe6581946cad53a377c71ec7 (patch)
treec6bc41f74dde1962a0578597c5ddcc27fa356689 /plugins/base/src
parent77d6ce22a286601bc5d1401619eb42fac58e7013 (diff)
downloaddokka-cacf1e0c6cda4e42fe6581946cad53a377c71ec7.tar.gz
dokka-cacf1e0c6cda4e42fe6581946cad53a377c71ec7.tar.bz2
dokka-cacf1e0c6cda4e42fe6581946cad53a377c71ec7.zip
Port some of the core tests from the previous model
Diffstat (limited to 'plugins/base/src')
-rw-r--r--plugins/base/src/test/kotlin/issues/IssuesTest.kt67
-rw-r--r--plugins/base/src/test/kotlin/model/ClassesTest.kt448
-rw-r--r--plugins/base/src/test/kotlin/model/CommentTest.kt332
-rw-r--r--plugins/base/src/test/kotlin/model/FunctionsTest.kt315
-rw-r--r--plugins/base/src/test/kotlin/model/JavaTest.kt367
-rw-r--r--plugins/base/src/test/kotlin/model/PackagesTest.kt126
-rw-r--r--plugins/base/src/test/kotlin/model/PropertyTest.kt176
-rw-r--r--plugins/base/src/test/kotlin/utils/ModelUtils.kt33
-rw-r--r--plugins/base/src/test/kotlin/utils/TestUtils.kt68
9 files changed, 1932 insertions, 0 deletions
diff --git a/plugins/base/src/test/kotlin/issues/IssuesTest.kt b/plugins/base/src/test/kotlin/issues/IssuesTest.kt
new file mode 100644
index 00000000..ea2f0f8e
--- /dev/null
+++ b/plugins/base/src/test/kotlin/issues/IssuesTest.kt
@@ -0,0 +1,67 @@
+package issues
+
+import org.jetbrains.dokka.model.Class
+import org.jetbrains.dokka.model.Function
+import org.junit.Test
+import utils.AbstractModelTest
+
+class IssuesTest : AbstractModelTest("/src/main/kotlin/issues/Test.kt", "issues") {
+
+ @Test
+ fun errorClasses() {
+ inlineModelTest(
+ """
+ |class Test(var value: String) {
+ | fun test(): List<String> = emptyList()
+ | fun brokenApply(v: String) = apply { value = v }
+ |
+ | fun brokenRun(v: String) = run {
+ | value = v
+ | this
+ | }
+ |
+ | fun brokenLet(v: String) = let {
+ | it.value = v
+ | it
+ | }
+ |
+ | fun brokenGenerics() = listOf("a", "b", "c")
+ |
+ | fun working(v: String) = doSomething()
+ |
+ | fun doSomething(): String = "Hello"
+ |}
+ """
+ ) {
+ with((this / "issues" / "Test").cast<Class>()) {
+ // passes
+ (this / "working").cast<Function>().type.constructorFqName equals "kotlin.String"
+ (this / "doSomething").cast<Function>().type.constructorFqName equals "kotlin.String"
+
+ // fails
+ (this / "brokenGenerics").cast<Function>().type.constructorFqName equals "kotlin.collections.List"
+ (this / "brokenApply").cast<Function>().type.constructorFqName equals "issues.Test"
+ (this / "brokenRun").cast<Function>().type.constructorFqName equals "issues.Test"
+ (this / "brokenLet").cast<Function>().type.constructorFqName equals "issues.Test"
+ }
+ }
+ }
+
+ //@Test
+ // fun errorClasses() {
+ // checkSourceExistsAndVerifyModel("testdata/issues/errorClasses.kt",
+ // modelConfig = ModelConfig(analysisPlatform = analysisPlatform, withJdk = true, withKotlinRuntime = true)) { model ->
+ // val cls = model.members.single().members.single()
+ //
+ // fun DocumentationNode.returnType() = this.details.find { it.kind == NodeKind.Type }?.name
+ // assertEquals("Test", cls.members[1].returnType())
+ // assertEquals("Test", cls.members[2].returnType())
+ // assertEquals("Test", cls.members[3].returnType())
+ // assertEquals("List", cls.members[4].returnType())
+ // assertEquals("String", cls.members[5].returnType())
+ // assertEquals("String", cls.members[6].returnType())
+ // assertEquals("String", cls.members[7].returnType())
+ // }
+ // }
+
+} \ No newline at end of file
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..2332df61
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/ClassesTest.kt
@@ -0,0 +1,448 @@
+package model
+
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.Function
+import org.jetbrains.dokka.model.Object
+import org.jetbrains.dokka.model.WithAbstraction.Modifier
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.junit.Test
+import utils.AbstractModelTest
+import utils.assertNotNull
+import utils.supers
+
+
+class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "classes") {
+
+ @Test
+ fun emptyClass() {
+ inlineModelTest(
+ """
+ |class Klass {}"""
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+ children counts 4
+ }
+ }
+ }
+
+ @Test
+ fun emptyObject() {
+ inlineModelTest(
+ """
+ |object Obj {}
+ """
+ ) {
+ with((this / "classes" / "Obj").cast<Object>()) {
+ name equals "Obj"
+ children counts 3
+ }
+ }
+ }
+
+ @Test
+ fun classWithConstructor() {
+ inlineModelTest(
+ """
+ |class Klass(name: String)
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+ children counts 4
+
+ with(constructors.firstOrNull().assertNotNull("Constructor")) {
+ visibility.values allEquals Visibilities.PUBLIC
+ parameters counts 1
+ with(parameters.firstOrNull().assertNotNull("Constructor parameter")) {
+ name equals "name"
+ type.constructorFqName equals "kotlin.String"
+ }
+ }
+
+ }
+ }
+ }
+
+ @Test
+ fun classWithFunction() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | fun fn() {}
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+ children counts 5
+
+ with((this / "fn").cast<Function>()) {
+ type.constructorFqName equals "kotlin.Unit"
+ parameters counts 0
+ visibility.values allEquals Visibilities.PUBLIC
+ }
+ }
+ }
+ }
+
+ @Test
+ fun classWithProperty() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | val name: String = ""
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+ children counts 5
+
+ with((this / "name").cast<Property>()) {
+ name equals "name"
+ // TODO property name
+ }
+ }
+ }
+ }
+
+ @Test
+ fun classWithCompanionObject() {
+ inlineModelTest(
+ """
+ |class Klass() {
+ | companion object {
+ | val x = 1
+ | fun foo() {}
+ | }
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+ children counts 5
+
+ with((this / "Companion").cast<Object>()) {
+ name equals "Companion"
+ children counts 5
+
+ with((this / "x").cast<Property>()) {
+ name equals "x"
+ }
+
+ with((this / "foo").cast<Function>()) {
+ name equals "foo"
+ parameters counts 0
+ type.constructorFqName equals "kotlin.Unit"
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun dataClass() {
+ inlineModelTest(
+ """
+ |data class Klass() {}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+ visibility.values allEquals Visibilities.PUBLIC
+ // TODO data modifier
+ }
+ }
+ }
+
+// @Test fun dataClass() {
+// verifyPackageMember("testdata/classes/dataClass.kt", defaultModelConfig) { cls ->
+// val modifiers = cls.details(NodeKind.Modifier).map { it.name }
+// assertTrue("data" in modifiers)
+// }
+// }
+
+ @Test
+ fun sealedClass() {
+ inlineModelTest(
+ """
+ |sealed class Klass() {}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+ modifier equals WithAbstraction.Modifier.Sealed
+ }
+ }
+ }
+
+// // TODO modifiers
+// @Test fun annotatedClassWithAnnotationParameters() {
+// checkSourceExistsAndVerifyModel(
+// "testdata/classes/annotatedClassWithAnnotationParameters.kt",
+// defaultModelConfig
+// ) { model ->
+// with(model.members.single().members.single()) {
+// with(deprecation!!) {
+// assertEquals("Deprecated", name)
+// assertEquals(Content.Empty, content)
+// assertEquals(NodeKind.Annotation, kind)
+// assertEquals(1, details.count())
+// with(details[0]) {
+// assertEquals(NodeKind.Parameter, kind)
+// assertEquals(1, details.count())
+// with(details[0]) {
+// assertEquals(NodeKind.Value, kind)
+// assertEquals("\"should no longer be used\"", name)
+// }
+// }
+// }
+// }
+// }
+// }
+
+ @Test
+ fun notOpenClass() {
+ inlineModelTest(
+ """
+ |open class C() {
+ | open fun f() {}
+ |}
+ |
+ |class D() : C() {
+ | override fun f() {}
+ |}
+ """
+ ) {
+ val C = (this / "classes" / "C").cast<Class>()
+ val D = (this / "classes" / "D").cast<Class>()
+
+ with(C) {
+ modifier equals Modifier.Open
+ with((this / "f").cast<Function>()) {
+ modifier equals Modifier.Open
+ }
+ }
+ with(D) {
+ modifier equals Modifier.Final
+ with((this / "f").cast<Function>()) {
+ modifier equals Modifier.Open
+ }
+ D.supertypes.flatMap { it.component2() }.firstOrNull() 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<Class>()
+ val D = (this / "classes" / "D").cast<Class>()
+ val E = (this / "classes" / "E").cast<Class>()
+
+ with(C) {
+ modifier equals Modifier.Abstract
+ ((this / "foo").cast<Function>()).modifier equals Modifier.Abstract
+ }
+
+ with(D) {
+ modifier equals Modifier.Abstract
+ }
+
+ with(E) {
+ modifier equals Modifier.Final
+
+ }
+ D.supers.firstOrNull() equals C.dri
+ E.supers.firstOrNull() equals D.dri
+ }
+ }
+
+ @Test // todo inner class
+ fun innerClass() {
+ inlineModelTest(
+ """
+ |class C {
+ | inner class D {}
+ |}
+ """
+ ) {
+ with((this / "classes" / "C").cast<Class>()) {
+
+ with((this / "D").cast<Class>()) {
+ }
+ }
+ }
+ }
+
+// // TODO modifiers
+// @Test fun innerClass() {
+// verifyPackageMember("testdata/classes/innerClass.kt", defaultModelConfig) { cls ->
+// val innerClass = cls.members.single { it.name == "D" }
+// val modifiers = innerClass.details(NodeKind.Modifier)
+// assertEquals(3, modifiers.size)
+// assertEquals("inner", modifiers[2].name)
+// }
+// }
+
+ @Test
+ fun companionObjectExtension() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | companion object Default {}
+ |}
+ |
+ |/**
+ | * The def
+ | */
+ |val Klass.Default.x: Int get() = 1
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+
+ with((this / "Default").cast<Object>()) {
+ 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<Class>()) {
+ 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.constructorFqName equals "kotlin.String"
+ }
+ }
+ }
+ }
+ }
+
+ // TODO modifiers
+// @Test fun sinceKotlin() {
+// checkSourceExistsAndVerifyModel("testdata/classes/sinceKotlin.kt", defaultModelConfig) { model ->
+// with(model.members.single().members.single()) {
+// assertEquals("1.1", sinceKotlin)
+// }
+// }
+// }
+
+ @Test
+ fun privateCompanionObject() {
+ inlineModelTest(
+ """
+ |class Klass {
+ | private companion object {
+ | fun fn() {}
+ | val a = 0
+ | }
+ |}
+ """
+ ) {
+ with((this / "classes" / "Klass").cast<Class>()) {
+ name equals "Klass"
+
+ with((this / "Companion").cast<Object>()) {
+ name equals "Companion"
+ visibility.values allEquals Visibilities.PRIVATE
+
+ with((this / "fn").cast<Function>()) {
+ name equals "fn"
+ parameters counts 0
+ receiver equals null
+ }
+ }
+ }
+ }
+ }
+
+ // TODO annotations
+// @Test
+// fun annotatedClass() {
+// verifyPackageMember("testdata/classes/annotatedClass.kt", ModelConfig(
+// analysisPlatform = analysisPlatform,
+// withKotlinRuntime = true
+// )
+// ) { cls ->
+// Assert.assertEquals(1, cls.annotations.count())
+// with(cls.annotations[0]) {
+// Assert.assertEquals("Strictfp", name)
+// Assert.assertEquals(Content.Empty, content)
+// Assert.assertEquals(NodeKind.Annotation, kind)
+// }
+// }
+// }
+
+
+// TODO annotations
+
+// @Test fun javaAnnotationClass() {
+// checkSourceExistsAndVerifyModel(
+// "testdata/classes/javaAnnotationClass.kt",
+// modelConfig = ModelConfig(analysisPlatform = analysisPlatform, withJdk = true)
+// ) { model ->
+// with(model.members.single().members.single()) {
+// Assert.assertEquals(1, annotations.count())
+// with(annotations[0]) {
+// Assert.assertEquals("Retention", name)
+// Assert.assertEquals(Content.Empty, content)
+// Assert.assertEquals(NodeKind.Annotation, kind)
+// with(details[0]) {
+// Assert.assertEquals(NodeKind.Parameter, kind)
+// Assert.assertEquals(1, details.count())
+// with(details[0]) {
+// Assert.assertEquals(NodeKind.Value, kind)
+// Assert.assertEquals("RetentionPolicy.SOURCE", name)
+// }
+// }
+// }
+// }
+// }
+// }
+
+} \ 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..d576cf49
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/CommentTest.kt
@@ -0,0 +1,332 @@
+package model
+
+import org.jetbrains.dokka.model.Property
+import org.jetbrains.dokka.model.doc.CustomWrapperTag
+import org.jetbrains.dokka.model.doc.Text
+import org.junit.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<Property>()) {
+ 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<Property>()) {
+ name equals "prop2"
+ comments() equals "a + b - c"
+ }
+ }
+ }
+
+ @Test
+ fun emptyDoc() {
+ inlineModelTest(
+ """
+ val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<Property>()) {
+ name equals "property"
+ comments() equals ""
+ }
+ }
+ }
+
+ @Test
+ fun emptyDocButComment() {
+ inlineModelTest(
+ """
+ |/* comment */
+ |val property = "test"
+ |fun tst() = property
+ """
+ ) {
+ val p = this
+ with((this / "comment" / "property").cast<Property>()) {
+ comments() equals ""
+ }
+ }
+ }
+
+ @Test
+ fun multilineDoc() {
+ inlineModelTest(
+ """
+ |/**
+ | * doc1
+ | *
+ | * doc2
+ | * doc3
+ | */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<Property>()) {
+ comments() equals "doc1\ndoc2 doc3"
+ }
+ }
+ }
+
+ @Test
+ fun multilineDocWithComment() {
+ inlineModelTest(
+ """
+ |/**
+ | * doc1
+ | *
+ | * doc2
+ | * doc3
+ | */
+ |// comment
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<Property>()) {
+ comments() equals "doc1\ndoc2 doc3"
+ }
+ }
+ }
+
+ @Test
+ fun oneLineDoc() {
+ inlineModelTest(
+ """
+ |/** doc */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<Property>()) {
+ comments() equals "doc"
+ }
+ }
+ }
+
+ @Test
+ fun oneLineDocWithComment() {
+ inlineModelTest(
+ """
+ |/** doc */
+ |// comment
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<Property>()) {
+ comments() equals "doc"
+ }
+ }
+ }
+
+ @Test
+ fun oneLineDocWithEmptyLine() {
+ inlineModelTest(
+ """
+ |/** doc */
+ |
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<Property>()) {
+ comments() equals "doc"
+ }
+ }
+ }
+
+ @Test
+ fun emptySection() {
+ inlineModelTest(
+ """
+ |/**
+ | * Summary
+ | * @one
+ | */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<Property>()) {
+ comments() equals "Summary\none: []"
+ docs().find { it is CustomWrapperTag && 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<Property>()) {
+ comments() equals """it's "useful""""
+ }
+ }
+ }
+
+ @Test
+ fun section1() {
+ inlineModelTest(
+ """
+ |/**
+ | * Summary
+ | * @one section one
+ | */
+ |val property = "test"
+ """
+ ) {
+ with((this / "comment" / "property").cast<Property>()) {
+ 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<Property>()) {
+ 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<Property>()) {
+ 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<Property>()) {
+ 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..9554ad02
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/FunctionsTest.kt
@@ -0,0 +1,315 @@
+package model
+
+import org.jetbrains.dokka.model.Function
+import org.jetbrains.dokka.model.Package
+import org.junit.Test
+import utils.*
+
+class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "function") {
+
+ @Test
+ fun function() {
+ inlineModelTest(
+ """
+ |/**
+ | * Function fn
+ | */
+ |fun fn() {}
+ """
+ ) {
+ with((this / "function" / "fn").cast<Function>()) {
+ name equals "fn"
+ type.constructorFqName equals "kotlin.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<Package>()) {
+ 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.constructorFqName equals "kotlin.Int"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun functionWithReceiver() {
+ inlineModelTest(
+ """
+ |/**
+ | * Function with receiver
+ | */
+ |fun String.fn() {}
+ |
+ |/**
+ | * Function with receiver
+ | */
+ |fun String.fn(x: Int) {}
+ """
+ ) {
+ with((this / "function").cast<Package>()) {
+ 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.constructorFqName equals "kotlin.Int"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun functionWithParams() {
+ inlineModelTest(
+ """
+ |/**
+ | * Multiline
+ | *
+ | * Function
+ | * Documentation
+ | */
+ |fun function(/** parameter */ x: Int) {
+ |}
+ """
+ ) {
+ with((this / "function" / "function").cast<Function>()) {
+ comments() equals "Multiline\nFunction Documentation"
+
+ name equals "function"
+ parameters counts 1
+ parameters.firstOrNull().assertNotNull("Parameter: ").also {
+ it.name equals "x"
+ it.type.constructorFqName equals "kotlin.Int"
+ it.comments() equals "parameter"
+ }
+
+ type.assertNotNull("Return type: ").constructorFqName equals "kotlin.Unit"
+ }
+ }
+ }
+
+// TODO add modifiers - start
+
+ @Test
+ fun functionWithNotDocumentedAnnotation() {
+ inlineModelTest(
+ """
+ |@Suppress("FOO") fun f() {}
+ """
+ ) {
+ // TODO add annotations
+
+ with((this / "function" / "f").cast<Function>()) {
+ assert(false) { "No annotation data" }
+ }
+ }
+ }
+
+// @Test fun functionWithNotDocumentedAnnotation() {
+// verifyPackageMember("testdata/functions/functionWithNotDocumentedAnnotation.kt", defaultModelConfig) { func ->
+// assertEquals(0, func.annotations.count())
+// }
+// }
+
+ @Test
+ fun inlineFunction() {
+ inlineModelTest(
+ """
+ |inline fun f(a: () -> String) {}
+ """
+ ) {
+ // TODO add data about inline
+
+ with((this / "function" / "f").cast<Function>()) {
+ assert(false) { "No inline data" }
+ }
+ }
+ }
+
+// @Test fun inlineFunction() {
+// verifyPackageMember("testdata/functions/inlineFunction.kt", defaultModelConfig) { func ->
+// val modifiers = func.details(NodeKind.Modifier).map { it.name }
+// assertTrue("inline" in modifiers)
+// }
+// }
+
+ @Test
+ fun suspendFunction() {
+ inlineModelTest(
+ """
+ |suspend fun f() {}
+ """
+ ) {
+ // TODO add data about suspend
+
+ with((this / "function" / "f").cast<Function>()) {
+ assert(false) { "No suspend data" }
+ }
+ }
+ }
+
+// @Test fun suspendFunction() {
+// verifyPackageMember("testdata/functions/suspendFunction.kt") { func ->
+// val modifiers = func.details(NodeKind.Modifier).map { it.name }
+// assertTrue("suspend" in modifiers)
+// }
+// }
+
+// @Test fun suspendInlineFunctionOrder() {
+// verifyPackageMember("testdata/functions/suspendInlineFunction.kt") { func ->
+// val modifiers = func.details(NodeKind.Modifier).map { it.name }.filter {
+// it == "suspend" || it == "inline"
+// }
+//
+// assertEquals(listOf("suspend", "inline"), modifiers)
+// }
+// }
+//
+// @Test fun inlineSuspendFunctionOrderChanged() {
+// verifyPackageMember("testdata/functions/inlineSuspendFunction.kt") { func ->
+// val modifiers = func.details(NodeKind.Modifier).map { it.name }.filter {
+// it == "suspend" || it == "inline"
+// }
+//
+// assertEquals(listOf("suspend", "inline"), modifiers)
+// }
+// }
+//
+// @Test fun functionWithAnnotatedParam() {
+// checkSourceExistsAndVerifyModel("testdata/functions/functionWithAnnotatedParam.kt", defaultModelConfig) { model ->
+// with(model.members.single().members.single { it.name == "function" }) {
+// with(details(NodeKind.Parameter).first()) {
+// assertEquals(1, annotations.count())
+// with(annotations[0]) {
+// assertEquals("Fancy", name)
+// assertEquals(Content.Empty, content)
+// assertEquals(NodeKind.Annotation, kind)
+// }
+// }
+// }
+// }
+// }
+//
+// @Test fun functionWithNoinlineParam() {
+// verifyPackageMember("testdata/functions/functionWithNoinlineParam.kt", defaultModelConfig) { func ->
+// with(func.details(NodeKind.Parameter).first()) {
+// val modifiers = details(NodeKind.Modifier).map { it.name }
+// assertTrue("noinline" in modifiers)
+// }
+// }
+// }
+//
+// @Test fun annotatedFunctionWithAnnotationParameters() {
+// checkSourceExistsAndVerifyModel(
+// "testdata/functions/annotatedFunctionWithAnnotationParameters.kt",
+// defaultModelConfig
+// ) { model ->
+// with(model.members.single().members.single { it.name == "f" }) {
+// assertEquals(1, annotations.count())
+// with(annotations[0]) {
+// assertEquals("Fancy", name)
+// assertEquals(Content.Empty, content)
+// assertEquals(NodeKind.Annotation, kind)
+// assertEquals(1, details.count())
+// with(details[0]) {
+// assertEquals(NodeKind.Parameter, kind)
+// assertEquals(1, details.count())
+// with(details[0]) {
+// assertEquals(NodeKind.Value, kind)
+// assertEquals("1", name)
+// }
+// }
+// }
+// }
+// }
+// }
+
+// TODO add modifiers - end
+
+// @Test
+// fun functionWithDefaultParameter() {
+// inlineModelTest(
+// """
+// |/src/main/kotlin/function/Test.kt
+// |package function
+// |fun f(x: String = "") {}
+// """
+// ) {
+// // TODO add default value data
+//
+// with(this / "function" / "f" cast Function::class) {
+// parameters.forEach { p ->
+// p.name equals "x"
+// p.type.constructorFqName.assertNotNull("Parameter type: ") equals "kotlin.String"
+// assert(false) { "Add default value data" }
+// }
+// }
+// }
+// }
+
+// @Test fun functionWithDefaultParameter() {
+// checkSourceExistsAndVerifyModel("testdata/functions/functionWithDefaultParameter.kt", defaultModelConfig) { model ->
+// with(model.members.single().members.single()) {
+// with(details.elementAt(3)) {
+// val value = details(NodeKind.Value)
+// assertEquals(1, value.count())
+// with(value[0]) {
+// assertEquals("\"\"", name)
+// }
+// }
+// }
+// }
+// }
+//
+// @Test fun sinceKotlin() {
+// checkSourceExistsAndVerifyModel("testdata/functions/sinceKotlin.kt", defaultModelConfig) { model ->
+// with(model.members.single().members.single()) {
+// assertEquals("1.1", sinceKotlin)
+// }
+// }
+// }
+//}
+
+} \ No newline at end of file
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..ea454763
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/JavaTest.kt
@@ -0,0 +1,367 @@
+package model
+
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.Enum
+import org.jetbrains.dokka.model.Function
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import utils.AbstractModelTest
+import utils.assertNotNull
+
+class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") {
+
+ @Test //todo params in comments
+ 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<Class>()) {
+ name equals "Test"
+ children counts 1
+ with((this / "fn").cast<Function>()) {
+ name equals "fn"
+ this
+ }
+ }
+ }
+ }
+
+ //@Test fun function() {
+ // verifyJavaPackageMember("testdata/java/member.java", defaultModelConfig) { cls ->
+ // assertEquals("Test", cls.name)
+ // assertEquals(NodeKind.Class, cls.kind)
+ // with(cls.members(NodeKind.Function).single()) {
+ // assertEquals("fn", name)
+ // assertEquals("Summary for Function", content.summary.toTestString().trimEnd())
+ // assertEquals(3, content.sections.size)
+ // with(content.sections[0]) {
+ // assertEquals("Parameters", tag)
+ // assertEquals("name", subjectName)
+ // assertEquals("render(Type:String,SUMMARY): is String parameter", toTestString())
+ // }
+ // with(content.sections[1]) {
+ // assertEquals("Parameters", tag)
+ // assertEquals("value", subjectName)
+ // assertEquals("render(Type:Int,SUMMARY): is int parameter", toTestString())
+ // }
+ // assertEquals("Unit", detail(NodeKind.Type).name)
+ // assertTrue(members.none())
+ // assertTrue(links.none())
+ // with(details.first { it.name == "name" }) {
+ // assertEquals(NodeKind.Parameter, kind)
+ // assertEquals("String", detail(NodeKind.Type).name)
+ // }
+ // with(details.first { it.name == "value" }) {
+ // assertEquals(NodeKind.Parameter, kind)
+ // assertEquals("Int", detail(NodeKind.Type).name)
+ // }
+ // }
+ // }
+ // }
+
+ @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<Function>()) {
+ this
+ }
+ }
+ }
+
+ // @Test fun memberWithModifiers() {
+ // verifyJavaPackageMember("testdata/java/memberWithModifiers.java", defaultModelConfig) { cls ->
+ // val modifiers = cls.details(NodeKind.Modifier).map { it.name }
+ // assertTrue("abstract" in modifiers)
+ // with(cls.members.single { it.name == "fn" }) {
+ // assertEquals("protected", details[0].name)
+ // }
+ // with(cls.members.single { it.name == "openFn" }) {
+ // assertEquals("open", details[1].name)
+ // }
+ // }
+ // }
+
+ @Test
+ fun superClass() {
+ inlineModelTest(
+ """
+ |public class Foo extends Exception implements Cloneable {}
+ """
+ ) {
+ with((this / "java" / "Foo").cast<Class>()) {
+ val sups = listOf("Exception", "Cloneable")
+ assertTrue(
+ "Foo must extend ${sups.joinToString(", ")}",
+ sups.all { s -> supertypes.map.values.flatten().any { it.classNames == s } })
+ }
+ }
+ }
+
+ @Test
+ fun arrayType() {
+ inlineModelTest(
+ """
+ |class Test {
+ | public String[] arrayToString(int[] data) {
+ | return null;
+ | }
+ |}
+ """
+ ) {
+ with((this / "java" / "Test").cast<Class>()) {
+ name equals "Test"
+ children counts 1
+
+ with((this / "arrayToString").cast<Function>()) {
+ name equals "arrayToString"
+ type.constructorFqName equals "java.lang.String[]"
+ with(parameters.firstOrNull().assertNotNull("parameters")) {
+ name equals "data"
+ type.constructorFqName equals "int[]"
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun typeParameter() {
+ inlineModelTest(
+ """
+ |class Foo<T extends Comparable<T>> {
+ | public <E> E foo();
+ |}
+ """
+ ) {
+ with((this / "java" / "Foo").cast<Class>()) {
+ this
+ }
+ }
+ }
+
+ // @Test fun typeParameter() {
+ // verifyJavaPackageMember("testdata/java/typeParameter.java", defaultModelConfig) { cls ->
+ // val typeParameters = cls.details(NodeKind.TypeParameter)
+ // with(typeParameters.single()) {
+ // assertEquals("T", name)
+ // with(detail(NodeKind.UpperBound)) {
+ // assertEquals("Comparable", name)
+ // assertEquals("T", detail(NodeKind.Type).name)
+ // }
+ // }
+ // with(cls.members(NodeKind.Function).single()) {
+ // val methodTypeParameters = details(NodeKind.TypeParameter)
+ // with(methodTypeParameters.single()) {
+ // assertEquals("E", name)
+ // }
+ // }
+ // }
+ // }
+
+ @Test
+ fun constructors() {
+ inlineModelTest(
+ """
+ |class Test {
+ | public Test() {}
+ |
+ | public Test(String s) {}
+ |}
+ """
+ ) {
+ with((this / "java" / "Test").cast<Class>()) {
+ 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?.constructorFqName equals "java.lang.String"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun innerClass() {
+ inlineModelTest(
+ """
+ |class InnerClass {
+ | public class D {}
+ |}
+ """
+ ) {
+ with((this / "java" / "InnerClass").cast<Class>()) {
+ children counts 1
+ with((this / "D").cast<Class>()) {
+ name equals "D"
+ children counts 0
+ }
+ }
+ }
+ }
+
+ @Test
+ fun varargs() {
+ inlineModelTest(
+ """
+ |class Foo {
+ | public void bar(String... x);
+ |}
+ """
+ ) {
+ with((this / "java" / "Foo").cast<Class>()) {
+ name equals "Foo"
+ children counts 1
+
+ with((this / "bar").cast<Function>()) {
+ name equals "bar"
+ with(parameters.firstOrNull().assertNotNull("parameter")) {
+ name equals "x"
+ type.constructorFqName equals "java.lang.String..."
+ }
+ }
+ }
+ }
+ }
+
+ @Test // todo
+ fun fields() {
+ inlineModelTest(
+ """
+ |class Test {
+ | public int i;
+ | public static final String s;
+ |}
+ """
+ ) {
+ with((this / "java" / "Test").cast<Class>()) {
+ children counts 2
+
+ with((this / "i").cast<Property>()) {
+ getter.assertNotNull("i.get")
+ setter.assertNotNull("i.set")
+ }
+
+ with((this / "s").cast<Property>()) {
+ getter.assertNotNull("s.get")
+ setter.assertNotNull("s.set")
+
+ }
+ }
+ }
+ }
+
+ // @Test fun fields() {
+ // verifyJavaPackageMember("testdata/java/field.java", defaultModelConfig) { cls ->
+ // val i = cls.members(NodeKind.Property).single { it.name == "i" }
+ // assertEquals("Int", i.detail(NodeKind.Type).name)
+ // assertTrue("var" in i.details(NodeKind.Modifier).map { it.name })
+ //
+ // val s = cls.members(NodeKind.Property).single { it.name == "s" }
+ // assertEquals("String", s.detail(NodeKind.Type).name)
+ // assertFalse("var" in s.details(NodeKind.Modifier).map { it.name })
+ // assertTrue("static" in s.details(NodeKind.Modifier).map { it.name })
+ // }
+ // }
+
+ // @Test fun staticMethod() { todo
+ // verifyJavaPackageMember("testdata/java/staticMethod.java", defaultModelConfig) { cls ->
+ // val m = cls.members(NodeKind.Function).single { it.name == "foo" }
+ // assertTrue("static" in m.details(NodeKind.Modifier).map { it.name })
+ // }
+ // }
+ //
+ // /**
+ // * `@suppress` not supported in Java!
+ // *
+ // * [Proposed tags](https://www.oracle.com/technetwork/java/javase/documentation/proposed-tags-142378.html)
+ // * Proposed tag `@exclude` for it, but not supported yet
+ // */
+ // @Ignore("@suppress not supported in Java!") @Test fun suppressTag() {
+ // verifyJavaPackageMember("testdata/java/suppressTag.java", defaultModelConfig) { cls ->
+ // assertEquals(1, cls.members(NodeKind.Function).size)
+ // }
+ // }
+ //
+ // @Test fun annotatedAnnotation() {
+ // verifyJavaPackageMember("testdata/java/annotatedAnnotation.java", defaultModelConfig) { cls ->
+ // assertEquals(1, cls.annotations.size)
+ // with(cls.annotations[0]) {
+ // assertEquals(1, details.count())
+ // with(details[0]) {
+ // assertEquals(NodeKind.Parameter, kind)
+ // assertEquals(1, details.count())
+ // with(details[0]) {
+ // assertEquals(NodeKind.Value, kind)
+ // assertEquals("[AnnotationTarget.FIELD, AnnotationTarget.CLASS, AnnotationTarget.FILE, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER]", name)
+ // }
+ // }
+ // }
+ // }
+ // }
+ //
+ // @Test fun deprecation() {
+ // verifyJavaPackageMember("testdata/java/deprecation.java", defaultModelConfig) { cls ->
+ // val fn = cls.members(NodeKind.Function).single()
+ // assertEquals("This should no longer be used", fn.deprecation!!.content.toTestString())
+ // }
+ // }
+ //
+ // @Test fun javaLangObject() {
+ // verifyJavaPackageMember("testdata/java/javaLangObject.java", defaultModelConfig) { cls ->
+ // val fn = cls.members(NodeKind.Function).single()
+ // assertEquals("Any", fn.detail(NodeKind.Type).name)
+ // }
+ // }
+
+ @Test
+ fun enumValues() {
+ inlineModelTest(
+ """
+ |enum E {
+ | Foo
+ |}
+ """
+ ) {
+ with((this / "java" / "E").cast<Enum>()) {
+ name equals "E"
+ entries counts 1
+
+ with((this / "Foo").cast<EnumEntry>()) {
+ name equals "Foo"
+ }
+ }
+ }
+ }
+
+
+ // todo
+ // @Test fun inheritorLinks() {
+ // verifyJavaPackageMember("testdata/java/InheritorLinks.java", defaultModelConfig) { cls ->
+ // val fooClass = cls.members.single { it.name == "Foo" }
+ // val inheritors = fooClass.references(RefKind.Inheritor)
+ // assertEquals(1, inheritors.size)
+ // }
+ // }
+} \ No newline at end of file
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..e19cc82d
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/PackagesTest.kt
@@ -0,0 +1,126 @@
+package model
+
+import org.jetbrains.dokka.model.Package
+import org.junit.Test
+import utils.AbstractModelTest
+
+class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "packages") {
+
+ @Test
+ fun rootPackage() {
+ inlineModelTest(
+ """
+ |
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ with((this / "").cast<Package>()) {
+ name equals ""
+ children counts 0
+ }
+ }
+ }
+
+ @Test
+ fun simpleNamePackage() {
+ inlineModelTest(
+ """
+ |package simple
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ with((this / "simple").cast<Package>()) {
+ name equals "simple"
+ children counts 0
+ }
+ }
+ }
+
+ @Test
+ fun dottedNamePackage() {
+ inlineModelTest(
+ """
+ |package dot.name
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ with((this / "dot.name").cast<Package>()) {
+ 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<Package>()) {
+ name equals "dot.name"
+ children counts 0
+ }
+ with((this / "simple").cast<Package>()) {
+ 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<Package>()) {
+ name equals "simple"
+ children counts 0
+ }
+ }
+ }
+
+ @Test
+ fun classAtPackageLevel() {
+ inlineModelTest(
+ """
+ |package simple.name
+ |
+ |class Foo {}
+ """.trimIndent(),
+ prependPackage = false
+ ) {
+ with((this / "simple.name").cast<Package>()) {
+ 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..633796e7
--- /dev/null
+++ b/plugins/base/src/test/kotlin/model/PropertyTest.kt
@@ -0,0 +1,176 @@
+package model
+
+import org.jetbrains.dokka.model.Package
+import org.jetbrains.dokka.model.Property
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.junit.Test
+import utils.AbstractModelTest
+import utils.assertNotNull
+
+class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "property") {
+
+ @Test
+ fun valueProperty() {
+ inlineModelTest(
+ """
+ |val property = "test""""
+ ) {
+ with((this / "property" / "property").cast<Property>()) {
+ name equals "property"
+ children counts 0
+ with(getter.assertNotNull("Getter")) {
+ type.constructorFqName equals "kotlin.String"
+ }
+ type.constructorFqName equals "kotlin.String"
+ }
+ }
+ }
+
+ @Test
+ fun variableProperty() {
+ inlineModelTest(
+ """
+ |var property = "test"
+ """
+ ) {
+ with((this / "property" / "property").cast<Property>()) {
+ name equals "property"
+ children counts 0
+ setter.assertNotNull("Setter")
+ with(getter.assertNotNull("Getter")) {
+ type.constructorFqName equals "kotlin.String"
+ }
+ type.constructorFqName equals "kotlin.String"
+ }
+ }
+ }
+
+ @Test
+ fun valuePropertyWithGetter() {
+ inlineModelTest(
+ """
+ |val property: String
+ | get() = "test"
+ """
+ ) {
+ with((this / "property" / "property").cast<Property>()) {
+ name equals "property"
+ children counts 0
+ with(getter.assertNotNull("Getter")) {
+ type.constructorFqName equals "kotlin.String"
+ }
+ type.constructorFqName equals "kotlin.String"
+ }
+ }
+ }
+
+ @Test
+ fun variablePropertyWithAccessors() {
+ inlineModelTest(
+ """
+ |var property: String
+ | get() = "test"
+ | set(value) {}
+ """
+ ) {
+ with((this / "property" / "property").cast<Property>()) {
+ name equals "property"
+ children counts 0
+ setter.assertNotNull("Setter")
+ with(getter.assertNotNull("Getter")) {
+ type.constructorFqName equals "kotlin.String"
+ }
+ visibility.values allEquals Visibilities.PUBLIC
+ }
+ }
+ }
+
+ @Test
+ fun propertyWithReceiver() {
+ inlineModelTest(
+ """
+ |val String.property: Int
+ | get() = size() * 2
+ """
+ ) {
+ with((this / "property" / "property").cast<Property>()) {
+ name equals "property"
+ children counts 0
+ with(receiver.assertNotNull("property receiver")) {
+ name equals null
+ type.constructorFqName equals "kotlin.String"
+ }
+ with(getter.assertNotNull("Getter")) {
+ type.constructorFqName equals "kotlin.Int"
+ }
+ visibility.values allEquals Visibilities.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<Package>()) {
+ with((this / "Foo" / "property").cast<Property>()) {
+ name equals "property"
+ children counts 0
+ with(getter.assertNotNull("Getter")) {
+ type.constructorFqName equals "kotlin.Int"
+ }
+ }
+ with((this / "Bar" / "property").cast<Property>()) {
+ name equals "property"
+ children counts 0
+ with(getter.assertNotNull("Getter")) {
+ type.constructorFqName equals "kotlin.Int"
+ }
+ }
+ }
+ }
+ }
+
+ // todo
+// @Test fun sinceKotlin() {
+// checkSourceExistsAndVerifyModel("testdata/properties/sinceKotlin.kt", defaultModelConfig) { model ->
+// with(model.members.single().members.single()) {
+// assertEquals("1.1", sinceKotlin)
+// }
+// }
+// }
+//}
+//
+//class JSPropertyTest: BasePropertyTest(Platform.js) {}
+//
+//class JVMPropertyTest : BasePropertyTest(Platform.jvm) {
+// @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)
+// }
+// }
+// }
+// }
+//
+//}
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/utils/ModelUtils.kt b/plugins/base/src/test/kotlin/utils/ModelUtils.kt
new file mode 100644
index 00000000..6893c65f
--- /dev/null
+++ b/plugins/base/src/test/kotlin/utils/ModelUtils.kt
@@ -0,0 +1,33 @@
+package utils
+
+import org.jetbrains.dokka.model.Module
+import org.jetbrains.dokka.model.doc.DocumentationNode
+import testApi.testRunner.AbstractCoreTest
+
+abstract class AbstractModelTest(val path: String? = null, val pkg: String) : ModelDSL(), AssertDSL {
+
+ fun inlineModelTest(
+ query: String,
+ platform: String = "jvm",
+ targetList: List<String> = listOf("jvm"),
+ prependPackage: Boolean = true,
+ block: Module.() -> Unit
+ ) {
+ val configuration = dokkaConfiguration {
+ passes {
+ pass {
+ sourceRoots = listOf("src/")
+ analysisPlatform = platform
+ targets = targetList
+ }
+ }
+ }
+ val prepend = path.let { p -> p?.let { "|$it\n" } ?: "" } + if(prependPackage) "|package $pkg" else ""
+
+ testInline(("$prepend\n$query").trim().trimIndent(), configuration) {
+ documentablesTransformationStage = block
+ }
+ }
+
+
+}
diff --git a/plugins/base/src/test/kotlin/utils/TestUtils.kt b/plugins/base/src/test/kotlin/utils/TestUtils.kt
new file mode 100644
index 00000000..641c68a2
--- /dev/null
+++ b/plugins/base/src/test/kotlin/utils/TestUtils.kt
@@ -0,0 +1,68 @@
+package utils
+
+import org.jetbrains.dokka.model.Class
+import org.jetbrains.dokka.model.Documentable
+import org.jetbrains.dokka.model.Function
+import org.jetbrains.dokka.model.Property
+import org.jetbrains.dokka.model.doc.*
+import testApi.testRunner.AbstractCoreTest
+import kotlin.reflect.KClass
+import kotlin.reflect.full.safeCast
+
+@DslMarker
+annotation class TestDSL
+
+@TestDSL
+abstract class ModelDSL : AbstractCoreTest() {
+ operator fun Documentable?.div(name: String): Documentable? =
+ this?.children?.find { it.name == name }
+
+ inline fun <reified T : Documentable> Documentable?.cast(): T =
+ (this as? T).assertNotNull()
+}
+
+@TestDSL
+interface AssertDSL {
+ infix fun Any?.equals(other: Any?) = this.assertEqual(other)
+ infix fun Collection<Any>?.allEquals(other: Any?) =
+ this?.also { c -> c.forEach { it equals other } } ?: run { assert(false) { "Collection is empty" } }
+
+ infix fun <T> Collection<T>?.counts(n: Int) = this.orEmpty().assertCount(n)
+
+ infix fun <T> T?.notNull(name: String): T = this.assertNotNull(name)
+
+ fun <T> Collection<T>.assertCount(n: Int, prefix: String = "") =
+ assert(count() == n) { "${prefix}Expected $n, got ${count()}" }
+
+ fun <T> T?.assertEqual(expected: T, prefix: String = "") = assert(this == expected) {
+ "${prefix}Expected $expected, got $this"
+ }
+}
+
+inline fun <reified T : Any> Any?.assertIsInstance(name: String): T =
+ this.let { it as? T } ?: throw AssertionError("$name should not be null")
+
+fun List<DocumentationNode>.commentsToString(): String =
+ this.flatMap { it.children }.joinToString(separator = "\n") { it.root.docTagSummary() }
+
+fun TagWrapper.text(): String = when (val t = this) {
+ is NamedTagWrapper -> "${t.name}: [${t.root.text()}]"
+ else -> t.root.text()
+}
+
+fun DocTag.text(): String = when (val t = this) {
+ is Text -> t.body
+ is Code -> t.children.joinToString("\n") { it.text() }
+ is P -> t.children.joinToString(separator = "\n") { it.text() }
+ else -> t.toString()
+}
+
+fun <T : Documentable> T?.comments(): String = docs().map { it.text() }
+ .joinToString(separator = "\n") { it }
+
+fun <T> T?.assertNotNull(name: String = ""): T = this ?: throw AssertionError("$name should not be null")
+
+fun <T : Documentable> T?.docs() = this?.documentation.orEmpty().values.flatMap { it.children }
+
+val Class.supers
+ get() = supertypes.flatMap{it.component2()} \ No newline at end of file