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