1 /*
2  * Copyright (C) 2007 The Guava Authors
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.google.common.io;
18 
19 import static com.google.common.io.Files.createTempDir;
20 import static com.google.common.io.Files.touch;
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import com.google.common.base.Charsets;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.hash.Hashing;
26 import com.google.common.primitives.Bytes;
27 
28 import junit.framework.TestSuite;
29 
30 import java.io.BufferedReader;
31 import java.io.BufferedWriter;
32 import java.io.ByteArrayOutputStream;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.FileNotFoundException;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.PrintWriter;
39 import java.io.RandomAccessFile;
40 import java.nio.ByteBuffer;
41 import java.nio.MappedByteBuffer;
42 import java.nio.channels.FileChannel.MapMode;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.List;
46 import java.util.Random;
47 
48 /**
49  * Unit test for {@link Files}.
50  *
51  * @author Chris Nokleberg
52  */
53 public class FilesTest extends IoTestCase {
54 
suite()55   public static TestSuite suite() {
56     TestSuite suite = new TestSuite();
57     suite.addTest(ByteSourceTester.tests("Files.asByteSource[File]",
58         SourceSinkFactories.fileByteSourceFactory(), true));
59     suite.addTest(ByteSinkTester.tests("Files.asByteSink[File]",
60         SourceSinkFactories.fileByteSinkFactory()));
61     suite.addTest(ByteSinkTester.tests("Files.asByteSink[File, APPEND]",
62         SourceSinkFactories.appendingFileByteSinkFactory()));
63     suite.addTest(CharSourceTester.tests("Files.asCharSource[File, Charset]",
64         SourceSinkFactories.fileCharSourceFactory()));
65     suite.addTest(CharSinkTester.tests("Files.asCharSink[File, Charset]",
66         SourceSinkFactories.fileCharSinkFactory()));
67     suite.addTest(CharSinkTester.tests("Files.asCharSink[File, Charset, APPEND]",
68         SourceSinkFactories.appendingFileCharSinkFactory()));
69     suite.addTestSuite(FilesTest.class);
70     return suite;
71   }
72 
testToByteArray()73   public void testToByteArray() throws IOException {
74     File asciiFile = getTestFile("ascii.txt");
75     File i18nFile = getTestFile("i18n.txt");
76     assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII),
77         Files.toByteArray(asciiFile)));
78     assertTrue(Arrays.equals(I18N.getBytes(Charsets.UTF_8),
79         Files.toByteArray(i18nFile)));
80     assertTrue(Arrays.equals(I18N.getBytes(Charsets.UTF_8),
81         Files.asByteSource(i18nFile).read()));
82   }
83 
testReadFile_withCorrectSize()84   public void testReadFile_withCorrectSize() throws IOException {
85     File asciiFile = getTestFile("ascii.txt");
86 
87     Closer closer = Closer.create();
88     try {
89       InputStream in = closer.register(new FileInputStream(asciiFile));
90       byte[] bytes = Files.readFile(in, asciiFile.length());
91       assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII), bytes));
92     } catch (Throwable e) {
93       throw closer.rethrow(e);
94     } finally {
95       closer.close();
96     }
97   }
98 
testReadFile_withSmallerSize()99   public void testReadFile_withSmallerSize() throws IOException {
100     File asciiFile = getTestFile("ascii.txt");
101 
102     Closer closer = Closer.create();
103     try {
104       InputStream in = closer.register(new FileInputStream(asciiFile));
105       byte[] bytes = Files.readFile(in, 10);
106       assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII), bytes));
107     } catch (Throwable e) {
108       throw closer.rethrow(e);
109     } finally {
110       closer.close();
111     }
112   }
113 
testReadFile_withLargerSize()114   public void testReadFile_withLargerSize() throws IOException {
115     File asciiFile = getTestFile("ascii.txt");
116 
117     Closer closer = Closer.create();
118     try {
119       InputStream in = closer.register(new FileInputStream(asciiFile));
120       byte[] bytes = Files.readFile(in, 500);
121       assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII), bytes));
122     } catch (Throwable e) {
123       throw closer.rethrow(e);
124     } finally {
125       closer.close();
126     }
127   }
128 
testReadFile_withSizeZero()129   public void testReadFile_withSizeZero() throws IOException {
130     File asciiFile = getTestFile("ascii.txt");
131 
132     Closer closer = Closer.create();
133     try {
134       InputStream in = closer.register(new FileInputStream(asciiFile));
135       byte[] bytes = Files.readFile(in, 0);
136       assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII), bytes));
137     } catch (Throwable e) {
138       throw closer.rethrow(e);
139     } finally {
140       closer.close();
141     }
142   }
143 
144   /**
145    * A {@link File} that provides a specialized value for {link File#length()}.
146    */
147   private static class BadLengthFile extends File {
148 
149     private final long badLength;
150 
BadLengthFile(File delegate, long badLength)151     public BadLengthFile(File delegate, long badLength) {
152       super(delegate.getPath());
153       this.badLength = badLength;
154     }
155 
156     @Override
length()157     public long length() {
158       return badLength;
159     }
160 
161     private static final long serialVersionUID = 0;
162   }
163 
testToString()164   public void testToString() throws IOException {
165     File asciiFile = getTestFile("ascii.txt");
166     File i18nFile = getTestFile("i18n.txt");
167     assertEquals(ASCII, Files.toString(asciiFile, Charsets.US_ASCII));
168     assertEquals(I18N, Files.toString(i18nFile, Charsets.UTF_8));
169     assertThat(Files.toString(i18nFile, Charsets.US_ASCII))
170         .isNotEqualTo(I18N);
171   }
172 
testWriteString()173   public void testWriteString() throws IOException {
174     File temp = createTempFile();
175     Files.write(I18N, temp, Charsets.UTF_16LE);
176     assertEquals(I18N, Files.toString(temp, Charsets.UTF_16LE));
177   }
178 
testWriteBytes()179   public void testWriteBytes() throws IOException {
180     File temp = createTempFile();
181     byte[] data = newPreFilledByteArray(2000);
182     Files.write(data, temp);
183     assertTrue(Arrays.equals(data, Files.toByteArray(temp)));
184 
185     try {
186       Files.write(null, temp);
187       fail("expected exception");
188     } catch (NullPointerException expected) {
189     }
190   }
191 
testAppendString()192   public void testAppendString() throws IOException {
193     File temp = createTempFile();
194     Files.append(I18N, temp, Charsets.UTF_16LE);
195     assertEquals(I18N, Files.toString(temp, Charsets.UTF_16LE));
196     Files.append(I18N, temp, Charsets.UTF_16LE);
197     assertEquals(I18N + I18N, Files.toString(temp, Charsets.UTF_16LE));
198     Files.append(I18N, temp, Charsets.UTF_16LE);
199     assertEquals(I18N + I18N + I18N, Files.toString(temp, Charsets.UTF_16LE));
200   }
201 
testCopyToOutputStream()202   public void testCopyToOutputStream() throws IOException {
203     File i18nFile = getTestFile("i18n.txt");
204     ByteArrayOutputStream out = new ByteArrayOutputStream();
205     Files.copy(i18nFile, out);
206     assertEquals(I18N, out.toString("UTF-8"));
207   }
208 
testCopyToAppendable()209   public void testCopyToAppendable() throws IOException {
210     File i18nFile = getTestFile("i18n.txt");
211     StringBuilder sb = new StringBuilder();
212     Files.copy(i18nFile, Charsets.UTF_8, sb);
213     assertEquals(I18N, sb.toString());
214   }
215 
testCopyFile()216   public void testCopyFile() throws IOException {
217     File i18nFile = getTestFile("i18n.txt");
218     File temp = createTempFile();
219     Files.copy(i18nFile, temp);
220     assertEquals(I18N, Files.toString(temp, Charsets.UTF_8));
221   }
222 
testCopyEqualFiles()223   public void testCopyEqualFiles() throws IOException {
224     File temp1 = createTempFile();
225     File temp2 = file(temp1.getPath());
226     assertEquals(temp1, temp2);
227     Files.write(ASCII, temp1, Charsets.UTF_8);
228     try {
229       Files.copy(temp1, temp2);
230       fail("Expected an IAE to be thrown but wasn't");
231     } catch (IllegalArgumentException expected) {
232     }
233     assertEquals(ASCII, Files.toString(temp1, Charsets.UTF_8));
234   }
235 
testCopySameFile()236   public void testCopySameFile() throws IOException {
237     File temp = createTempFile();
238     Files.write(ASCII, temp, Charsets.UTF_8);
239     try {
240       Files.copy(temp, temp);
241       fail("Expected an IAE to be thrown but wasn't");
242     } catch (IllegalArgumentException expected) {
243     }
244     assertEquals(ASCII, Files.toString(temp, Charsets.UTF_8));
245   }
246 
testCopyIdenticalFiles()247   public void testCopyIdenticalFiles() throws IOException {
248     File temp1 = createTempFile();
249     Files.write(ASCII, temp1, Charsets.UTF_8);
250     File temp2 = createTempFile();
251     Files.write(ASCII, temp2, Charsets.UTF_8);
252     Files.copy(temp1, temp2);
253     assertEquals(ASCII, Files.toString(temp1, Charsets.UTF_8));
254   }
255 
testEqual()256   public void testEqual() throws IOException {
257     File asciiFile = getTestFile("ascii.txt");
258     File i18nFile = getTestFile("i18n.txt");
259     assertFalse(Files.equal(asciiFile, i18nFile));
260     assertTrue(Files.equal(asciiFile, asciiFile));
261 
262     File temp = createTempFile();
263     Files.copy(asciiFile, temp);
264     assertTrue(Files.equal(asciiFile, temp));
265 
266     Files.copy(i18nFile, temp);
267     assertTrue(Files.equal(i18nFile, temp));
268 
269     Files.copy(asciiFile, temp);
270     RandomAccessFile rf = new RandomAccessFile(temp, "rw");
271     rf.writeByte(0);
272     rf.close();
273     assertEquals(asciiFile.length(), temp.length());
274     assertFalse(Files.equal(asciiFile, temp));
275 
276     assertTrue(Files.asByteSource(asciiFile)
277         .contentEquals(Files.asByteSource(asciiFile)));
278 
279     // 0-length files have special treatment (/proc, etc.)
280     assertTrue(Files.equal(asciiFile, new BadLengthFile(asciiFile, 0)));
281   }
282 
testNewReader()283   public void testNewReader() throws IOException {
284     File asciiFile = getTestFile("ascii.txt");
285     try {
286       Files.newReader(asciiFile, null);
287       fail("expected exception");
288     } catch (NullPointerException expected) {
289     }
290 
291     try {
292       Files.newReader(null, Charsets.UTF_8);
293       fail("expected exception");
294     } catch (NullPointerException expected) {
295     }
296 
297     BufferedReader r = Files.newReader(asciiFile, Charsets.US_ASCII);
298     try {
299       assertEquals(ASCII, r.readLine());
300     } finally {
301       r.close();
302     }
303   }
304 
testNewWriter()305   public void testNewWriter() throws IOException {
306     File temp = createTempFile();
307     try {
308       Files.newWriter(temp, null);
309       fail("expected exception");
310     } catch (NullPointerException expected) {
311     }
312 
313     try {
314       Files.newWriter(null, Charsets.UTF_8);
315       fail("expected exception");
316     } catch (NullPointerException expected) {
317     }
318 
319     BufferedWriter w = Files.newWriter(temp, Charsets.UTF_8);
320     try {
321       w.write(I18N);
322     } finally {
323       w.close();
324     }
325 
326     File i18nFile = getTestFile("i18n.txt");
327     assertTrue(Files.equal(i18nFile, temp));
328   }
329 
testTouch()330   public void testTouch() throws IOException {
331     File temp = createTempFile();
332     assertTrue(temp.exists());
333     assertTrue(temp.delete());
334     assertFalse(temp.exists());
335     Files.touch(temp);
336     assertTrue(temp.exists());
337     Files.touch(temp);
338     assertTrue(temp.exists());
339 
340     try {
341       Files.touch(new File(temp.getPath()) {
342         @Override
343         public boolean setLastModified(long t) {
344           return false;
345         }
346 
347         private static final long serialVersionUID = 0;
348       });
349       fail("expected exception");
350     } catch (IOException expected) {
351     }
352   }
353 
testTouchTime()354   public void testTouchTime() throws IOException {
355     File temp = createTempFile();
356     assertTrue(temp.exists());
357     temp.setLastModified(0);
358     assertEquals(0, temp.lastModified());
359     Files.touch(temp);
360     assertThat(temp.lastModified()).isNotEqualTo(0);
361   }
362 
testCreateParentDirs_root()363   public void testCreateParentDirs_root() throws IOException {
364     File file = root();
365     assertNull(file.getParentFile());
366     assertNull(file.getCanonicalFile().getParentFile());
367     Files.createParentDirs(file);
368   }
369 
testCreateParentDirs_relativePath()370   public void testCreateParentDirs_relativePath() throws IOException {
371     File file = file("nonexistent.file");
372     assertNull(file.getParentFile());
373     assertNotNull(file.getCanonicalFile().getParentFile());
374     Files.createParentDirs(file);
375   }
376 
testCreateParentDirs_noParentsNeeded()377   public void testCreateParentDirs_noParentsNeeded() throws IOException {
378     File file = file(getTempDir(), "nonexistent.file");
379     assertTrue(file.getParentFile().exists());
380     Files.createParentDirs(file);
381   }
382 
testCreateParentDirs_oneParentNeeded()383   public void testCreateParentDirs_oneParentNeeded() throws IOException {
384     File file = file(getTempDir(), "parent", "nonexistent.file");
385     File parent = file.getParentFile();
386     assertFalse(parent.exists());
387     try {
388       Files.createParentDirs(file);
389       assertTrue(parent.exists());
390     } finally {
391       assertTrue(parent.delete());
392     }
393   }
394 
testCreateParentDirs_multipleParentsNeeded()395   public void testCreateParentDirs_multipleParentsNeeded() throws IOException {
396     File file = file(getTempDir(), "grandparent", "parent", "nonexistent.file");
397     File parent = file.getParentFile();
398     File grandparent = parent.getParentFile();
399     assertFalse(grandparent.exists());
400     Files.createParentDirs(file);
401     assertTrue(parent.exists());
402   }
403 
testCreateParentDirs_nonDirectoryParentExists()404   public void testCreateParentDirs_nonDirectoryParentExists() throws IOException {
405     File parent = getTestFile("ascii.txt");
406     assertTrue(parent.isFile());
407     File file = file(parent, "foo");
408     try {
409       Files.createParentDirs(file);
410       fail();
411     } catch (IOException expected) {
412     }
413   }
414 
testCreateTempDir()415   public void testCreateTempDir() {
416     File temp = Files.createTempDir();
417     assertTrue(temp.exists());
418     assertTrue(temp.isDirectory());
419     assertEquals(0, temp.listFiles().length);
420     assertTrue(temp.delete());
421   }
422 
testMove()423   public void testMove() throws IOException {
424     File i18nFile = getTestFile("i18n.txt");
425     File temp1 = createTempFile();
426     File temp2 = createTempFile();
427 
428     Files.copy(i18nFile, temp1);
429     moveHelper(true, temp1, temp2);
430     assertTrue(Files.equal(temp2, i18nFile));
431   }
432 
testMoveViaCopy()433   public void testMoveViaCopy() throws IOException {
434     File i18nFile = getTestFile("i18n.txt");
435     File temp1 = createTempFile();
436     File temp2 = createTempFile();
437 
438     Files.copy(i18nFile, temp1);
439     moveHelper(true, new UnmovableFile(temp1, false, true), temp2);
440     assertTrue(Files.equal(temp2, i18nFile));
441   }
442 
testMoveFailures()443   public void testMoveFailures() throws IOException {
444     File temp1 = createTempFile();
445     File temp2 = createTempFile();
446 
447     moveHelper(false, new UnmovableFile(temp1, false, false), temp2);
448     moveHelper(false, new UnmovableFile(temp1, false, false),
449         new UnmovableFile(temp2, true, false));
450 
451     try {
452       File asciiFile = getTestFile("ascii.txt");
453       moveHelper(false, asciiFile, asciiFile);
454       fail("expected exception");
455     } catch (IllegalArgumentException expected) {
456     }
457   }
458 
moveHelper(boolean success, File from, File to)459   private void moveHelper(boolean success, File from, File to)
460       throws IOException {
461     try {
462       Files.move(from, to);
463       if (success) {
464         assertFalse(from.exists());
465         assertTrue(to.exists());
466       } else {
467         fail("expected exception");
468       }
469     } catch (IOException possiblyExpected) {
470       if (success) {
471         throw possiblyExpected;
472       }
473     }
474   }
475 
476   private static class UnmovableFile extends File {
477 
478     private final boolean canRename;
479     private final boolean canDelete;
480 
UnmovableFile(File file, boolean canRename, boolean canDelete)481     public UnmovableFile(File file, boolean canRename, boolean canDelete) {
482       super(file.getPath());
483       this.canRename = canRename;
484       this.canDelete = canDelete;
485     }
486 
487     @Override
renameTo(File to)488     public boolean renameTo(File to) {
489       return canRename && super.renameTo(to);
490     }
491 
492     @Override
delete()493     public boolean delete() {
494       return canDelete && super.delete();
495     }
496 
497     private static final long serialVersionUID = 0;
498   }
499 
testLineReading()500   public void testLineReading() throws IOException {
501     File temp = createTempFile();
502     assertNull(Files.readFirstLine(temp, Charsets.UTF_8));
503     assertTrue(Files.readLines(temp, Charsets.UTF_8).isEmpty());
504 
505     PrintWriter w = new PrintWriter(Files.newWriter(temp, Charsets.UTF_8));
506     w.println("hello");
507     w.println("");
508     w.println(" world  ");
509     w.println("");
510     w.close();
511 
512     assertEquals("hello", Files.readFirstLine(temp, Charsets.UTF_8));
513     assertEquals(ImmutableList.of("hello", "", " world  ", ""),
514         Files.readLines(temp, Charsets.UTF_8));
515 
516     assertTrue(temp.delete());
517   }
518 
testReadLines_withLineProcessor()519   public void testReadLines_withLineProcessor() throws IOException {
520     File temp = createTempFile();
521     LineProcessor<List<String>> collect = new LineProcessor<List<String>>() {
522       List<String> collector = new ArrayList<String>();
523 
524       @Override
525       public boolean processLine(String line) {
526         collector.add(line);
527         return true;
528       }
529 
530       @Override
531       public List<String> getResult() {
532         return collector;
533       }
534     };
535     assertThat(Files.readLines(temp, Charsets.UTF_8, collect)).isEmpty();
536 
537     PrintWriter w = new PrintWriter(Files.newWriter(temp, Charsets.UTF_8));
538     w.println("hello");
539     w.println("");
540     w.println(" world  ");
541     w.println("");
542     w.close();
543     Files.readLines(temp, Charsets.UTF_8, collect);
544     assertThat(collect.getResult())
545         .has().exactly("hello", "", " world  ", "").inOrder();
546 
547     LineProcessor<List<String>> collectNonEmptyLines =
548         new LineProcessor<List<String>>() {
549           List<String> collector = new ArrayList<String>();
550 
551           @Override
552           public boolean processLine(String line) {
553             if (line.length() > 0) {
554               collector.add(line);
555             }
556             return true;
557           }
558 
559           @Override
560           public List<String> getResult() {
561             return collector;
562           }
563         };
564     Files.readLines(temp, Charsets.UTF_8, collectNonEmptyLines);
565     assertThat(collectNonEmptyLines.getResult()).has().exactly(
566         "hello", " world  ").inOrder();
567 
568     assertTrue(temp.delete());
569   }
570 
testHash()571   public void testHash() throws IOException {
572     File asciiFile = getTestFile("ascii.txt");
573     File i18nFile = getTestFile("i18n.txt");
574 
575     String init = "d41d8cd98f00b204e9800998ecf8427e";
576     assertEquals(init, Hashing.md5().newHasher().hash().toString());
577 
578     String asciiHash = "e5df5a39f2b8cb71b24e1d8038f93131";
579     assertEquals(asciiHash, Files.hash(asciiFile, Hashing.md5()).toString());
580 
581     String i18nHash = "7fa826962ce2079c8334cd4ebf33aea4";
582     assertEquals(i18nHash, Files.hash(i18nFile, Hashing.md5()).toString());
583   }
584 
testMap()585   public void testMap() throws IOException {
586     // Test data
587     int size = 1024;
588     byte[] bytes = newPreFilledByteArray(size);
589 
590     // Setup
591     File file = createTempFile();
592     Files.write(bytes, file);
593 
594     // Test
595     MappedByteBuffer actual = Files.map(file);
596 
597     // Verify
598     ByteBuffer expected = ByteBuffer.wrap(bytes);
599     assertTrue("ByteBuffers should be equal.", expected.equals(actual));
600   }
601 
testMap_noSuchFile()602   public void testMap_noSuchFile() throws IOException {
603     // Setup
604     File file = createTempFile();
605     boolean deleted = file.delete();
606     assertTrue(deleted);
607 
608     // Test
609     try {
610       Files.map(file);
611       fail("Should have thrown FileNotFoundException.");
612     } catch (FileNotFoundException expected) {
613     }
614   }
615 
testMap_readWrite()616   public void testMap_readWrite() throws IOException {
617     // Test data
618     int size = 1024;
619     byte[] expectedBytes = new byte[size];
620     byte[] bytes = newPreFilledByteArray(1024);
621 
622     // Setup
623     File file = createTempFile();
624     Files.write(bytes, file);
625 
626     Random random = new Random();
627     random.nextBytes(expectedBytes);
628 
629     // Test
630     MappedByteBuffer map = Files.map(file, MapMode.READ_WRITE);
631     map.put(expectedBytes);
632 
633     // Verify
634     byte[] actualBytes = Files.toByteArray(file);
635     assertTrue(Arrays.equals(expectedBytes, actualBytes));
636   }
637 
testMap_readWrite_creates()638   public void testMap_readWrite_creates() throws IOException {
639     // Test data
640     int size = 1024;
641     byte[] expectedBytes = newPreFilledByteArray(1024);
642 
643     // Setup
644     File file = createTempFile();
645     boolean deleted = file.delete();
646     assertTrue(deleted);
647     assertFalse(file.exists());
648 
649     // Test
650     MappedByteBuffer map = Files.map(file, MapMode.READ_WRITE, size);
651     map.put(expectedBytes);
652 
653     // Verify
654     assertTrue(file.exists());
655     assertTrue(file.isFile());
656     assertEquals(size, file.length());
657     byte[] actualBytes = Files.toByteArray(file);
658     assertTrue(Arrays.equals(expectedBytes, actualBytes));
659   }
660 
testMap_readWrite_max_value_plus_1()661   public void testMap_readWrite_max_value_plus_1() throws IOException {
662     // Setup
663     File file = createTempFile();
664     // Test
665     try {
666       Files.map(file, MapMode.READ_WRITE, (long) Integer.MAX_VALUE + 1);
667       fail("Should throw when size exceeds Integer.MAX_VALUE");
668     } catch (IllegalArgumentException expected) {
669     }
670   }
671 
testGetFileExtension()672   public void testGetFileExtension() {
673     assertEquals("txt", Files.getFileExtension(".txt"));
674     assertEquals("txt", Files.getFileExtension("blah.txt"));
675     assertEquals("txt", Files.getFileExtension("blah..txt"));
676     assertEquals("txt", Files.getFileExtension(".blah.txt"));
677     assertEquals("txt", Files.getFileExtension("/tmp/blah.txt"));
678     assertEquals("gz", Files.getFileExtension("blah.tar.gz"));
679     assertEquals("", Files.getFileExtension("/"));
680     assertEquals("", Files.getFileExtension("."));
681     assertEquals("", Files.getFileExtension(".."));
682     assertEquals("", Files.getFileExtension("..."));
683     assertEquals("", Files.getFileExtension("blah"));
684     assertEquals("", Files.getFileExtension("blah."));
685     assertEquals("", Files.getFileExtension(".blah."));
686     assertEquals("", Files.getFileExtension("/foo.bar/blah"));
687     assertEquals("", Files.getFileExtension("/foo/.bar/blah"));
688   }
689 
testGetNameWithoutExtension()690   public void testGetNameWithoutExtension() {
691     assertEquals("", Files.getNameWithoutExtension(".txt"));
692     assertEquals("blah", Files.getNameWithoutExtension("blah.txt"));
693     assertEquals("blah.", Files.getNameWithoutExtension("blah..txt"));
694     assertEquals(".blah", Files.getNameWithoutExtension(".blah.txt"));
695     assertEquals("blah", Files.getNameWithoutExtension("/tmp/blah.txt"));
696     assertEquals("blah.tar", Files.getNameWithoutExtension("blah.tar.gz"));
697     assertEquals("", Files.getNameWithoutExtension("/"));
698     assertEquals("", Files.getNameWithoutExtension("."));
699     assertEquals(".", Files.getNameWithoutExtension(".."));
700     assertEquals("..", Files.getNameWithoutExtension("..."));
701     assertEquals("blah", Files.getNameWithoutExtension("blah"));
702     assertEquals("blah", Files.getNameWithoutExtension("blah."));
703     assertEquals(".blah", Files.getNameWithoutExtension(".blah."));
704     assertEquals("blah", Files.getNameWithoutExtension("/foo.bar/blah"));
705     assertEquals("blah", Files.getNameWithoutExtension("/foo/.bar/blah"));
706   }
707 
testReadBytes()708   public void testReadBytes() throws IOException {
709     ByteProcessor<byte[]> processor = new ByteProcessor<byte[]>() {
710       private final ByteArrayOutputStream out = new ByteArrayOutputStream();
711 
712       @Override
713       public boolean processBytes(byte[] buffer, int offset, int length) throws IOException {
714         if (length >= 0) {
715           out.write(buffer, offset, length);
716         }
717         return true;
718       }
719 
720       @Override
721       public byte[] getResult() {
722         return out.toByteArray();
723       }
724     };
725 
726     File asciiFile = getTestFile("ascii.txt");
727     byte[] result = Files.readBytes(asciiFile, processor);
728     assertEquals(Bytes.asList(Files.toByteArray(asciiFile)), Bytes.asList(result));
729   }
730 
testReadBytes_returnFalse()731   public void testReadBytes_returnFalse() throws IOException {
732     ByteProcessor<byte[]> processor = new ByteProcessor<byte[]>() {
733       private final ByteArrayOutputStream out = new ByteArrayOutputStream();
734 
735       @Override
736       public boolean processBytes(byte[] buffer, int offset, int length) throws IOException {
737         if (length > 0) {
738           out.write(buffer, offset, 1);
739           return false;
740         } else {
741           return true;
742         }
743       }
744 
745       @Override
746       public byte[] getResult() {
747         return out.toByteArray();
748       }
749     };
750 
751     File asciiFile = getTestFile("ascii.txt");
752     byte[] result = Files.readBytes(asciiFile, processor);
753     assertEquals(1, result.length);
754   }
755 
testPredicates()756   public void testPredicates() throws IOException {
757     File asciiFile = getTestFile("ascii.txt");
758     File dir = asciiFile.getParentFile();
759     assertTrue(Files.isDirectory().apply(dir));
760     assertFalse(Files.isFile().apply(dir));
761 
762     assertFalse(Files.isDirectory().apply(asciiFile));
763     assertTrue(Files.isFile().apply(asciiFile));
764   }
765 
766   /**
767    * Returns a root path for the file system.
768    */
root()769   private static File root() {
770     return File.listRoots()[0];
771   }
772 
773   /**
774    * Returns a {@code File} object for the given path parts.
775    */
file(String first, String... more)776   private static File file(String first, String... more) {
777     return file(new File(first), more);
778   }
779 
780   /**
781    * Returns a {@code File} object for the given path parts.
782    */
file(File first, String... more)783   private static File file(File first, String... more) {
784     // not very efficient, but should definitely be correct
785     File file = first;
786     for (String name : more) {
787       file = new File(file, name);
788     }
789     return file;
790   }
791 }
792