• 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:state <file>
245                                              Check compatibility. Type is one of 'api' and 'removed', which checks
246                                              either the public api or the removed api. State is one of 'current' and
247                                              'released', to check either the currently in development API or the last
248                                              publicly released API, respectively. Different compatibility checks apply
249                                              in the two scenarios. For example, to check the code base against the
250                                              current public API, use --check-compatibility:api:current.
251 --check-compatibility:base <file>
252                                              When performing a compat check, use the provided signature file as a base
253                                              api, which is treated as part of the API being checked. This allows us to
254                                              compute the full API surface from a partial API surface (e.g. the current
255                                              @SystemApi txt file), which allows us to recognize when an API is moved
256                                              from the partial API to the base API and avoid incorrectly flagging this as
257                                              an API removal.
258 --api-lint [api file]
259                                              Check API for Android API best practices. If a signature file is provided,
260                                              only the APIs that are new since the API will be checked.
261 --api-lint-ignore-prefix [prefix]
262                                              A list of package prefixes to ignore API issues in when running with
263                                              --api-lint.
264 --migrate-nullness <api file>
265                                              Compare nullness information with the previous stable API and mark newly
266                                              annotated APIs as under migration.
267 --warnings-as-errors
268                                              Promote all warnings to errors
269 --lints-as-errors
270                                              Promote all API lint warnings to errors
271 --error <id>
272                                              Report issues of the given id as errors
273 --warning <id>
274                                              Report issues of the given id as warnings
275 --lint <id>
276                                              Report issues of the given id as having lint-severity
277 --hide <id>
278                                              Hide/skip issues of the given id
279 --report-even-if-suppressed <file>
280                                              Write all issues into the given file, even if suppressed (via annotation or
281                                              baseline) but not if hidden (by '--hide')
282 --baseline <file>
283                                              Filter out any errors already reported in the given baseline file, or
284                                              create if it does not already exist
285 --update-baseline [file]
286                                              Rewrite the existing baseline file with the current set of warnings. If
287                                              some warnings have been fixed, this will delete them from the baseline
288                                              files. If a file is provided, the updated baseline is written to the given
289                                              file; otherwise the original source baseline file is updated.
290 --baseline:api-lint <file> --update-baseline:api-lint [file]
291                                              Same as --baseline and --update-baseline respectively, but used
292                                              specifically for API lint issues performed by --api-lint.
293 --baseline:compatibility:released <file> --update-baseline:compatibility:released [file]
294                                              Same as --baseline and --update-baseline respectively, but used
295                                              specifically for API compatibility issues performed by
296                                              --check-compatibility:api:released and
297                                              --check-compatibility:removed:released.
298 --merge-baseline [file]
299                                              Like --update-baseline, but instead of always replacing entries in the
300                                              baseline, it will merge the existing baseline with the new baseline. This
301                                              is useful if metalava runs multiple times on the same source tree with
302                                              different flags at different times, such as occasionally with --api-lint.
303 --pass-baseline-updates
304                                              Normally, encountering error will fail the build, even when updating
305                                              baselines. This flag allows you to tell metalava to continue without
306                                              errors, such that all the baselines in the source tree can be updated in
307                                              one go.
308 --delete-empty-baselines
309                                              Whether to delete baseline files if they are updated and there is nothing
310                                              to include.
311 --error-message:api-lint <message>
312                                              If set, metalava shows it when errors are detected in --api-lint.
313 --error-message:compatibility:released <message>
314                                              If set, metalava shows it when errors are detected in
315                                              --check-compatibility:api:released and
316                                              --check-compatibility:removed:released.
317 
318 
319 JDiff:
320 --api-xml <file>
321                                              Like --api, but emits the API in the JDiff XML format instead
322 --convert-to-jdiff <sig> <xml>
323                                              Reads in the given signature file, and writes it out in the JDiff XML
324                                              format. Can be specified multiple times.
325 --convert-new-to-jdiff <old> <new> <xml>
326                                              Reads in the given old and new api files, computes the difference, and
327                                              writes out only the new parts of the API in the JDiff XML format.
328 
329 
330 Extracting Annotations:
331 --extract-annotations <zipfile>
332                                              Extracts source annotations from the source files and writes them into the
333                                              given zip file
334 --include-annotation-classes <dir>
335                                              Copies the given stub annotation source files into the generated stub
336                                              sources; <dir> is typically metalava/stub-annotations/src/main/java/.
337 --rewrite-annotations <dir/jar>
338                                              For a bytecode folder or output jar, rewrites the androidx annotations to
339                                              be package private
340 --force-convert-to-warning-nullability-annotations <package1:-package2:...>
341                                              On every API declared in a class referenced by the given filter, makes
342                                              nullability issues appear to callers as warnings rather than errors by
343                                              replacing @Nullable/@NonNull in these APIs with
344                                              @RecentlyNullable/@RecentlyNonNull
345 --copy-annotations <source> <dest>
346                                              For a source folder full of annotation sources, generates corresponding
347                                              package private versions of the same annotations.
348 --include-source-retention
349                                              If true, include source-retention annotations in the stub files. Does not
350                                              apply to signature files. Source retention annotations are extracted into
351                                              the external annotations files instead.
352 
353 
354 Injecting API Levels:
355 --apply-api-levels <api-versions.xml>
356                                              Reads an XML file containing API level descriptions and merges the
357                                              information into the documentation
358 
359 
360 Extracting API Levels:
361 --generate-api-levels <xmlfile>
362                                              Reads android.jar SDK files and generates an XML file recording the API
363                                              level for each class, method and field
364 --android-jar-pattern <pattern>
365                                              Patterns to use to locate Android JAR files. The default is
366                                              ${"$"}ANDROID_HOME/platforms/android-%/android.jar.
367 --first-version
368                                              Sets the first API level to generate an API database from; usually 1
369 --current-version
370                                              Sets the current API level of the current source code
371 --current-codename
372                                              Sets the code name for the current source code
373 --current-jar
374                                              Points to the current API jar, if any
375 
376 
377 Sandboxing:
378 --no-implicit-root
379                                              Disable implicit root directory detection. Otherwise, metalava adds in
380                                              source roots implied by the source files
381 --strict-input-files <file>
382                                              Do not read files that are not explicitly specified in the command line.
383                                              All violations are written to the given file. Reads on directories are
384                                              always allowed, but metalava still tracks reads on directories that are not
385                                              specified in the command line, and write them to the file.
386 --strict-input-files:warn <file>
387                                              Warn when files not explicitly specified on the command line are read. All
388                                              violations are written to the given file. Reads on directories not
389                                              specified in the command line are allowed but also logged.
390 --strict-input-files:stack <file>
391                                              Same as --strict-input-files but also print stacktraces.
392 --strict-input-files-exempt <files or dirs>
393                                              Used with --strict-input-files. Explicitly allow access to files and/or
394                                              directories (separated by `:). Can also be @ followed by a path to a text
395                                              file containing paths to the full set of files and/or directories.
396 
397 
398 Environment Variables:
399 METALAVA_DUMP_ARGV
400                                              Set to true to have metalava emit all the arguments it was invoked with.
401                                              Helpful when debugging or reproducing under a debugger what the build
402                                              system is doing.
403 METALAVA_PREPEND_ARGS
404                                              One or more arguments (concatenated by space) to insert into the command
405                                              line, before the documentation flags.
406 METALAVA_APPEND_ARGS
407                                              One or more arguments (concatenated by space) to append to the end of the
408                                              command line, after the generate documentation flags.
409 
410     """.trimIndent()
411 
412     @Test
Test invalid argumentsnull413     fun `Test invalid arguments`() {
414         val args = listOf(ARG_NO_COLOR, "--blah-blah-blah")
415 
416         val stdout = StringWriter()
417         val stderr = StringWriter()
418         run(
419             originalArgs = args.toTypedArray(),
420             stdout = PrintWriter(stdout),
421             stderr = PrintWriter(stderr)
422         )
423         assertEquals(BANNER + "\n\n", stdout.toString())
424         assertEquals(
425             """
426 
427 Aborting: Invalid argument --blah-blah-blah
428 
429 $FLAGS
430 
431             """.trimIndent(),
432             stderr.toString()
433         )
434     }
435 
436     @Test
Test helpnull437     fun `Test help`() {
438         val args = listOf(ARG_NO_COLOR, "--help")
439 
440         val stdout = StringWriter()
441         val stderr = StringWriter()
442         run(
443             originalArgs = args.toTypedArray(),
444             stdout = PrintWriter(stdout),
445             stderr = PrintWriter(stderr)
446         )
447         assertEquals("", stderr.toString())
448         assertEquals(
449             """
450 $BANNER
451 
452 
453 $DESCRIPTION
454 
455 $FLAGS
456 
457             """.trimIndent(),
458             stdout.toString()
459         )
460     }
461 
462     @Test
Test issue severity optionsnull463     fun `Test issue severity options`() {
464         check(
465             extraArguments = arrayOf(
466                 "--hide",
467                 "StartWithLower",
468                 "--lint",
469                 "EndsWithImpl",
470                 "--warning",
471                 "StartWithUpper",
472                 "--error",
473                 "ArrayReturn"
474             )
475         )
476         assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.START_WITH_LOWER))
477         assertEquals(Severity.LINT, defaultConfiguration.getSeverity(Issues.ENDS_WITH_IMPL))
478         assertEquals(Severity.WARNING, defaultConfiguration.getSeverity(Issues.START_WITH_UPPER))
479         assertEquals(Severity.ERROR, defaultConfiguration.getSeverity(Issues.ARRAY_RETURN))
480     }
481 
482     @Test
Test multiple issue severity optionsnull483     fun `Test multiple issue severity options`() {
484         check(
485             extraArguments = arrayOf("--hide", "StartWithLower,StartWithUpper,ArrayReturn")
486         )
487         assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.START_WITH_LOWER))
488         assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.START_WITH_UPPER))
489         assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.ARRAY_RETURN))
490     }
491 
492     @Test
Test issue severity options with inheriting issuesnull493     fun `Test issue severity options with inheriting issues`() {
494         check(
495             extraArguments = arrayOf("--error", "RemovedClass")
496         )
497         assertEquals(Severity.ERROR, defaultConfiguration.getSeverity(Issues.REMOVED_CLASS))
498         assertEquals(Severity.ERROR, defaultConfiguration.getSeverity(Issues.REMOVED_DEPRECATED_CLASS))
499     }
500 
501     @Test
Test issue severity options with case insensitive namesnull502     fun `Test issue severity options with case insensitive names`() {
503         check(
504             extraArguments = arrayOf("--hide", "arrayreturn"),
505             expectedIssues = "warning: Case-insensitive issue matching is deprecated, use --hide ArrayReturn instead of --hide arrayreturn [DeprecatedOption]"
506         )
507         assertEquals(Severity.HIDDEN, defaultConfiguration.getSeverity(Issues.ARRAY_RETURN))
508     }
509 
510     @Test
Test issue severity options with non-existing issuenull511     fun `Test issue severity options with non-existing issue`() {
512         check(
513             extraArguments = arrayOf("--hide", "ThisIssueDoesNotExist"),
514             expectedFail = "Aborting: Unknown issue id: --hide ThisIssueDoesNotExist"
515         )
516     }
517 
518     @Test
Test for --strict-input-files-exemptnull519     fun `Test for --strict-input-files-exempt`() {
520         val top = temporaryFolder.newFolder()
521 
522         val dir = File(top, "childdir").apply { mkdirs() }
523         val grandchild1 = File(dir, "grandchiild1").apply { createNewFile() }
524         val grandchild2 = File(dir, "grandchiild2").apply { createNewFile() }
525         val file1 = File(top, "file1").apply { createNewFile() }
526         val file2 = File(top, "file2").apply { createNewFile() }
527 
528         try {
529             check(
530                 extraArguments = arrayOf(
531                     "--strict-input-files-exempt",
532                     file1.path + File.pathSeparatorChar + dir.path
533                 )
534             )
535 
536             assertTrue(FileReadSandbox.isAccessAllowed(file1))
537             assertTrue(FileReadSandbox.isAccessAllowed(grandchild1))
538             assertTrue(FileReadSandbox.isAccessAllowed(grandchild2))
539 
540             assertFalse(FileReadSandbox.isAccessAllowed(file2)) // Access *not* allowed
541         } finally {
542             FileReadSandbox.reset()
543         }
544     }
545 }
546