1 /* <lambda>null2 * 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 18 19 import com.android.tools.lint.checks.infrastructure.TestFiles 20 import com.android.tools.metalava.cli.common.BaseCommandTest 21 import com.android.tools.metalava.cli.common.COMMON_BASELINE_OPTIONS_HELP 22 import com.android.tools.metalava.cli.common.CommonOptions 23 import com.android.tools.metalava.cli.common.ISSUE_REPORTING_OPTIONS_HELP 24 import com.android.tools.metalava.cli.common.SOURCE_OPTIONS_HELP 25 import com.android.tools.metalava.cli.compatibility.COMPATIBILITY_CHECK_OPTIONS_HELP 26 import com.android.tools.metalava.cli.lint.API_LINT_OPTIONS_HELP 27 import com.android.tools.metalava.cli.signature.SIGNATURE_FORMAT_OPTIONS_HELP 28 import com.android.tools.metalava.model.source.DEFAULT_JAVA_LANGUAGE_LEVEL 29 import com.android.tools.metalava.model.source.DEFAULT_KOTLIN_LANGUAGE_LEVEL 30 import com.android.tools.metalava.reporter.Issues 31 import java.io.File 32 import java.util.Locale 33 import kotlin.test.assertEquals 34 import org.junit.Assert 35 import org.junit.Test 36 37 class MainCommandTest : 38 BaseCommandTest<MainCommand>({ executionEnvironment -> 39 MainCommand( 40 commonOptions = CommonOptions(), 41 executionEnvironment = executionEnvironment, 42 ) 43 }) { 44 45 private val EXPECTED_HELP = 46 """ 47 Usage: metalava main [options] [flags]... 48 49 The default sub-command that is run if no sub-command is specified. 50 51 Options: 52 --api-class-resolution [api|api:classpath] 53 Determines how class resolution is performed when loading API signature 54 files. Any classes that cannot be found will be treated as empty.", 55 56 api - will only look for classes in the API signature files. 57 58 api:classpath (default) - will look for classes in the API signature files 59 first and then in the classpath. 60 --suppress-compatibility-meta-annotation <meta-annotation class> 61 Suppress compatibility checks for any elements within the scope of an 62 annotation which is itself annotated with the given meta-annotation. 63 --manifest <file> A manifest file, used to check permissions to cross check APIs and retrieve 64 min_sdk_version. (default: no manifest) 65 --hide-sdk-extensions-newer-than INT Ignore SDK extensions version INT and above. Used to exclude finalized but 66 not yet released SDK extensions. 67 --typedefs-in-signatures [none|ref|inline] 68 Whether to include typedef annotations in signature files. 69 70 none (default) - will not include typedef annotations in signature. 71 72 ref - will include just a reference to the typedef class, which is not 73 itself part of the API and is not included as a class 74 75 inline - will include the constants themselves into each usage site 76 -h, --help Show this message and exit 77 78 $SOURCE_OPTIONS_HELP 79 80 $ISSUE_REPORTING_OPTIONS_HELP 81 82 $COMMON_BASELINE_OPTIONS_HELP 83 84 $GENERAL_REPORTING_OPTIONS_HELP 85 86 $API_SELECTION_OPTIONS_HELP 87 88 $API_LINT_OPTIONS_HELP 89 90 $COMPATIBILITY_CHECK_OPTIONS_HELP 91 92 Signature File Output: 93 94 Options controlling the signature file output. The format of the generated file is determined by the options in the 95 `Signature Format Output` section. 96 97 --api <file> Output file into which the API signature will be generated. If this is not 98 specified then no API signature file will be created. 99 --removed-api <file> Output file into which the API signatures for removed APIs will be 100 generated. If this is not specified then no removed API signature file will 101 be created. 102 103 $SIGNATURE_FORMAT_OPTIONS_HELP 104 105 $STUB_GENERATION_OPTIONS_HELP 106 107 Arguments: 108 flags See below. 109 110 111 API sources: 112 --source-files <files> 113 A comma separated list of source files to be parsed. Can also be @ followed 114 by a path to a text file containing paths to the full set of files to 115 parse. 116 --classpath <paths> 117 One or more directories or jars (separated by `:`) containing classes that 118 should be on the classpath when parsing the source files 119 --merge-qualifier-annotations <file> 120 An external annotations file to merge and overlay the sources, or a 121 directory of such files. Should be used for annotations intended for 122 inclusion in the API to be written out, e.g. nullability. Formats supported 123 are: IntelliJ's external annotations database format, .jar or .zip files 124 containing those, Android signature files, and Java stub files. 125 --merge-inclusion-annotations <file> 126 An external annotations file to merge and overlay the sources, or a 127 directory of such files. Should be used for annotations which determine 128 inclusion in the API to be written out, i.e. show and hide. The only format 129 supported is Java stub files. 130 --validate-nullability-from-merged-stubs 131 Triggers validation of nullability annotations for any class where 132 --merge-qualifier-annotations includes a Java stub file. 133 --validate-nullability-from-list 134 Triggers validation of nullability annotations for any class listed in the 135 named file (one top-level class per line, # prefix for comment line). 136 --nullability-warnings-txt <file> 137 Specifies where to write warnings encountered during validation of 138 nullability annotations. (Does not trigger validation by itself.) 139 --nullability-errors-non-fatal 140 Specifies that errors encountered during validation of nullability 141 annotations should not be treated as errors. They will be written out to 142 the file specified in --nullability-warnings-txt instead. 143 --hide-package <package> 144 Remove the given packages from the API even if they have not been marked 145 with @hide 146 --hide-annotation <annotation class> 147 Treat any elements annotated with the given annotation as hidden 148 --show-unannotated 149 Include un-annotated public APIs in the signature file as well 150 --java-source <level> 151 Sets the source level for Java source files; default is ${DEFAULT_JAVA_LANGUAGE_LEVEL}. 152 --kotlin-source <level> 153 Sets the source level for Kotlin source files; default is ${DEFAULT_KOTLIN_LANGUAGE_LEVEL}. 154 --sdk-home <dir> 155 If set, locate the `android.jar` file from the given Android SDK 156 --compile-sdk-version <api> 157 Use the given API level 158 --jdk-home <dir> 159 If set, add the Java APIs from the given JDK to the classpath 160 --stub-packages <package-list> 161 List of packages (separated by :) which will be used to filter out 162 irrelevant code. If specified, only code in these packages will be included 163 in signature files, stubs, etc. (This is not limited to just the stubs; the 164 name is historical.) You can also use ".*" at the end to match subpackages, 165 so `foo.*` will match both `foo` and `foo.bar`. 166 --subtract-api <api file> 167 Subtracts the API in the given signature or jar file from the current API 168 being emitted via --api, --stubs, --doc-stubs, etc. Note that the 169 subtraction only applies to classes; it does not subtract members. 170 --ignore-classes-on-classpath 171 Prevents references to classes on the classpath from being added to the 172 generated stub files. 173 --ignore-comments 174 Ignore any comments in source files. 175 176 177 Extracting Signature Files: 178 --dex-api <file> 179 Generate a DEX signature descriptor file listing the APIs 180 --proguard <file> 181 Write a ProGuard keep file for the API 182 --sdk-values <dir> 183 Write SDK values files to the given directory 184 185 186 Generating Stubs: 187 --doc-stubs <dir> 188 Generate documentation stub source files for the API. Documentation stub 189 files are similar to regular stub files, but there are some differences. 190 For example, in the stub files, we'll use special annotations like 191 @RecentlyNonNull instead of @NonNull to indicate that an element is 192 recently marked as non null, whereas in the documentation stubs we'll just 193 list this as @NonNull. Another difference is that @doconly elements are 194 included in documentation stubs, but not regular stubs, etc. 195 --kotlin-stubs 196 [CURRENTLY EXPERIMENTAL] If specified, stubs generated from Kotlin source 197 code will be written in Kotlin rather than the Java programming language. 198 --pass-through-annotation <annotation classes> 199 A comma separated list of fully qualified names of annotation classes that 200 must be passed through unchanged. 201 --exclude-annotation <annotation classes> 202 A comma separated list of fully qualified names of annotation classes that 203 must be stripped from metalava's outputs. 204 --enhance-documentation 205 Enhance documentation in various ways, for example auto-generating 206 documentation based on source annotations present in the code. This is 207 implied by --doc-stubs. 208 --exclude-documentation-from-stubs 209 Exclude element documentation (javadoc and kdoc) from the generated stubs. 210 (Copyright notices are not affected by this, they are always included. 211 Documentation stubs (--doc-stubs) are not affected.) 212 213 214 Diffs and Checks: 215 --migrate-nullness <api file> 216 Compare nullness information with the previous stable API and mark newly 217 annotated APIs as under migration. 218 219 220 Extracting Annotations: 221 --extract-annotations <zipfile> 222 Extracts source annotations from the source files and writes them into the 223 given zip file 224 --include-source-retention 225 If true, include source-retention annotations in the stub files. Does not 226 apply to signature files. Source retention annotations are extracted into 227 the external annotations files instead. 228 229 230 Injecting API Levels: 231 --apply-api-levels <api-versions.xml> 232 Reads an XML file containing API level descriptions and merges the 233 information into the documentation 234 235 236 Extracting API Levels: 237 --generate-api-levels <xmlfile> 238 Reads android.jar SDK files and generates an XML file recording the API 239 level for each class, method and field 240 --remove-missing-class-references-in-api-levels 241 Removes references to missing classes when generating the API levels XML 242 file. This can happen when generating the XML file for the non-updatable 243 portions of the module-lib sdk, as those non-updatable portions can 244 reference classes that are part of an updatable apex. 245 --android-jar-pattern <pattern> 246 Patterns to use to locate Android JAR files. The default is 247 ${"$"}ANDROID_HOME/platforms/android-%/android.jar. 248 --first-version 249 Sets the first API level to generate an API database from; usually 1 250 --current-version 251 Sets the current API level of the current source code 252 --current-codename 253 Sets the code name for the current source code 254 --current-jar 255 Points to the current API jar, if any 256 --sdk-extensions-root 257 Points to root of prebuilt extension SDK jars, if any. This directory is 258 expected to contain snapshots of historical extension SDK versions in the 259 form of stub jars. The paths should be on the format 260 "<int>/public/<module-name>.jar", where <int> corresponds to the extension 261 SDK version, and <module-name> to the name of the mainline module. 262 --sdk-extensions-info 263 Points to map of extension SDK APIs to include, if any. The file is a plain 264 text file and describes, per extension SDK, what APIs from that extension 265 to include in the file created via --generate-api-levels. The format of 266 each line is one of the following: "<module-name> <pattern> <ext-name> 267 [<ext-name> [...]]", where <module-name> is the name of the mainline module 268 this line refers to, <pattern> is a common Java name prefix of the APIs 269 this line refers to, and <ext-name> is a list of extension SDK names in 270 which these SDKs first appeared, or "<ext-name> <ext-id> <type>", where 271 <ext-name> is the name of an SDK, <ext-id> its numerical ID and <type> is 272 one of "platform" (the Android platform SDK), "platform-ext" (an extension 273 to the Android platform SDK), "standalone" (a separate SDK). Fields are 274 separated by whitespace. A mainline module may be listed multiple times. 275 The special pattern "*" refers to all APIs in the given mainline module. 276 Lines beginning with # are comments. 277 278 279 Generating API version history: 280 --generate-api-version-history <jsonfile> 281 Reads API signature files and generates a JSON file recording the API 282 version each class, method, and field was added in and (if applicable) 283 deprecated in. Required to generate API version JSON. 284 --api-version-signature-files <files> 285 An ordered list of text API signature files. The oldest API version should 286 be first, the newest last. This should not include a signature file for the 287 current API version, which will be parsed from the provided source files. 288 Not required to generate API version JSON if the current version is the 289 only version. 290 --api-version-names <strings> 291 An ordered list of strings with the names to use for the API versions from 292 --api-version-signature-files, and the name of the current API version. 293 Required to generate API version JSON. 294 295 296 Environment Variables: 297 METALAVA_DUMP_ARGV 298 Set to true to have metalava emit all the arguments it was invoked with. 299 Helpful when debugging or reproducing under a debugger what the build 300 system is doing. 301 METALAVA_PREPEND_ARGS 302 One or more arguments (concatenated by space) to insert into the command 303 line, before the documentation flags. 304 METALAVA_APPEND_ARGS 305 One or more arguments (concatenated by space) to append to the end of the 306 command line, after the generate documentation flags. 307 """ 308 .trimIndent() 309 310 @Test Test helpnull311 fun `Test help`() { 312 commandTest { 313 args += listOf("main", "--help") 314 expectedStdout = EXPECTED_HELP 315 } 316 } 317 318 @Test Test invalid optionnull319 fun `Test invalid option`() { 320 commandTest { 321 args += listOf("main", "--blah-blah-blah") 322 expectedStderr = 323 """ 324 Aborting: Error: no such option: "--blah-blah-blah" 325 326 $EXPECTED_HELP 327 """ 328 .trimIndent() 329 } 330 } 331 332 @Test Test deprecated lowercase matching in issue configuration optionsnull333 fun `Test deprecated lowercase matching in issue configuration options`() { 334 // Temporarily set [options] as it is needed by the [ReporterOptions.reporter] when 335 // reporting [Issues.DEPRECATED_OPTION]. 336 @Suppress("DEPRECATION") 337 options = Options() 338 339 commandTest { 340 args += 341 listOf( 342 "main", 343 "--error", 344 Issues.DEPRECATED_OPTION.name, 345 "--hide", 346 Issues.ADDED_FINAL.name.lowercase(Locale.US), 347 ) 348 349 expectedStderr = 350 """ 351 error: Case-insensitive issue matching is deprecated, use --hide AddedFinal instead of --hide addedfinal [DeprecatedOption] 352 """ 353 .trimIndent() 354 355 verify { assertEquals(-1, exitCode, message = "exitCode") } 356 } 357 } 358 359 @Test Test for @filenull360 fun `Test for @file`() { 361 val dir = temporaryFolder.newFolder() 362 val files = (1..4).map { TestFiles.source("File$it.java", "File$it").createFile(dir) } 363 val fileList = 364 TestFiles.source( 365 "files.lst", 366 """ 367 ${files[0]} 368 ${files[1]} ${files[2]} 369 ${files[3]} 370 """ 371 .trimIndent() 372 ) 373 374 val file = fileList.createFile(dir) 375 376 commandTest { 377 args += listOf("main", "@$file") 378 379 verify { 380 fun normalize(f: File): String = f.relativeTo(dir).path 381 Assert.assertEquals( 382 files.map { normalize(it) }, 383 command.optionGroup.sources.map { normalize(it) } 384 ) 385 } 386 } 387 } 388 } 389