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