diff options
| -rw-r--r-- | plugins/base/src/test/kotlin/issues/IssuesTest.kt | 67 | ||||
| -rw-r--r-- | plugins/base/src/test/kotlin/model/ClassesTest.kt | 448 | ||||
| -rw-r--r-- | plugins/base/src/test/kotlin/model/CommentTest.kt | 332 | ||||
| -rw-r--r-- | plugins/base/src/test/kotlin/model/FunctionsTest.kt | 315 | ||||
| -rw-r--r-- | plugins/base/src/test/kotlin/model/JavaTest.kt | 367 | ||||
| -rw-r--r-- | plugins/base/src/test/kotlin/model/PackagesTest.kt | 126 | ||||
| -rw-r--r-- | plugins/base/src/test/kotlin/model/PropertyTest.kt | 176 | ||||
| -rw-r--r-- | plugins/base/src/test/kotlin/utils/ModelUtils.kt | 33 | ||||
| -rw-r--r-- | plugins/base/src/test/kotlin/utils/TestUtils.kt | 68 | ||||
| -rw-r--r-- | testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt | 8 |
10 files changed, 1935 insertions, 5 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 } |
