### Question:
AppcacheLinker extends AbstractLinker { @Nonnull final String writeManifest( @Nonnull final TreeLogger logger, @Nonnull final Set<String> staticResources, @Nonnull final Map<String, String> fallbackResources, @Nonnull final Set<String> cacheResources ) throws UnableToCompleteException { final ManifestDescriptor descriptor = new ManifestDescriptor(); final List<String> cachedResources = Stream .concat( staticResources.stream(), cacheResources.stream() ) .sorted() .distinct() .collect( Collectors.toList() ); descriptor.getCachedResources().addAll( cachedResources ); descriptor.getFallbackResources().putAll( fallbackResources ); descriptor.getNetworkResources().add( "*" ); try { return descriptor.toString(); } catch ( final Exception e ) { logger.log( Type.ERROR, "Error generating manifest: " + e, e ); throw new UnableToCompleteException(); } }  @Override String getDescription(); @Override ArtifactSet link( @Nonnull final TreeLogger logger,
                           @Nonnull final LinkerContext context,
                           @Nonnull final ArtifactSet artifacts,
                           final boolean onePermutation );  }### Answer:
@Test public void writeManifest() throws Exception { final AppcacheLinker linker = new AppcacheLinker(); final HashSet<String> staticResources = new HashSet<>(); staticResources.add( "index.html" ); staticResources.add( "file with space.html" ); final HashSet<String> cacheResources = new HashSet<>(); cacheResources.add( "mydir/file_with_$.js" ); cacheResources.add( "5435435435435435FDEC.js" ); final HashMap<String, String> fallbackResources = new HashMap<>(); fallbackResources.put( "online.png", "offline.png" ); final String manifest = linker.writeManifest( TreeLogger.NULL, staticResources, fallbackResources, cacheResources ); final String[] lines = manifest.split( "\n" ); assertEquals( lines[ 0 ], "CACHE MANIFEST" ); final int cacheSectionStart = findLine( lines, 0, lines.length, "CACHE:" ); final int networkSectionStart = findLine( lines, cacheSectionStart + 1, lines.length, "NETWORK:" ); final int fallbackSectionStart = findLine( lines, networkSectionStart + 1, lines.length, "FALLBACK:" ); assertNotEquals( findLine( lines, networkSectionStart + 1, lines.length, "*" ), -1 ); assertNotEquals( findLine( lines, cacheSectionStart + 1, networkSectionStart, "index.html" ), -1 ); assertNotEquals( findLine( lines, cacheSectionStart + 1, networkSectionStart, "file%20with%20space.html" ), -1 ); assertNotEquals( findLine( lines, cacheSectionStart + 1, networkSectionStart, "5435435435435435FDEC.js" ), -1 ); assertNotEquals( findLine( lines, cacheSectionStart + 1, networkSectionStart, "mydir/file_with_%24.js" ), -1 ); assertNotEquals( findLine( lines, fallbackSectionStart + 1, lines.length, "online.png offline.png" ), -1 ); }