blob: 80021f6df8c3f42567c7c9483e5e34502b09842f [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.devsite.renderer.converters
import com.google.common.truth.Truth.assertThat
import com.google.devsite.components.pages.Classlike
import com.google.devsite.components.pages.DevsitePage
import com.google.devsite.components.symbols.SymbolSummary
import com.google.devsite.components.table.SingleColumnSummaryItem
import com.google.devsite.components.table.SummaryList
import com.google.devsite.renderer.Language
import com.google.devsite.renderer.converters.testing.content
import com.google.devsite.renderer.converters.testing.functionSummary
import com.google.devsite.renderer.converters.testing.item
import com.google.devsite.renderer.converters.testing.items
import com.google.devsite.renderer.converters.testing.link
import com.google.devsite.renderer.converters.testing.name
import com.google.devsite.renderer.converters.testing.title
import com.google.devsite.renderer.impl.DocumentablesHolder
import com.google.devsite.testing.ConverterTestBase
import kotlinx.coroutines.runBlocking
import org.jetbrains.dokka.model.DModule
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
internal class ClasslikeDocumentableConverterTest(
private val language: Language
) : ConverterTestBase(language) {
@Test
fun `Classlike creates components with correct title`() {
val page = """
|class Foo
""".render().page()
assertThat(page.data.title).isEqualTo("Foo")
}
@Test
fun `Classlike creates components with correct path`() {
val page = """
|class Foo
""".render().page()
assertThat(page.data.path).isEqualTo("androidx/example/Foo.html")
}
@Test
fun `Classlike creates components with correct book path`() {
val page = """
|class Foo
""".render().page()
assertPath(page.data.bookPath, "androidx/_book.yaml")
}
@Test
fun `Empty classlike has no symbols`() {
val page = """
|interface Foo
""".render().page()
val classlike = page.content<Classlike>()
for ((summary, symbol) in classlike.data.symbolTypes) {
assertThat(summary.hasContent()).isFalse()
assertThat(symbol.symbols).isEmpty()
}
}
@Test
fun `Public function gets documented`() {
val page = """
|class Foo {
| fun foo() = Unit
|}
""".render().page()
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Public functions", "Public methods")
assertThat(summary.item().functionSummary().name()).isEqualTo("foo")
}
@Test
fun `@jvmName functions get documented and sorted by correct name`() {
val page = """
|class Foo {
| @JvmName("bar")
| fun foo() = Unit
|
| @JvmName("aar")
| fun zoo() = Unit
|}
""".render().page()
javaOnly {
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Public functions", "Public methods")
assertThat(summary.items().first().functionSummary().name()).isEqualTo("aar")
assertThat(summary.items().last().functionSummary().name()).isEqualTo("bar")
}
kotlinOnly {
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Public functions", "Public methods")
assertThat(summary.items().first().functionSummary().name()).isEqualTo("foo")
assertThat(summary.items().last().functionSummary().name()).isEqualTo("zoo")
}
}
@Test
fun `@JvmSynthetic methods are not documented in java`() {
val page = """
|class Foo {
| fun foo() = Unit
|
| @JvmSynthetic
| fun zoo() = Unit
|}
""".render().page()
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Public functions", "Public methods")
javaOnly {
assertThat(summary.items().size).isEqualTo(1)
}
kotlinOnly {
assertThat(summary.items().size).isEqualTo(2)
}
}
@Ignore // TODO(b/165112358): foo doesn't show up in the dokka model
@Test
fun `Protected function gets documented`() {
val page = """
|abstract class Foo {
| protected open fun foo() = Unit
|}
""".render().page()
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Protected functions", "Protected methods")
assertThat(summary.item().functionSummary().name()).isEqualTo("foo")
}
@Test
fun `Public property gets documented`() {
val page = """
|class Foo {
| val foo = Unit
|}
""".render().page()
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Public properties", "Public fields")
assertThat(summary.item().functionSummary().name()).isEqualTo("foo")
}
@Ignore // TODO(b/165112358): foo doesn't show up in the dokka model
@Test
fun `Protected property gets documented`() {
val page = """
|abstract class Foo {
| protected open val foo = Unit
|}
""".render().page()
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Protected properties", "Protected fields")
assertThat(summary.item().functionSummary().name()).isEqualTo("foo")
}
@Test
fun `Public constructor gets documented`() {
val page = """
|class Foo
""".render().page()
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Public constructors")
assertThat(summary.constructor().name()).isEqualTo("Foo")
}
@Ignore // TODO(b/165112358): foo doesn't show up in the dokka model
@Test
fun `Protected constructor gets documented`() {
val page = """
|open class Foo protected constructor()
""".render().page()
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Protected constructors")
assertThat(summary.constructor().name()).isEqualTo("Foo")
}
@Test
fun `Nested type gets documented`() {
val page = """
|class Foo {
| class Bar
|}
""".render().page()
val classlike = page.content<Classlike>()
val (summary) = classlike.symbolsFor("Nested types")
assertThat(summary.item().link().name).isEqualTo("Foo.Bar")
}
@Test
fun `Direct subclasses are found`() {
val page = """
|abstract class Foo
|open class C : B
|open class B : Foo
|open class A : Foo
""".render().page()
val classlike = page.content<Classlike>()
val subclasses = classlike.data.relatedSymbols.data.directSubclasses.items(2)
assertThat(subclasses.first().data.name).isEqualTo("A")
assertThat(subclasses.last().data.name).isEqualTo("B")
}
@Test
fun `Indirect subclasses are found`() {
val page = """
|abstract class Foo
|open class C : Foo
|open class B : C
|open class A : B
""".render().page()
val classlike = page.content<Classlike>()
val subclasses = classlike.data.relatedSymbols.data.indirectSubclasses.items(2)
assertThat(subclasses.first().data.name).isEqualTo("A")
assertThat(subclasses.last().data.name).isEqualTo("B")
}
@Test
fun `Class with root object as parent does not have hierarchy`() {
val page = """
|class Foo
""".render().page()
val classlike = page.content<Classlike>()
val parents = classlike.data.hierarchy.data.parents
assertThat(parents).isEmpty()
}
@Test
fun `Class with single parent has hierarchy with root object, parent, and itself`() {
val page = """
|abstract class Parent
|class Foo : Parent
""".render().page()
val classlike = page.content<Classlike>()
val parents = classlike.data.hierarchy.data.parents.items(3).toList()
javaOnly { assertThat(parents[0].data.name).isEqualTo("Object") }
kotlinOnly { assertThat(parents[0].data.name).isEqualTo("Any") }
assertThat(parents[1].data.name).isEqualTo("Parent")
assertThat(parents[2].data.name).isEqualTo("Foo")
}
@Test
fun `Class with multiple parents has hierarchy with root object and parents`() {
val page = """
|abstract class A
|abstract class B : A
|abstract class C : B
|class Foo : C
""".render().page()
val classlike = page.content<Classlike>()
val parents = classlike.data.hierarchy.data.parents.items(5).toList()
javaOnly { assertThat(parents[0].data.name).isEqualTo("Object") }
kotlinOnly { assertThat(parents[0].data.name).isEqualTo("Any") }
assertThat(parents[1].data.name).isEqualTo("A")
assertThat(parents[2].data.name).isEqualTo("B")
assertThat(parents[3].data.name).isEqualTo("C")
assertThat(parents[4].data.name).isEqualTo("Foo")
}
@Test
fun `Class signature appears with extends and implements`() {
val page = """
|interface A
|abstract class B
|class Foo : A, B
""".render().page()
val classlike = page.content<Classlike>()
assertThat(classlike.data.signature.data.type).isEqualTo("class")
assertThat(classlike.data.signature.data.extends.single().data.name).isEqualTo("B")
assertThat(classlike.data.signature.data.implements.single().data.name).isEqualTo("A")
}
private fun DModule.page(): DevsitePage {
val classlike = packages.single().classlikes.single { it.name() == "Foo" }
val holder = runBlocking { DocumentablesHolder(this@page, this) }
val converter = ClasslikeDocumentableConverter(language, classlike, pathProvider(), holder)
return runBlocking { converter.classlike() }
}
private fun Classlike.symbolsFor(
vararg types: String
) = data.symbolTypes.single { (summary, _) ->
summary.title() in types
}
private fun SummaryList.constructor() =
(data.items.item() as SingleColumnSummaryItem).data.description as SymbolSummary
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{0}")
fun data() = listOf(
arrayOf(Language.JAVA),
arrayOf(Language.KOTLIN)
)
}
}