1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.metalava.model.testsuite.documentation
18 
19 import com.android.tools.metalava.model.ItemDocumentation
20 import com.android.tools.metalava.model.provider.InputFormat
21 import com.android.tools.metalava.model.testsuite.BaseModelTest
22 import com.android.tools.metalava.testing.java
23 import com.android.tools.metalava.testing.kotlin
24 import java.util.EnumSet
25 import kotlin.test.assertEquals
26 import org.junit.Rule
27 import org.junit.Test
28 import org.junit.rules.TestRule
29 import org.junit.runner.Description
30 import org.junit.runners.Parameterized
31 import org.junit.runners.model.Statement
32 
33 /** Common tests for implementations of [ItemDocumentation] */
34 class CommonParameterizedDocumentationTest : BaseModelTest() {
35 
36     @Parameterized.Parameter(0) lateinit var params: TestParams
37 
38     data class TestParams(
39         val name: String,
40         val inputFormats: Set<InputFormat> = EnumSet.allOf(InputFormat::class.java),
41         val imports: List<String> = emptyList(),
42         val comment: String,
43         val expectedText: String = comment,
44         val expectedFullyQualified: String = expectedText,
45     ) {
skipForInputFormatnull46         fun skipForInputFormat(inputFormat: InputFormat?) = inputFormat !in inputFormats
47 
48         override fun toString(): String {
49             return name
50         }
51     }
52 
53     companion object {
54         private val javaOnly = EnumSet.of(InputFormat.JAVA)
55         private val kotlinOnly = EnumSet.of(InputFormat.KOTLIN)
56 
57         private val params =
58             listOf(
59                 TestParams(
60                     name = "inline comment",
61                     comment = "// inline comment",
62                     expectedText = "",
63                 ),
64                 TestParams(
65                     name = "inline comment - link tag",
66                     comment = "// inline comment - {@link}",
67                     expectedText = "",
68                 ),
69                 TestParams(
70                     name = "block comment",
71                     comment = "/* block comment */",
72                     expectedText = "",
73                 ),
74                 TestParams(
75                     name = "block comment - link tag",
76                     comment = "/* block comment - {@link} */",
77                     expectedText = "",
78                 ),
79                 TestParams(
80                     name = "doc comment - plain text",
81                     comment = "/** doc comment */",
82                 ),
83                 TestParams(
84                     name = "doc comment with link - java",
85                     inputFormats = javaOnly,
86                     imports = listOf("java.util.List"),
87                     comment = "/** {@link List} */",
88                     expectedFullyQualified = "/** {@link java.util.List List} */",
89                 ),
90                 TestParams(
91                     name = "doc comment with link - kotlin",
92                     inputFormats = kotlinOnly,
93                     imports = listOf("kotlin.random.Random"),
94                     comment = "/** {@link Random} */",
95                     // Doc comments in Kotlin are not fully qualified as that is only needed for
96                     // java stubs due to an issue with doclava. Kotlin stubs are not supported.
97                 ),
98             )
99 
paramsnull100         @JvmStatic @Parameterized.Parameters fun params() = params
101     }
102 
103     /**
104      * [TestRule] that ignores tests whose [TestParams] are not suitable for the current
105      * [inputFormat].
106      */
107     @get:Rule
108     val filter =
109         object : TestRule {
110             override fun apply(base: Statement, description: Description): Statement {
111                 return object : Statement() {
112                     override fun evaluate() {
113                         if (params.skipForInputFormat(inputFormat)) return
114                         base.evaluate()
115                     }
116                 }
117             }
118         }
119 
importsnull120     private fun imports(): String =
121         if (params.imports.isEmpty()) ""
122         else {
123             val terminator = if (inputFormat == InputFormat.JAVA) ";" else "\n"
124             params.imports.joinToString { "                    import $it$terminator" }
125         }
126 
127     @Test
Documentation textnull128     fun `Documentation text`() {
129         runSourceCodebaseTest(
130             java(
131                 """
132                     package test.pkg;
133                     ${imports()}
134                     ${params.comment}
135                     public class Test {
136                     }
137                 """
138             ),
139             kotlin(
140                 """
141                     package test.pkg
142                     ${imports()}
143 
144                     ${params.comment}
145                     class Test
146                 """
147             )
148         ) {
149             val testClass = codebase.assertClass("test.pkg.Test")
150             val documentation = testClass.documentation
151 
152             assertEquals(params.expectedText, documentation.text)
153         }
154     }
155 
156     @Test
Documentation fully qualifiednull157     fun `Documentation fully qualified`() {
158         runSourceCodebaseTest(
159             java(
160                 """
161                     package test.pkg;
162                     ${imports()}
163 
164                     ${params.comment}
165                     public class Test {
166                     }
167                 """
168             ),
169             kotlin(
170                 """
171                     package test.pkg
172                     ${imports()}
173 
174                     ${params.comment}
175                     class Test
176                 """
177             )
178         ) {
179             val testClass = codebase.assertClass("test.pkg.Test")
180             val documentation = testClass.documentation
181 
182             assertEquals(params.expectedFullyQualified, documentation.fullyQualifiedDocumentation())
183         }
184     }
185 }
186