1 /*
2 * Copyright (C) 2023 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
18
19 import com.google.common.truth.Truth.assertThat
20 import kotlin.test.assertEquals
21 import kotlin.test.assertIs
22 import kotlin.test.assertNotNull
23
24 interface Assertions {
25
26 /** Get the class from the [Codebase], failing if it does not exist. */
assertClassnull27 fun Codebase.assertClass(qualifiedName: String): ClassItem {
28 val classItem = findClass(qualifiedName)
29 assertNotNull(classItem, message = "Expected $qualifiedName to be defined")
30 return classItem
31 }
32
33 /** Resolve the class from the [Codebase], failing if it does not exist. */
Codebasenull34 fun Codebase.assertResolvedClass(qualifiedName: String): ClassItem {
35 val classItem = resolveClass(qualifiedName)
36 assertNotNull(classItem, message = "Expected $qualifiedName to be defined")
37 return classItem
38 }
39
40 /** Get the package from the [Codebase], failing if it does not exist. */
assertPackagenull41 fun Codebase.assertPackage(pkgName: String): PackageItem {
42 val packageItem = findPackage(pkgName)
43 assertNotNull(packageItem, message = "Expected $pkgName to be defined")
44 return packageItem
45 }
46
47 /** Get the field from the [ClassItem], failing if it does not exist. */
ClassItemnull48 fun ClassItem.assertField(fieldName: String): FieldItem {
49 val fieldItem = findField(fieldName)
50 assertNotNull(fieldItem, message = "Expected $fieldName to be defined")
51 return fieldItem
52 }
53
54 /** Get the method from the [ClassItem], failing if it does not exist. */
ClassItemnull55 fun ClassItem.assertMethod(methodName: String, parameters: String): MethodItem {
56 val methodItem = findMethod(methodName, parameters)
57 assertNotNull(methodItem, message = "Expected $methodName($parameters) to be defined")
58 return methodItem
59 }
60
61 /** Get the constructor from the [ClassItem], failing if it does not exist. */
ClassItemnull62 fun ClassItem.assertConstructor(parameters: String): ConstructorItem {
63 val methodItem = findMethod(simpleName(), parameters)
64 assertNotNull(methodItem, message = "Expected ${simpleName()}($parameters) to be defined")
65 return assertIs(methodItem)
66 }
67
68 /** Get the property from the [ClassItem], failing if it does not exist. */
ClassItemnull69 fun ClassItem.assertProperty(propertyName: String): PropertyItem {
70 val propertyItem = properties().firstOrNull { it.name() == propertyName }
71 assertNotNull(propertyItem, message = "Expected $propertyName to be defined")
72 return propertyItem
73 }
74
75 /** Get the annotation from the [Item], failing if it does not exist. */
Itemnull76 fun Item.assertAnnotation(qualifiedName: String): AnnotationItem {
77 val annoItem = modifiers.findAnnotation(qualifiedName)
78 assertNotNull(annoItem, message = "Expected item to be annotated with ($qualifiedName)")
79 return assertIs(annoItem)
80 }
81
82 /**
83 * Check the [Item.originallyDeprecated] and [Item.effectivelyDeprecated] are
84 * [explicitlyDeprecated] and [implicitlyDeprecated] respectively.
85 */
Itemnull86 private fun Item.assertDeprecatedStatus(
87 explicitlyDeprecated: Boolean,
88 implicitlyDeprecated: Boolean = explicitlyDeprecated,
89 ) {
90 assertEquals(
91 explicitlyDeprecated,
92 originallyDeprecated,
93 message = "$this: originallyDeprecated"
94 )
95 assertEquals(
96 implicitlyDeprecated,
97 effectivelyDeprecated,
98 message = "$this: effectivelyDeprecated"
99 )
100 }
101
102 /** Make sure that the item is not deprecated explicitly, or implicitly. */
Itemnull103 fun Item.assertNotDeprecated() {
104 assertDeprecatedStatus(explicitlyDeprecated = false)
105 }
106
107 /** Make sure that the item is explicitly deprecated. */
assertExplicitlyDeprecatednull108 fun Item.assertExplicitlyDeprecated() {
109 assertDeprecatedStatus(explicitlyDeprecated = true)
110 }
111
112 /**
113 * Make sure that the item is implicitly deprecated, this will fail if the item is explicitly
114 * deprecated.
115 */
Itemnull116 fun Item.assertImplicitlyDeprecated() {
117 assertDeprecatedStatus(
118 explicitlyDeprecated = false,
119 implicitlyDeprecated = true,
120 )
121 }
122
123 /**
124 * Create a Kotlin like method description. It uses Kotlin structure for a method and Kotlin
125 * style nulls but not Kotlin types.
126 */
<lambda>null127 fun MethodItem.kotlinLikeDescription(): String = buildString {
128 if (isConstructor()) {
129 append("constructor ")
130 } else {
131 append("fun ")
132 }
133 append(name())
134 append("(")
135 parameters().joinTo(this) {
136 "${it.name()}: ${it.type().toTypeString(kotlinStyleNulls = true)}"
137 }
138 append("): ")
139 append(returnType().toTypeString(kotlinStyleNulls = true))
140 }
141
142 /** Get the list of fully qualified annotation names associated with the [TypeItem]. */
TypeItemnull143 fun TypeItem.annotationNames(): List<String?> {
144 return modifiers.annotations().map { it.qualifiedName }
145 }
146
147 /** Get the list of fully qualified annotation names associated with the [Item]. */
Itemnull148 fun Item.annotationNames(): List<String?> {
149 return modifiers.annotations().map { it.qualifiedName }
150 }
151
152 /**
153 * Check to make sure that this [TypeItem] is actually a [VariableTypeItem] whose
154 * [VariableTypeItem.asTypeParameter] references the supplied [typeParameter] and then run the
155 * optional lambda on the [VariableTypeItem].
156 */
assertReferencesTypeParameternull157 fun TypeItem.assertReferencesTypeParameter(
158 typeParameter: TypeParameterItem,
159 body: (VariableTypeItem.() -> Unit)? = null
160 ) {
161 assertVariableTypeItem {
162 assertThat(asTypeParameter).isSameInstanceAs(typeParameter)
163 if (body != null) this.body()
164 }
165 }
166
167 /**
168 * Check to make sure that this nullable [TypeItem] is actually a [TypeItem] and then run the
169 * optional lambda on the [TypeItem].
170 */
assertNotNullTypeItemnull171 fun <T : TypeItem> T?.assertNotNullTypeItem(body: (T.() -> Unit)? = null) {
172 assertThat(this).isNotNull()
173 if (body != null) this?.body()
174 }
175
176 /**
177 * Check to make sure that this [TypeItem] is actually a [ArrayTypeItem] and then run the
178 * optional lambda on the [ArrayTypeItem].
179 */
assertArrayTypeItemnull180 fun TypeItem?.assertArrayTypeItem(body: (ArrayTypeItem.() -> Unit)? = null) {
181 assertIsInstanceOf(body ?: {})
182 }
183
184 /**
185 * Check to make sure that this [TypeItem] is actually a [ClassTypeItem] and then run the
186 * optional lambda on the [ClassTypeItem].
187 */
assertClassTypeItemnull188 fun TypeItem?.assertClassTypeItem(body: (ClassTypeItem.() -> Unit)? = null) {
189 assertIsInstanceOf(body ?: {})
190 }
191
192 /**
193 * Check to make sure that this [TypeItem] is actually a [PrimitiveTypeItem] and then run the
194 * optional lambda on the [PrimitiveTypeItem].
195 */
assertPrimitiveTypeItemnull196 fun TypeItem?.assertPrimitiveTypeItem(body: (PrimitiveTypeItem.() -> Unit)? = null) {
197 assertIsInstanceOf(body ?: {})
198 }
199
200 /**
201 * Check to make sure that this [TypeItem] is actually a [LambdaTypeItem] and then run the
202 * optional lambda on the [LambdaTypeItem].
203 */
assertLambdaTypeItemnull204 fun TypeItem?.assertLambdaTypeItem(body: (LambdaTypeItem.() -> Unit)? = null) {
205 assertIsInstanceOf(body ?: {})
206 }
207
208 /**
209 * Check to make sure that this [TypeItem] is actually a [VariableTypeItem] and then run the
210 * optional lambda on the [VariableTypeItem].
211 */
assertVariableTypeItemnull212 fun TypeItem?.assertVariableTypeItem(body: (VariableTypeItem.() -> Unit)? = null) {
213 assertIsInstanceOf(body ?: {})
214 }
215
216 /**
217 * Check to make sure that this [TypeItem] is actually a [WildcardTypeItem] and then run the
218 * optional lambda on the [WildcardTypeItem].
219 */
assertWildcardItemnull220 fun TypeItem?.assertWildcardItem(body: (WildcardTypeItem.() -> Unit)? = null) {
221 assertIsInstanceOf(body ?: {})
222 }
223 }
224
assertIsInstanceOfnull225 private inline fun <reified T> Any?.assertIsInstanceOf(body: (T).() -> Unit) {
226 assertThat(this).isInstanceOf(T::class.java)
227 (this as T).body()
228 }
229