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