1/*
2 * Copyright (C) 2016 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
17package libcore.java.nio.file;
18
19import org.junit.Before;
20import org.junit.Rule;
21import org.junit.Test;
22import org.junit.runner.RunWith;
23
24import java.io.IOException;
25import java.net.URI;
26import java.nio.ByteBuffer;
27import java.nio.channels.FileChannel;
28import java.nio.channels.NonReadableChannelException;
29import java.nio.file.CopyOption;
30import java.nio.file.DirectoryNotEmptyException;
31import java.nio.file.DirectoryStream;
32import java.nio.file.FileAlreadyExistsException;
33import java.nio.file.FileStore;
34import java.nio.file.Files;
35import java.nio.file.NoSuchFileException;
36import java.nio.file.NotLinkException;
37import java.nio.file.OpenOption;
38import java.nio.file.Path;
39import java.nio.file.Paths;
40import java.nio.file.StandardOpenOption;
41import java.nio.file.attribute.BasicFileAttributeView;
42import java.nio.file.attribute.BasicFileAttributes;
43import java.nio.file.attribute.FileAttribute;
44import java.nio.file.attribute.FileTime;
45import java.nio.file.attribute.PosixFilePermission;
46import java.nio.file.attribute.PosixFilePermissions;
47import java.nio.file.spi.FileSystemProvider;
48import java.util.EnumSet;
49import java.util.HashMap;
50import java.util.HashSet;
51import java.util.List;
52import java.util.Map;
53import java.util.Set;
54import java.util.concurrent.TimeUnit;
55
56import junitparams.JUnitParamsRunner;
57import junitparams.Parameters;
58
59import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;
60import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
61import static java.nio.file.StandardOpenOption.APPEND;
62import static java.nio.file.StandardOpenOption.CREATE;
63import static java.nio.file.StandardOpenOption.READ;
64import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
65import static java.nio.file.StandardOpenOption.WRITE;
66import static junit.framework.TestCase.assertNotNull;
67import static junit.framework.TestCase.assertTrue;
68import static libcore.java.nio.file.FilesSetup.DATA_FILE;
69import static libcore.java.nio.file.FilesSetup.NonStandardOption;
70import static libcore.java.nio.file.FilesSetup.TEST_FILE_DATA;
71import static libcore.java.nio.file.FilesSetup.TEST_FILE_DATA_2;
72import static libcore.java.nio.file.FilesSetup.readFromFile;
73import static libcore.java.nio.file.FilesSetup.writeToFile;
74import static libcore.java.nio.file.LinuxFileSystemTestData.getPath_URI_InputOutputTestData;
75import static org.junit.Assert.assertEquals;
76import static org.junit.Assert.assertFalse;
77import static org.junit.Assert.fail;
78
79@RunWith(JUnitParamsRunner.class)
80public class DefaultFileSystemProvider2Test {
81
82    @Rule
83    public FilesSetup filesSetup = new FilesSetup();
84
85    private FileSystemProvider provider;
86
87    @Before
88    public void setUp() throws Exception {
89        provider = filesSetup.getDataFilePath().getFileSystem().provider();
90    }
91
92    @Test
93    public void test_move() throws IOException {
94        provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath());
95        assertEquals(TEST_FILE_DATA, readFromFile(filesSetup.getTestPath()));
96        assertFalse(Files.exists(filesSetup.getDataFilePath()));
97
98        filesSetup.reset();
99        Files.createFile(filesSetup.getTestPath());
100        // When target file exists.
101        try {
102            provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath());
103            fail();
104        } catch (FileAlreadyExistsException expected) {}
105
106        // Move to existing target file with REPLACE_EXISTING copy option.
107        filesSetup.reset();
108        Files.createFile(filesSetup.getTestPath());
109        writeToFile(filesSetup.getDataFilePath(), TEST_FILE_DATA_2);
110        provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath(), REPLACE_EXISTING);
111        assertEquals(TEST_FILE_DATA_2, readFromFile(filesSetup.getTestPath()));
112
113        // Copy from a non existent file.
114        filesSetup.reset();
115        try {
116            provider.move(filesSetup.getTestPath(), filesSetup.getDataFilePath(), REPLACE_EXISTING);
117            fail();
118        } catch (NoSuchFileException expected) {}
119    }
120
121    @Test
122    public void test_move_CopyOption() throws IOException {
123        FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis() - 10000);
124        Files.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", fileTime);
125        provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath());
126        assertEquals(fileTime.to(TimeUnit.SECONDS),
127                ((FileTime) Files.getAttribute(filesSetup.getTestPath(),
128                        "basic:lastModifiedTime")).to(TimeUnit.SECONDS));
129        assertEquals(TEST_FILE_DATA, readFromFile(filesSetup.getTestPath()));
130
131        // ATOMIC_MOVE
132        filesSetup.reset();
133        provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath(), ATOMIC_MOVE);
134        assertEquals(TEST_FILE_DATA, readFromFile(filesSetup.getTestPath()));
135
136        filesSetup.reset();
137        try {
138            provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath(),
139                    NonStandardOption.OPTION1);
140            fail();
141        } catch (UnsupportedOperationException expected) {}
142    }
143
144    @Test
145    public void test_move_NPE() throws IOException {
146        try {
147            provider.move(null, filesSetup.getTestPath());
148            fail();
149        } catch(NullPointerException expected) {}
150
151        try {
152            provider.move(filesSetup.getDataFilePath(), null);
153            fail();
154        } catch(NullPointerException expected) {}
155
156        try {
157            provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath(),
158                    (CopyOption[]) null);
159            fail();
160        } catch(NullPointerException expected) {}
161    }
162
163    @Test
164    public void test_move_directory() throws IOException {
165        Path dirPath = filesSetup.getPathInTestDir("dir1");
166        final Path nestedDirPath = filesSetup.getPathInTestDir("dir1/dir");
167        final Path dirPath2 = filesSetup.getPathInTestDir("dir2");
168
169        Files.createDirectory(dirPath);
170        Files.createDirectory(nestedDirPath);
171        Files.copy(filesSetup.getDataFilePath(),
172                filesSetup.getPathInTestDir("dir1/" + DATA_FILE));
173        provider.move(dirPath, dirPath2);
174
175        Map<Path, Boolean> pathMap = new HashMap<>();
176        try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(dirPath2)) {
177            directoryStream.forEach(file -> pathMap.put(file, true));
178        }
179
180        // The files are not copied. The command is equivalent of creating a new directory.
181        assertEquals(2, pathMap.size());
182        assertEquals(TEST_FILE_DATA,
183                readFromFile(filesSetup.getPathInTestDir("dir2/" + DATA_FILE)));
184        assertFalse(Files.exists(dirPath));
185
186        filesSetup.reset();
187    }
188
189    @Test
190    public void test_move_directory_DirectoryNotEmptyException() throws IOException {
191        Path dirPath = filesSetup.getPathInTestDir("dir1");
192        Path dirPath4 = filesSetup.getPathInTestDir("dir4");
193        Files.createDirectory(dirPath);
194        Files.createDirectory(dirPath4);
195        Files.createFile(Paths.get(dirPath.toString(), DATA_FILE));
196        Files.createFile(Paths.get(dirPath4.toString(), DATA_FILE));
197        try {
198            Files.copy(dirPath, dirPath4, REPLACE_EXISTING);
199            fail();
200        } catch (DirectoryNotEmptyException expected) {}
201    }
202
203    @Test
204    public void test_readSymbolicLink() throws IOException {
205        provider.createSymbolicLink(/* Path of the symbolic link */ filesSetup.getTestPath(),
206                /* Path of the target of the symbolic link */
207                filesSetup.getDataFilePath().toAbsolutePath());
208        assertEquals(filesSetup.getDataFilePath().toAbsolutePath(),
209                Files.readSymbolicLink(filesSetup.getTestPath()));
210
211        // Sym link to itself
212        filesSetup.reset();
213        provider.createSymbolicLink(/* Path of the symbolic link */ filesSetup.getTestPath(),
214                /* Path of the target of the symbolic link */
215                filesSetup.getTestPath().toAbsolutePath());
216        assertEquals(filesSetup.getTestPath().toAbsolutePath(),
217                Files.readSymbolicLink(filesSetup.getTestPath()));
218
219        filesSetup.reset();
220        try {
221            provider.readSymbolicLink(filesSetup.getDataFilePath());
222            fail();
223        } catch (NotLinkException expected) {
224        }
225    }
226
227    @Test
228    public void test_readSymbolicLink_NPE() throws IOException {
229        try {
230            provider.readSymbolicLink(null);
231            fail();
232        } catch (NullPointerException expected) {}
233    }
234
235    @Test
236    public void test_isSameFile() throws IOException {
237        // When both the files exists.
238        assertTrue(provider.isSameFile(filesSetup.getDataFilePath(), filesSetup.getDataFilePath()));
239
240        // When the files doesn't exist.
241        assertTrue(provider.isSameFile(filesSetup.getTestPath(), filesSetup.getTestPath()));
242
243        // With two different files.
244        try {
245            assertFalse(
246                    provider.isSameFile(filesSetup.getDataFilePath(), filesSetup.getTestPath()));
247            fail();
248        } catch (NoSuchFileException expected) {}
249    }
250
251    @Test
252    public void test_isSameFile_NPE() throws IOException {
253        try {
254            provider.isSameFile(null, filesSetup.getDataFilePath());
255            fail();
256        } catch (NullPointerException expected) {}
257
258        try {
259            provider.isSameFile(filesSetup.getDataFilePath(), null);
260            fail();
261        } catch (NullPointerException expected) {}
262    }
263
264    @Test
265    public void test_getFileStore() throws IOException {
266        try {
267            provider.getFileStore(filesSetup.getDataFilePath());
268            fail();
269        } catch (SecurityException expected) {
270        }
271
272        try {
273            provider.getFileStore(null);
274            fail();
275        } catch (SecurityException expected) {
276        }
277    }
278
279    @Test
280    public void test_isHidden() throws IOException {
281        assertFalse(provider.isHidden(filesSetup.getDataFilePath()));
282
283        // Files can't be hidden using the "dos" view, which is unsupported since it relies
284        // on a custom xattr, which may or may not be available on all FSs.
285        //
286        // Note that this weirdly asymmetric : setting the hidden attribute uses xattrs to
287        // emulate dos attributes whereas isHidden checks whether the the file name begins with a
288        // leading period. <shrug>
289        try {
290            Files.setAttribute(filesSetup.getDataFilePath(), "dos:hidden", true);
291            fail();
292        } catch (UnsupportedOperationException expected) {
293        }
294
295        assertFalse(provider.isHidden(filesSetup.getDataFilePath()));
296    }
297
298    @Test
299    public void test_isHidden_NPE() throws IOException {
300        try {
301            provider.isHidden(null);
302            fail();
303        } catch (NullPointerException expected) {}
304    }
305
306    @Test
307    public void test_probeContentType_NPE() throws IOException {
308        try {
309            Files.probeContentType(null);
310            fail();
311        } catch (NullPointerException expected) {}
312    }
313
314    @Test
315    public void test_getFileAttributeView() throws IOException {
316        BasicFileAttributeView fileAttributeView = provider
317                .getFileAttributeView(filesSetup.getDataFilePath(),
318                BasicFileAttributeView.class);
319
320        assertTrue(fileAttributeView.readAttributes().isRegularFile());
321        assertFalse(fileAttributeView.readAttributes().isDirectory());
322    }
323
324    @Test
325    public void test_getFileAttributeView_NPE() throws IOException {
326        try {
327            provider.getFileAttributeView(null, BasicFileAttributeView.class);
328            fail();
329        } catch (NullPointerException expected) {}
330
331        try {
332            provider.getFileAttributeView(filesSetup.getDataFilePath(), null);
333            fail();
334        } catch (NullPointerException expected) {}
335    }
336
337    @Test
338    public void test_readAttributes() throws IOException {
339        FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis() - 10000);
340        Files.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", fileTime);
341        BasicFileAttributes basicFileAttributes = provider
342                .readAttributes(filesSetup.getDataFilePath(),
343                BasicFileAttributes.class);
344        FileTime lastModifiedTime = basicFileAttributes.lastModifiedTime();
345        assertEquals(fileTime.to(TimeUnit.SECONDS), lastModifiedTime.to(TimeUnit.SECONDS));
346
347        // When file is NON_EXISTENT.
348        try {
349            provider.readAttributes(filesSetup.getTestPath(), BasicFileAttributes.class);
350            fail();
351        } catch (NoSuchFileException expected) {}
352    }
353
354    @Test
355    public void test_readAttributes_NPE() throws IOException {
356        try {
357            provider.readAttributes(filesSetup.getDataFilePath(),
358                    (Class<BasicFileAttributes>) null);
359            fail();
360        } catch(NullPointerException expected) {}
361
362        try {
363            provider.readAttributes(null, BasicFileAttributes.class);
364            fail();
365        } catch(NullPointerException expected) {}
366    }
367
368    @Test
369    public void test_setAttribute() throws IOException {
370        // Other tests are covered in test_readAttributes.
371        // When file is NON_EXISTENT.
372        try {
373            FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis());
374            provider.setAttribute(filesSetup.getTestPath(), "basic:lastModifiedTime", fileTime);
375            fail();
376        } catch (NoSuchFileException expected) {}
377
378        // ClassCastException
379        try {
380            provider.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", 10);
381            fail();
382        } catch (ClassCastException expected) {}
383
384        // IllegalArgumentException
385        try {
386            provider.setAttribute(filesSetup.getDataFilePath(), "xyz", 10);
387            fail();
388        } catch (IllegalArgumentException expected) {}
389
390        try {
391            provider.setAttribute(null, "xyz", 10);
392            fail();
393        } catch (NullPointerException expected) {}
394
395        try {
396            provider.setAttribute(filesSetup.getDataFilePath(), null, 10);
397            fail();
398        } catch (NullPointerException expected) {}
399    }
400
401    @Test
402    public void test_newFileChannel() throws IOException {
403        Set<OpenOption> openOptions = new HashSet<>();
404
405        // When file doesn't exist/
406        try {
407            // With CREATE & WRITE in OpenOptions.
408            openOptions.add(CREATE);
409            openOptions.add(WRITE);
410            provider.newFileChannel(filesSetup.getTestPath(), openOptions);
411            assertTrue(Files.exists(filesSetup.getTestPath()));
412            Files.delete(filesSetup.getTestPath());
413        } finally {
414            filesSetup.reset();
415            openOptions.clear();
416        }
417
418        try {
419            // With CREATE & APPEND in OpenOption.
420            assertFalse(Files.exists(filesSetup.getTestPath()));
421            openOptions.add(CREATE);
422            openOptions.add(APPEND);
423            provider.newFileChannel(filesSetup.getTestPath(), openOptions);
424            assertTrue(Files.exists(filesSetup.getTestPath()));
425            Files.delete(filesSetup.getTestPath());
426        } finally {
427            filesSetup.reset();
428            openOptions.clear();
429        }
430
431        // When file exists.
432        try {
433            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
434            assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc));
435        } finally {
436            filesSetup.reset();
437            openOptions.clear();
438        }
439
440        try {
441            // When file exists and READ in OpenOptions.
442            openOptions.add(READ);
443            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
444            assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc));
445        } finally {
446            filesSetup.reset();
447            openOptions.clear();
448        }
449
450        // Reading from a file opened with WRITE.
451        try {
452            openOptions.add(WRITE);
453            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
454            assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc));
455            fail();
456        } catch (NonReadableChannelException expected) {
457        } finally {
458            filesSetup.reset();
459            openOptions.clear();
460        }
461
462        // Writing to an exiting file.
463        try {
464            openOptions.add(WRITE);
465            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
466            writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2);
467            fc.close();
468            assertEquals(overlayString1OnString2(TEST_FILE_DATA_2, TEST_FILE_DATA),
469                    readFromFile(filesSetup.getDataFilePath()));
470        } finally {
471            filesSetup.reset();
472            openOptions.clear();
473        }
474
475        // APPEND to an existing file.
476        try {
477            openOptions.add(WRITE);
478            openOptions.add(TRUNCATE_EXISTING);
479            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
480            writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2);
481            fc.close();
482            assertEquals(TEST_FILE_DATA_2, readFromFile(filesSetup.getDataFilePath()));
483        } finally {
484            filesSetup.reset();
485            openOptions.clear();
486        }
487
488        // TRUNCATE an existing file.
489        try {
490            openOptions.add(WRITE);
491            openOptions.add(APPEND);
492            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
493            writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2);
494            fc.close();
495            assertEquals(TEST_FILE_DATA + TEST_FILE_DATA_2, readFromFile(filesSetup.getDataFilePath()));
496        } finally {
497            filesSetup.reset();
498            openOptions.clear();
499        }
500    }
501
502    @Test
503    @Parameters(method = "parameters_test_newFileChannel_NoSuchFileException")
504    public void test_newFileChannel_NoSuchFileException(Set<? extends OpenOption> openOptions)
505            throws IOException {
506        try {
507            provider.newFileChannel(filesSetup.getTestPath(), openOptions);
508            fail();
509        } catch (NoSuchFileException expected) {}
510    }
511
512    @SuppressWarnings("unused")
513    private Object[] parameters_test_newFileChannel_NoSuchFileException() {
514        return new Object[] {
515                new Object[] { EnumSet.noneOf(StandardOpenOption.class) },
516                new Object[] { EnumSet.of(READ) },
517                new Object[] { EnumSet.of(WRITE) },
518                new Object[] { EnumSet.of(TRUNCATE_EXISTING) },
519                new Object[] { EnumSet.of(APPEND) },
520                new Object[] { EnumSet.of(CREATE, READ) },
521                new Object[] { EnumSet.of(CREATE, TRUNCATE_EXISTING) },
522                new Object[] { EnumSet.of(CREATE, READ) },
523        };
524    }
525
526    @Test
527    public void test_newFileChannel_withFileAttributes() throws IOException {
528        Set<OpenOption> openOptions = new HashSet<>();
529        FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis());
530        Files.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", fileTime);
531        FileAttribute<FileTime> unsupportedAttr = new MockFileAttribute<>(
532                "basic:lastModifiedTime", fileTime);
533
534        Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rwx------");
535        FileAttribute<Set<PosixFilePermission>> supportedAttr =
536                PosixFilePermissions.asFileAttribute(perm);
537
538        try {
539            // When file doesn't exists and with OpenOption CREATE & WRITE.
540            openOptions.clear();
541            openOptions.add(CREATE);
542            openOptions.add(WRITE);
543            provider.newFileChannel(filesSetup.getTestPath(), openOptions, unsupportedAttr);
544            fail();
545        } catch (UnsupportedOperationException expected) {
546        } finally {
547            filesSetup.reset();
548            openOptions.clear();
549        }
550
551        try {
552            // With OpenOption CREATE & WRITE.
553            openOptions.clear();
554            openOptions.add(CREATE);
555            openOptions.add(WRITE);
556            provider.newFileChannel(filesSetup.getTestPath(), openOptions, supportedAttr);
557            assertEquals(supportedAttr.value(), Files.getAttribute(filesSetup.getTestPath(),
558                    supportedAttr.name()));
559        } finally {
560            filesSetup.reset();
561            openOptions.clear();
562        }
563
564        // When file exists.
565        try {
566            provider.newFileChannel(filesSetup.getDataFilePath(), openOptions,
567                    unsupportedAttr);
568            fail();
569        } catch (UnsupportedOperationException expected) {
570        } finally {
571            filesSetup.reset();
572            openOptions.clear();
573        }
574
575        // When file exists. No change in permissions.
576        try {
577            Set<PosixFilePermission> originalPermissions= (Set<PosixFilePermission>)
578                    Files.getAttribute(filesSetup.getDataFilePath(), supportedAttr.name());
579            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions,
580                    supportedAttr);
581            assertEquals(originalPermissions, Files.getAttribute(filesSetup.getDataFilePath(),
582                    supportedAttr.name()));
583        } finally {
584            filesSetup.reset();
585            openOptions.clear();
586        }
587    }
588
589
590    @Test
591    public void test_newFileChannel_NPE() throws IOException {
592        try {
593            provider.newByteChannel(null, new HashSet<>(), new MockFileAttribute<>());
594            fail();
595        } catch (NullPointerException expected) {}
596
597        try {
598            provider.newByteChannel(filesSetup.getTestPath(), null, new MockFileAttribute<>());
599            fail();
600        } catch (NullPointerException expected) {}
601
602        try {
603            provider.newByteChannel(filesSetup.getTestPath(), new HashSet<>(), null);
604            fail();
605        } catch (NullPointerException expected) {}
606    }
607
608    @Test
609    public void test_getPath() throws Exception {
610        List<LinuxFileSystemTestData.TestData> inputOutputTestCases = getPath_URI_InputOutputTestData();
611        for (LinuxFileSystemTestData.TestData inputOutputTestCase : inputOutputTestCases) {
612            assertEquals(inputOutputTestCase.output,
613                    provider.getPath(new URI(inputOutputTestCase.input)).toString());
614        }
615
616        // When URI is null.
617        try {
618            provider.getPath(null);
619            fail();
620        } catch (NullPointerException expected) {}
621
622        // When Schema is not supported.
623        try {
624            provider.getPath(new URI("scheme://d"));
625            fail();
626        } catch (IllegalArgumentException expected) {}
627    }
628
629    @Test
630    public void test_getScheme() {
631        assertEquals("file", provider.getScheme());
632    }
633
634    @Test
635    public void test_installedProviders() {
636        assertNotNull(provider.installedProviders());
637    }
638
639    @Test
640    public void test_newFileSystem$URI$Map() throws Exception {
641        Path testPath = Paths.get("/");
642        assertNotNull(provider.getFileSystem(testPath.toUri()));
643
644        try {
645            provider.getFileSystem(null);
646            fail();
647        } catch (NullPointerException expected) {}
648
649        // Test the case when URI has illegal scheme.
650        URI stubURI = new URI("scheme://path");
651        try {
652            provider.getFileSystem(stubURI);
653            fail();
654        } catch (IllegalArgumentException expected) {}
655    }
656
657    String readFromFileChannel(FileChannel fc) throws IOException {
658        ByteBuffer bb = ByteBuffer.allocate(20);
659        fc.read(bb);
660        return new String(bb.array(), "UTF-8").trim();
661    }
662
663    void writeToFileChannel(FileChannel fc, String data) throws IOException {
664        fc.write(ByteBuffer.wrap(data.getBytes()));
665    }
666
667    String overlayString1OnString2(String s1, String s2) {
668        return s1 + s2.substring(s1.length());
669    }
670
671    static class MockFileAttribute<T> implements FileAttribute {
672
673        String name;
674        T value;
675
676        MockFileAttribute() {
677        }
678
679        MockFileAttribute(String name, T value) {
680            this.name = name;
681            this.value = value;
682        }
683
684        @Override
685        public String name() {
686            return name;
687        }
688
689        @Override
690        public T value() {
691            return value;
692        }
693    }
694}
695