FileInputStreamTest.java revision e3603abc77118773fc0cf5892be0df4056b1fb57
1/* 2 * Copyright (C) 2010 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.io; 18 19import java.io.File; 20import java.io.FileDescriptor; 21import java.io.FileInputStream; 22import java.io.FileNotFoundException; 23import java.io.FileOutputStream; 24import java.io.IOException; 25import java.util.ArrayList; 26import java.util.List; 27 28import android.system.ErrnoException; 29import android.system.OsConstants; 30import junit.framework.TestCase; 31 32import libcore.io.IoUtils; 33import libcore.io.Libcore; 34 35public final class FileInputStreamTest extends TestCase { 36 private static final int TOTAL_SIZE = 1024; 37 private static final int SKIP_SIZE = 100; 38 39 private static class DataFeeder extends Thread { 40 private FileDescriptor mOutFd; 41 42 public DataFeeder(FileDescriptor fd) { 43 mOutFd = fd; 44 } 45 46 @Override 47 public void run() { 48 try { 49 FileOutputStream fos = new FileOutputStream(mOutFd); 50 try { 51 byte[] buffer = new byte[TOTAL_SIZE]; 52 for (int i = 0; i < buffer.length; ++i) { 53 buffer[i] = (byte) i; 54 } 55 fos.write(buffer); 56 } finally { 57 IoUtils.closeQuietly(fos); 58 IoUtils.close(mOutFd); 59 } 60 } catch (IOException e) { 61 throw new RuntimeException(e); 62 } 63 } 64 } 65 66 private void verifyData(FileInputStream is, int start, int count) throws IOException { 67 byte buffer[] = new byte[count]; 68 assertEquals(count, is.read(buffer)); 69 for (int i = 0; i < count; ++i) { 70 assertEquals((byte) (i + start), buffer[i]); 71 } 72 } 73 74 public void testSkipInPipes() throws Exception { 75 FileDescriptor[] pipe = Libcore.os.pipe2(0); 76 DataFeeder feeder = new DataFeeder(pipe[1]); 77 try { 78 feeder.start(); 79 FileInputStream fis = new FileInputStream(pipe[0]); 80 fis.skip(SKIP_SIZE); 81 verifyData(fis, SKIP_SIZE, TOTAL_SIZE - SKIP_SIZE); 82 assertEquals(-1, fis.read()); 83 feeder.join(1000); 84 assertFalse(feeder.isAlive()); 85 } finally { 86 IoUtils.closeQuietly(pipe[0]); 87 } 88 } 89 90 public void testDirectories() throws Exception { 91 try { 92 new FileInputStream("."); 93 fail(); 94 } catch (FileNotFoundException expected) { 95 } 96 } 97 98 private File makeFile() throws Exception { 99 File tmp = File.createTempFile("FileOutputStreamTest", "tmp"); 100 FileOutputStream fos = new FileOutputStream(tmp); 101 fos.write(1); 102 fos.write(1); 103 fos.close(); 104 return tmp; 105 } 106 107 public void testFileDescriptorOwnership() throws Exception { 108 File tmp = makeFile(); 109 110 FileInputStream fis1 = new FileInputStream(tmp); 111 FileInputStream fis2 = new FileInputStream(fis1.getFD()); 112 113 // Close the second FileDescriptor and check we can't use it... 114 fis2.close(); 115 116 try { 117 fis2.available(); 118 fail(); 119 } catch (IOException expected) { 120 } 121 try { 122 fis2.read(); 123 fail(); 124 } catch (IOException expected) { 125 } 126 try { 127 fis2.read(new byte[1], 0, 1); 128 fail(); 129 } catch (IOException expected) { 130 } 131 try { 132 fis2.skip(1); 133 fail(); 134 } catch (IOException expected) { 135 } 136 // ...but that we can still use the first. 137 assertTrue(fis1.getFD().valid()); 138 assertFalse(fis1.read() == -1); 139 140 // Close the first FileDescriptor and check we can't use it... 141 fis1.close(); 142 try { 143 fis1.available(); 144 fail(); 145 } catch (IOException expected) { 146 } 147 try { 148 fis1.read(); 149 fail(); 150 } catch (IOException expected) { 151 } 152 try { 153 fis1.read(new byte[1], 0, 1); 154 fail(); 155 } catch (IOException expected) { 156 } 157 try { 158 fis1.skip(1); 159 fail(); 160 } catch (IOException expected) { 161 } 162 163 // FD is no longer owned by any stream, should be invalidated. 164 assertFalse(fis1.getFD().valid()); 165 } 166 167 public void testClose() throws Exception { 168 File tmp = makeFile(); 169 FileInputStream fis = new FileInputStream(tmp); 170 171 // Closing an already-closed stream is a no-op... 172 fis.close(); 173 fis.close(); 174 175 // But any explicit activity is an error. 176 try { 177 fis.available(); 178 fail(); 179 } catch (IOException expected) { 180 } 181 try { 182 fis.read(); 183 fail(); 184 } catch (IOException expected) { 185 } 186 try { 187 fis.read(new byte[1], 0, 1); 188 fail(); 189 } catch (IOException expected) { 190 } 191 try { 192 fis.skip(1); 193 fail(); 194 } catch (IOException expected) { 195 } 196 // Including 0-byte skips... 197 try { 198 fis.skip(0); 199 fail(); 200 } catch (IOException expected) { 201 } 202 // ...but not 0-byte reads... 203 fis.read(new byte[0], 0, 0); 204 } 205 206 // http://b/26117827 207 public void testReadProcVersion() throws IOException { 208 File file = new File("/proc/version"); 209 FileInputStream input = new FileInputStream(file); 210 assertTrue(input.available() == 0); 211 } 212 213 // http://b/25695227 214 public void testFdLeakWhenOpeningDirectory() throws Exception { 215 File phile = IoUtils.createTemporaryDirectory("test_bug_25695227"); 216 217 try { 218 new FileInputStream(phile); 219 fail(); 220 } catch (FileNotFoundException expected) { 221 } 222 223 assertTrue(getOpenFdsForPrefix("test_bug_25695227").isEmpty()); 224 } 225 226 private static List<Integer> getOpenFdsForPrefix(String path) throws Exception { 227 File[] fds = new File("/proc/self/fd").listFiles(); 228 List<Integer> list = new ArrayList<>(); 229 for (File fd : fds) { 230 try { 231 File fdPath = new File(android.system.Os.readlink(fd.getAbsolutePath())); 232 if (fdPath.getName().startsWith(path)) { 233 list.add(Integer.valueOf(fd.getName())); 234 } 235 } catch (ErrnoException e) { 236 if (e.errno != OsConstants.ENOENT) { 237 throw e.rethrowAsIOException(); 238 } 239 } 240 } 241 242 return list; 243 } 244} 245