1 /* 2 * Copyright (C) 2017 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.metalava.model.defaultConfiguration 20 import org.junit.Assert.assertEquals 21 import org.junit.Assert.assertFalse 22 import org.junit.Assert.assertTrue 23 import org.junit.Test 24 import java.io.File 25 import java.io.PrintWriter 26 import java.io.StringWriter 27 28 @Suppress("PrivatePropertyName") 29 class OptionsTest : DriverTest() { 30 private val DESCRIPTION = """ 31 $PROGRAM_NAME extracts metadata from source code to generate artifacts such as the signature files, the SDK stub files, 32 external annotations etc. 33 """.trimIndent() 34 35 private val FLAGS = """ 36 Usage: metalava <flags> 37 38 39 General: 40 --help 41 This message. 42 --version 43 Show the version of metalava. 44 --quiet 45 Only include vital output 46 --verbose 47 Include extra diagnostic output 48 --color 49 Attempt to colorize the output (defaults to true if ${"$"}TERM is xterm) 50 --no-color 51 Do not attempt to colorize the output 52 --no-docs 53 Cancel any other documentation flags supplied to metalava. This is here to 54 make it easier customize build system tasks. 55 --only-update-api 56 Cancel any other "action" flags other than generating signature files. This 57 is here to make it easier customize build system tasks, particularly for 58 the "make update-api" task. 59 --only-check-api 60 Cancel any other "action" flags other than checking signature files. This 61 is here to make it easier customize build system tasks, particularly for 62 the "make checkapi" task. 63 --repeat-errors-max <N> 64 When specified, repeat at most N errors before finishing. 65 66 67 API sources: 68 --source-files <files> 69 A comma separated list of source files to be parsed. Can also be @ followed 70 by a path to a text file containing paths to the full set of files to 71 parse. 72 --source-path <paths> 73 One or more directories (separated by `:`) containing source files (within 74 a package hierarchy). If --strict-input-files, --strict-input-files:warn, 75 or --strict-input-files:stack are used, files accessed under --source-path 76 that are not explicitly specified in --source-files are reported as 77 violations. 78 --classpath <paths> 79 One or more directories or jars (separated by `:`) containing classes that 80 should be on the classpath when parsing the source files 81 --merge-qualifier-annotations <file> 82 An external annotations file to merge and overlay the sources, or a 83 directory of such files. Should be used for annotations intended for 84 inclusion in the API to be written out, e.g. nullability. Formats supported 85 are: IntelliJ's external annotations database format, .jar or .zip files 86 containing those, Android signature files, and Java stub files. 87 --merge-inclusion-annotations <file> 88 An external annotations file to merge and overlay the sources, or a 89 directory of such files. Should be used for annotations which determine 90 inclusion in the API to be written out, i.e. show and hide. The only format 91 supported is Java stub files. 92 --validate-nullability-from-merged-stubs 93 Triggers validation of nullability annotations for any class where 94 --merge-qualifier-annotations includes a Java stub file. 95 --validate-nullability-from-list 96 Triggers validation of nullability annotations for any class listed in the 97 named file (one top-level class per line, # prefix for comment line). 98 --nullability-warnings-txt <file> 99 Specifies where to write warnings encountered during validation of 100 nullability annotations. (Does not trigger validation by itself.) 101 --nullability-errors-non-fatal 102 Specifies that errors encountered during validation of nullability 103 annotations should not be treated as errors. They will be written out to 104 the file specified in --nullability-warnings-txt instead. 105 --input-api-jar <file> 106 A .jar file to read APIs from directly 107 --manifest <file> 108 A manifest file, used to for check permissions to cross check APIs 109 --replace-documentation <p> <r> <t> 110 Amongst nonempty documentation of items from Java packages <p> and their 111 subpackages, replaces any matches of regular expression <r> with 112 replacement text <t>. <p> is given as a nonempty list of Java package names 113 separated by ':' (e.g. "java:android.util"); <t> may contain backreferences 114 ($1, $2 etc.) to matching groups from <r>. 115 --hide-package <package> 116 Remove the given packages from the API even if they have not been marked 117 with @hide 118 --show-annotation <annotation class> 119 Unhide any hidden elements that are also annotated with the given 120 annotation 121 --show-single-annotation <annotation> 122 Like --show-annotation, but does not apply to members; these must also be 123 explicitly annotated 124 --show-for-stub-purposes-annotation <annotation class> 125 Like --show-annotation, but elements annotated with it are assumed to be 126 "implicitly" included in the API surface, and they'll be included in 127 certain kinds of output such as stubs, but not in others, such as the 128 signature file and API lint 129 --hide-annotation <annotation class> 130 Treat any elements annotated with the given annotation as hidden 131 --hide-meta-annotation <meta-annotation class> 132 Treat as hidden any elements annotated with an annotation which is itself 133 annotated with the given meta-annotation 134 --show-unannotated 135 Include un-annotated public APIs in the signature file as well 136 --java-source <level> 137 Sets the source level for Java source files; default is 1.8. 138 --kotlin-source <level> 139 Sets the source level for Kotlin source files; default is 1.4. 140 --sdk-home <dir> 141 If set, locate the `android.jar` file from the given Android SDK 142 --compile-sdk-version <api> 143 Use the given API level 144 --jdk-home <dir> 145 If set, add the Java APIs from the given JDK to the classpath 146 --stub-packages <package-list> 147 List of packages (separated by :) which will be used to filter out 148 irrelevant code. If specified, only code in these packages will be included 149 in signature files, stubs, etc. (This is not limited to just the stubs; the 150 name is historical.) You can also use ".*" at the end to match subpackages, 151 so `foo.*` will match both `foo` and `foo.bar`. 152 --subtract-api <api file> 153 Subtracts the API in the given signature or jar file from the current API 154 being emitted via --api, --stubs, --doc-stubs, etc. Note that the 155 subtraction only applies to classes; it does not subtract members. 156 --typedefs-in-signatures <ref|inline> 157 Whether to include typedef annotations in signature files. 158 `--typedefs-in-signatures ref` will include just a reference to the typedef 159 class, which is not itself part of the API and is not included as a class, 160 and `--typedefs-in-signatures inline` will include the constants themselves 161 into each usage site. You can also supply `--typedefs-in-signatures none` 162 to explicitly turn it off, if the default ever changes. 163 --ignore-classes-on-classpath 164 Prevents references to classes on the classpath from being added to the 165 generated stub files. 166 167 168 Documentation: 169 --public 170 Only include elements that are public 171 --protected 172 Only include elements that are public or protected 173 --package 174 Only include elements that are public, protected or package protected 175 --private 176 Include all elements except those that are marked hidden 177 --hidden 178 Include all elements, including hidden 179 180 181 Extracting Signature Files: 182 --api <file> 183 Generate a signature descriptor file 184 --dex-api <file> 185 Generate a DEX signature descriptor file listing the APIs 186 --removed-api <file> 187 Generate a signature descriptor file for APIs that have been removed 188 --format=<v1,v2,v3,...> 189 Sets the output signature file format to be the given version. 190 --output-kotlin-nulls[=yes|no] 191 Controls whether nullness annotations should be formatted as in Kotlin 192 (with "?" for nullable types, "" for non nullable types, and "!" for 193 unknown. The default is yes. 194 --output-default-values[=yes|no] 195 Controls whether default values should be included in signature files. The 196 default is yes. 197 --compatible-output=[yes|no] 198 Controls whether to keep signature files compatible with the historical 199 format (with its various quirks) or to generate the new format (which will 200 also include annotations that are part of the API, etc.) 201 --omit-common-packages[=yes|no] 202 Skip common package prefixes like java.lang.* and kotlin.* in signature 203 files, along with packages for well known annotations like @Nullable and 204 @NonNull. 205 --include-signature-version[=yes|no] 206 Whether the signature files should include a comment listing the format 207 version of the signature file. 208 --proguard <file> 209 Write a ProGuard keep file for the API 210 --sdk-values <dir> 211 Write SDK values files to the given directory 212 213 214 Generating Stubs: 215 --stubs <dir> 216 Generate stub source files for the API 217 --doc-stubs <dir> 218 Generate documentation stub source files for the API. Documentation stub 219 files are similar to regular stub files, but there are some differences. 220 For example, in the stub files, we'll use special annotations like 221 @RecentlyNonNull instead of @NonNull to indicate that an element is 222 recently marked as non null, whereas in the documentation stubs we'll just 223 list this as @NonNull. Another difference is that @doconly elements are 224 included in documentation stubs, but not regular stubs, etc. 225 --kotlin-stubs 226 [CURRENTLY EXPERIMENTAL] If specified, stubs generated from Kotlin source 227 code will be written in Kotlin rather than the Java programming language. 228 --include-annotations 229 Include annotations such as @Nullable in the stub files. 230 --exclude-all-annotations 231 Exclude annotations such as @Nullable from the stub files; the default. 232 --pass-through-annotation <annotation classes> 233 A comma separated list of fully qualified names of annotation classes that 234 must be passed through unchanged. 235 --exclude-annotation <annotation classes> 236 A comma separated list of fully qualified names of annotation classes that 237 must be stripped from metalava's outputs. 238 --exclude-documentation-from-stubs 239 Exclude element documentation (javadoc and kdoc) from the generated stubs. 240 (Copyright notices are not affected by this, they are always included. 241 Documentation stubs (--doc-stubs) are not affected.) 242 --write-stubs-source-list <file> 243 Write the list of generated stub files into the given source list file. If 244 generating documentation stubs and you haven't also specified 245 --write-doc-stubs-source-list, this list will refer to the documentation 246 stubs; otherwise it's the non-documentation stubs. 247 --write-doc-stubs-source-list <file> 248 Write the list of generated doc stub files into the given source list file 249 --register-artifact <api-file> <id> 250 Registers the given id for the packages found in the given signature file. 251 metalava will inject an @artifactId <id> tag into every top level stub 252 class in that API. 253 254 255 Diffs and Checks: 256 --input-kotlin-nulls[=yes|no] 257 Whether the signature file being read should be interpreted as having 258 encoded its types using Kotlin style types: a suffix of "?" for nullable 259 types, no suffix for non nullable types, and "!" for unknown. The default 260 is no. 261 --check-compatibility:type:state <file> 262 Check compatibility. Type is one of 'api' and 'removed', which checks 263 either the public api or the removed api. State is one of 'current' and 264 'released', to check either the currently in development API or the last 265 publicly released API, respectively. Different compatibility checks apply 266 in the two scenarios. For example, to check the code base against the 267 current public API, use --check-compatibility:api:current. 268 --check-compatibility:base <file> 269 When performing a compat check, use the provided signature file as a base 270 api, which is treated as part of the API being checked. This allows us to 271 compute the full API surface from a partial API surface (e.g. the current 272 @SystemApi txt file), which allows us to recognize when an API is moved 273 from the partial API to the base API and avoid incorrectly flagging this as 274 an API removal. 275 --api-lint [api file] 276 Check API for Android API best practices. If a signature file is provided, 277 only the APIs that are new since the API will be checked. 278 --api-lint-ignore-prefix [prefix] 279 A list of package prefixes to ignore API issues in when running with 280 --api-lint. 281 --migrate-nullness <api file> 282 Compare nullness information with the previous stable API and mark newly 283 annotated APIs as under migration. 284 --warnings-as-errors 285 Promote all warnings to errors 286 --lints-as-errors 287 Promote all API lint warnings to errors 288 --error <id> 289 Report issues of the given id as errors 290 --warning <id> 291 Report issues of the given id as warnings 292 --lint <id> 293 Report issues of the given id as having lint-severity 294 --hide <id> 295 Hide/skip issues of the given id 296 --report-even-if-suppressed <file> 297 Write all issues into the given file, even if suppressed (via annotation or 298 baseline) but not if hidden (by '--hide') 299 --baseline <file> 300 Filter out any errors already reported in the given baseline file, or 301 create if it does not already exist 302 --update-baseline [file] 303 Rewrite the existing baseline file with the current set of warnings. If 304 some warnings have been fixed, this will delete them from the baseline 305 files. If a file is provided, the updated baseline is written to the given 306 file; otherwise the original source baseline file is updated. 307 --baseline:api-lint <file> --update-baseline:api-lint [file] 308 Same as --baseline and --update-baseline respectively, but used 309 specifically for API lint issues performed by --api-lint. 310 --baseline:compatibility:released <file> --update-baseline:compatibility:released [file] 311 Same as --baseline and --update-baseline respectively, but used 312 specifically for API compatibility issues performed by 313 --check-compatibility:api:released and 314 --check-compatibility:removed:released. 315 --merge-baseline [file] 316 Like --update-baseline, but instead of always replacing entries in the 317 baseline, it will merge the existing baseline with the new baseline. This 318 is useful if metalava runs multiple times on the same source tree with 319 different flags at different times, such as occasionally with --api-lint. 320 --pass-baseline-updates 321 Normally, encountering error will fail the build, even when updating 322 baselines. This flag allows you to tell metalava to continue without 323 errors, such that all the baselines in the source tree can be updated in 324 one go. 325 --delete-empty-baselines 326 Whether to delete baseline files if they are updated and there is nothing 327 to include. 328 --error-message:api-lint <message> 329 If set, metalava shows it when errors are detected in --api-lint. 330 --error-message:compatibility:released <message> 331 If set, metalava shows it when errors are detected in 332 --check-compatibility:api:released and 333 --check-compatibility:removed:released. 334 --error-message:compatibility:current <message> 335 If set, metalava shows it when errors are detected in 336 --check-compatibility:api:current and 337 --check-compatibility:removed:current. 338 339 340 JDiff: 341 --api-xml <file> 342 Like --api, but emits the API in the JDiff XML format instead 343 --convert-to-jdiff <sig> <xml> 344 Reads in the given signature file, and writes it out in the JDiff XML 345 format. Can be specified multiple times. 346 --convert-new-to-jdiff <old> <new> <xml> 347 Reads in the given old and new api files, computes the difference, and 348 writes out only the new parts of the API in the JDiff XML format. 349 --convert-to-v1 <sig> <sig> 350 Reads in the given signature file and writes it out as a signature file in 351 the original v1/doclava format. 352 --convert-to-v2 <sig> <sig> 353 Reads in the given signature file and writes it out as a signature file in 354 the new signature format, v2. 355 --convert-new-to-v2 <old> <new> <sig> 356 Reads in the given old and new api files, computes the difference, and 357 writes out only the new parts of the API in the v2 format. 358 359 360 Statistics: 361 --annotation-coverage-stats 362 Whether metalava should emit coverage statistics for annotations, listing 363 the percentage of the API that has been annotated with nullness 364 information. 365 --annotation-coverage-of <paths> 366 One or more jars (separated by `:`) containing existing apps that we want 367 to measure annotation coverage statistics for. The set of API usages in 368 those apps are counted up and the most frequently used APIs that are 369 missing annotation metadata are listed in descending order. 370 --skip-java-in-coverage-report 371 In the coverage annotation report, skip java.** and kotlin.** to narrow the 372 focus down to the Android framework APIs. 373 --write-class-coverage-to <path> 374 Specifies a file to write the annotation coverage report for classes to. 375 --write-member-coverage-to <path> 376 Specifies a file to write the annotation coverage report for members to. 377 378 379 Extracting Annotations: 380 --extract-annotations <zipfile> 381 Extracts source annotations from the source files and writes them into the 382 given zip file 383 --include-annotation-classes <dir> 384 Copies the given stub annotation source files into the generated stub 385 sources; <dir> is typically metalava/stub-annotations/src/main/java/. 386 --rewrite-annotations <dir/jar> 387 For a bytecode folder or output jar, rewrites the androidx annotations to 388 be package private 389 --force-convert-to-warning-nullability-annotations <package1:-package2:...> 390 On every API declared in a class referenced by the given filter, makes 391 nullability issues appear to callers as warnings rather than errors by 392 replacing @Nullable/@NonNull in these APIs with 393 @RecentlyNullable/@RecentlyNonNull 394 --copy-annotations <source> <dest> 395 For a source folder full of annotation sources, generates corresponding 396 package private versions of the same annotations. 397 --include-source-retention 398 If true, include source-retention annotations in the stub files. Does not 399 apply to signature files. Source retention annotations are extracted into 400 the external annotations files instead. 401 402 403 Injecting API Levels: 404 --apply-api-levels <api-versions.xml> 405 Reads an XML file containing API level descriptions and merges the 406 information into the documentation 407 408 409 Extracting API Levels: 410 --generate-api-levels <xmlfile> 411 Reads android.jar SDK files and generates an XML file recording the API 412 level for each class, method and field 413 --android-jar-pattern <pattern> 414 Patterns to use to locate Android JAR files. The default is 415 ${"$"}ANDROID_HOME/platforms/android-%/android.jar. 416 --current-version 417 Sets the current API level of the current source code 418 --current-codename 419 Sets the code name for the current source code 420 --current-jar 421 Points to the current API jar, if any 422 423 424 Sandboxing: 425 --no-implicit-root 426 Disable implicit root directory detection. Otherwise, metalava adds in 427 source roots implied by the source files 428 --strict-input-files <file> 429 Do not read files that are not explicitly specified in the command line. 430 All violations are written to the given file. Reads on directories are 431 always allowed, but metalava still tracks reads on directories that are not 432 specified in the command line, and write them to the file. 433 --strict-input-files:warn <file> 434 Warn when files not explicitly specified on the command line are read. All 435 violations are written to the given file. Reads on directories not 436 specified in the command line are allowed but also logged. 437 --strict-input-files:stack <file> 438 Same as --strict-input-files but also print stacktraces. 439 --strict-input-files-exempt <files or dirs> 440 Used with --strict-input-files. Explicitly allow access to files and/or 441 directories (separated by `:). Can also be @ followed by a path to a text 442 file containing paths to the full set of files and/or directories. 443 444 445 Environment Variables: 446 METALAVA_DUMP_ARGV 447 Set to true to have metalava emit all the arguments it was invoked with. 448 Helpful when debugging or reproducing under a debugger what the build 449 system is doing. 450 METALAVA_PREPEND_ARGS 451 One or more arguments (concatenated by space) to insert into the command 452 line, before the documentation flags. 453 METALAVA_APPEND_ARGS 454 One or more arguments (concatenated by space) to append to the end of the 455 command line, after the generate documentation flags. 456 457 """.trimIndent() 458 459 @Test Test invalid argumentsnull460 fun `Test invalid arguments`() { 461 val args = listOf(ARG_NO_COLOR, "--blah-blah-blah") 462 463 val stdout = StringWriter() 464 val stderr = StringWriter() 465 run( 466 originalArgs = args.toTypedArray(), 467 stdout = PrintWriter(stdout), 468 stderr = PrintWriter(stderr) 469 ) 470 assertEquals(BANNER + "\n\n", stdout.toString()) 471 assertEquals( 472 """ 473 474 Aborting: Invalid argument --blah-blah-blah 475 476 $FLAGS 477 478 """.trimIndent(), stderr.toString() 479 ) 480 } 481 482 @Test Test helpnull483 fun `Test help`() { 484 val args = listOf(ARG_NO_COLOR, "--help") 485 486 val stdout = StringWriter() 487 val stderr = StringWriter() 488 run( 489 originalArgs = args.toTypedArray(), 490 stdout = PrintWriter(stdout), 491 stderr = PrintWriter(stderr) 492 ) 493 assertEquals("", stderr.toString()) 494 assertEquals( 495 """ 496 $BANNER 497 498 499 $DESCRIPTION 500 501 $FLAGS 502 503 """.trimIndent(), stdout.toString() 504 ) 505 } 506 507 @Test Test issue severity optionsnull508 fun `Test issue severity options`() { 509 check( 510 extraArguments = arrayOf( 511 "--hide", 512 "StartWithLower", 513 "--lint", 514 "EndsWithImpl", 515 "--warning", 516 "StartWithUpper", 517 "--error", 518 "ArrayReturn" 519 ) 520 ) 521 assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.START_WITH_LOWER)) 522 assertEquals(Severity.LINT, defaultConfiguration.getSeverity(Issues.ENDS_WITH_IMPL)) 523 assertEquals(Severity.WARNING, defaultConfiguration.getSeverity(Issues.START_WITH_UPPER)) 524 assertEquals(Severity.ERROR, defaultConfiguration.getSeverity(Issues.ARRAY_RETURN)) 525 } 526 527 @Test Test multiple issue severity optionsnull528 fun `Test multiple issue severity options`() { 529 check( 530 extraArguments = arrayOf("--hide", "StartWithLower,StartWithUpper,ArrayReturn") 531 ) 532 assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.START_WITH_LOWER)) 533 assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.START_WITH_UPPER)) 534 assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.ARRAY_RETURN)) 535 } 536 537 @Test Test issue severity options with inheriting issuesnull538 fun `Test issue severity options with inheriting issues`() { 539 check( 540 extraArguments = arrayOf("--error", "RemovedClass") 541 ) 542 assertEquals(Severity.ERROR, defaultConfiguration.getSeverity(Issues.REMOVED_CLASS)) 543 assertEquals(Severity.ERROR, defaultConfiguration.getSeverity(Issues.REMOVED_DEPRECATED_CLASS)) 544 } 545 546 @Test Test issue severity options with case insensitive namesnull547 fun `Test issue severity options with case insensitive names`() { 548 check( 549 extraArguments = arrayOf("--hide", "arrayreturn"), 550 expectedIssues = "warning: Case-insensitive issue matching is deprecated, use --hide ArrayReturn instead of --hide arrayreturn [DeprecatedOption]" 551 ) 552 assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.ARRAY_RETURN)) 553 } 554 555 @Test Test issue severity options with non-existing issuenull556 fun `Test issue severity options with non-existing issue`() { 557 check( 558 extraArguments = arrayOf("--hide", "ThisIssueDoesNotExist"), 559 expectedFail = "Aborting: Unknown issue id: --hide ThisIssueDoesNotExist" 560 ) 561 } 562 563 @Test Test for --strict-input-files-exemptnull564 fun `Test for --strict-input-files-exempt`() { 565 val top = temporaryFolder.newFolder() 566 567 val dir = File(top, "childdir").apply { mkdirs() } 568 val grandchild1 = File(dir, "grandchiild1").apply { createNewFile() } 569 val grandchild2 = File(dir, "grandchiild2").apply { createNewFile() } 570 val file1 = File(top, "file1").apply { createNewFile() } 571 val file2 = File(top, "file2").apply { createNewFile() } 572 573 try { 574 check( 575 extraArguments = arrayOf("--strict-input-files-exempt", 576 file1.path + File.pathSeparatorChar + dir.path) 577 ) 578 579 assertTrue(FileReadSandbox.isAccessAllowed(file1)) 580 assertTrue(FileReadSandbox.isAccessAllowed(grandchild1)) 581 assertTrue(FileReadSandbox.isAccessAllowed(grandchild2)) 582 583 assertFalse(FileReadSandbox.isAccessAllowed(file2)) // Access *not* allowed 584 } finally { 585 FileReadSandbox.reset() 586 } 587 } 588 } 589