Home | History | Annotate | Download | only in io
      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 
     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 
     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 
     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 
     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 
    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 
    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 
    151     public BadLengthFile(File delegate, long badLength) {
    152       super(delegate.getPath());
    153       this.badLength = badLength;
    154     }
    155 
    156     @Override
    157     public long length() {
    158       return badLength;
    159     }
    160 
    161     private static final long serialVersionUID = 0;
    162   }
    163 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    488     public boolean renameTo(File to) {
    489       return canRename && super.renameTo(to);
    490     }
    491 
    492     @Override
    493     public boolean delete() {
    494       return canDelete && super.delete();
    495     }
    496 
    497     private static final long serialVersionUID = 0;
    498   }
    499 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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    */
    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    */
    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    */
    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