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.nio.channels; 18 19import java.io.File; 20import java.io.FileDescriptor; 21import java.io.FileInputStream; 22import java.io.FileOutputStream; 23import java.io.IOException; 24import java.io.RandomAccessFile; 25import java.nio.ByteBuffer; 26import java.nio.channels.FileChannel; 27import libcore.io.IoUtils; 28 29public class FileChannelTest extends junit.framework.TestCase { 30 public void testReadOnlyByteArrays() throws Exception { 31 ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer(); 32 File tmp = File.createTempFile("FileChannelTest", "tmp"); 33 34 // You can't read into a read-only buffer... 35 FileChannel fc = new FileInputStream(tmp).getChannel(); 36 try { 37 fc.read(readOnly); 38 fail(); 39 } catch (IllegalArgumentException expected) { 40 } 41 try { 42 fc.read(new ByteBuffer[] { readOnly }); 43 fail(); 44 } catch (IllegalArgumentException expected) { 45 } 46 try { 47 fc.read(new ByteBuffer[] { readOnly }, 0, 1); 48 fail(); 49 } catch (IllegalArgumentException expected) { 50 } 51 try { 52 fc.read(readOnly, 0L); 53 fail(); 54 } catch (IllegalArgumentException expected) { 55 } 56 fc.close(); 57 58 59 // But you can write from a read-only buffer... 60 fc = new FileOutputStream(tmp).getChannel(); 61 fc.write(readOnly); 62 fc.write(new ByteBuffer[] { readOnly }); 63 fc.write(new ByteBuffer[] { readOnly }, 0, 1); 64 fc.write(readOnly, 0L); 65 fc.close(); 66 } 67 68 public void test_readv() throws Exception { 69 File tmp = File.createTempFile("FileChannelTest", "tmp"); 70 FileChannel fc = new FileOutputStream(tmp).getChannel(); 71 fc.write(ByteBuffer.wrap("abcdABCD".getBytes("US-ASCII"))); 72 fc.close(); 73 // Check that both direct and non-direct buffers work. 74 fc = new FileInputStream(tmp).getChannel(); 75 ByteBuffer[] buffers = new ByteBuffer[] { ByteBuffer.allocateDirect(4), ByteBuffer.allocate(4) }; 76 assertEquals(8, fc.read(buffers)); 77 fc.close(); 78 assertEquals(8, buffers[0].limit() + buffers[1].limit()); 79 byte[] bytes = new byte[4]; 80 buffers[0].flip(); 81 buffers[0].get(bytes); 82 assertEquals("abcd", new String(bytes, "US-ASCII")); 83 buffers[1].flip(); 84 buffers[1].get(bytes); 85 assertEquals("ABCD", new String(bytes, "US-ASCII")); 86 } 87 88 public void test_writev() throws Exception { 89 File tmp = File.createTempFile("FileChannelTest", "tmp"); 90 FileChannel fc = new FileOutputStream(tmp).getChannel(); 91 // Check that both direct and non-direct buffers work. 92 ByteBuffer[] buffers = new ByteBuffer[] { ByteBuffer.allocateDirect(4), ByteBuffer.allocate(4) }; 93 buffers[0].put("abcd".getBytes("US-ASCII")).flip(); 94 buffers[1].put("ABCD".getBytes("US-ASCII")).flip(); 95 assertEquals(8, fc.write(buffers)); 96 fc.close(); 97 assertEquals(8, tmp.length()); 98 assertEquals("abcdABCD", new String(IoUtils.readFileAsString(tmp.getPath()))); 99 } 100 101 public void test_append() throws Exception { 102 File tmp = File.createTempFile("FileChannelTest", "tmp"); 103 FileOutputStream fos = new FileOutputStream(tmp, true); 104 FileChannel fc = fos.getChannel(); 105 106 fc.write(ByteBuffer.wrap("hello".getBytes("US-ASCII"))); 107 fc.position(0); 108 // The RI reports end of file 109 assertEquals(5, fc.position()); 110 // ...but writes to the end of the file. 111 fc.write(ByteBuffer.wrap(" world".getBytes("US-ASCII"))); 112 fos.close(); 113 114 assertEquals("hello world", new String(IoUtils.readFileAsString(tmp.getPath()))); 115 } 116 117 public void test_position_writeAddsPadding() throws Exception { 118 byte[] initialBytes = "12345".getBytes("US-ASCII"); 119 int initialFileSize = initialBytes.length; // 5 120 FileChannel fc = createFileContainingBytes(initialBytes); 121 122 int positionBeyondSize = 10; 123 fc.position(positionBeyondSize); 124 assertEquals(positionBeyondSize, fc.position()); 125 assertEquals(initialFileSize, fc.size()); 126 127 byte[] newBytes = "6789A".getBytes("US-ASCII"); 128 fc.write(ByteBuffer.wrap(newBytes)); 129 130 int expectedNewLength = positionBeyondSize + newBytes.length; 131 assertEquals(expectedNewLength, fc.position()); 132 assertEquals(expectedNewLength, fc.size()); 133 134 fc.close(); 135 } 136 137 public void test_truncate_greaterThanSizeWithPositionChange() throws Exception { 138 byte[] initialBytes = "12345".getBytes("US-ASCII"); 139 int initialFileSize = initialBytes.length; // 5 140 FileChannel fc = createFileContainingBytes(initialBytes); 141 142 int initialPosition = 40; 143 fc.position(initialPosition); // Should not affect the file size 144 assertEquals(initialPosition, fc.position()); 145 assertEquals(initialFileSize, fc.size()); 146 147 // truncateArg < position, truncateArg > initialFileSize: Should not affect the file size 148 // and should move the position. 149 int truncateArg = 10; 150 fc.truncate(truncateArg); // Should not affect the file size, but should move the position. 151 assertEquals(initialFileSize, fc.size()); 152 // The RI does not behave properly here, according to the docs for truncate(), position() 153 // should now be the same as truncateArg. 154 assertEquals(truncateArg, fc.position()); 155 156 fc.close(); 157 } 158 159 public void test_truncate_greaterThanSizeWithoutPositionChange() throws Exception { 160 byte[] initialBytes = "123456789A".getBytes("US-ASCII"); 161 int initialFileSize = initialBytes.length; // 10 162 FileChannel fc = createFileContainingBytes(initialBytes); 163 164 int initialPosition = 5; 165 fc.position(initialPosition); 166 assertEquals(initialPosition, fc.position()); 167 assertEquals(initialFileSize, fc.size()); 168 169 // truncateArg > position, truncateArg > initialFileSize: Should not affect the file size 170 // and should not move the position. 171 int truncateArg = 15; 172 fc.truncate(truncateArg); 173 assertEquals(initialFileSize, fc.size()); 174 assertEquals(initialPosition, fc.position()); 175 176 fc.close(); 177 } 178 179 public void test_truncate_lessThanSizeWithPositionChange() throws Exception { 180 byte[] initialBytes = "123456789A".getBytes("US-ASCII"); 181 int initialFileSize = initialBytes.length; // 10 182 FileChannel fc = createFileContainingBytes(initialBytes); 183 184 int initialPosition = initialFileSize; 185 fc.position(initialPosition); 186 assertEquals(initialPosition, fc.position()); 187 assertEquals(initialFileSize, fc.size()); 188 189 int truncateArg = 5; 190 // truncateArg < initialPosition, truncateArg < initialFileSize: Should affect the file size 191 // and should move the position. 192 fc.truncate(truncateArg); 193 assertEquals(truncateArg, fc.size()); 194 assertEquals(truncateArg, fc.position()); 195 196 fc.close(); 197 } 198 199 public void test_truncate_lessThanSizeWithoutPositionChange() throws Exception { 200 byte[] initialBytes = "123456789A".getBytes("US-ASCII"); 201 int initialFileSize = initialBytes.length; // 10 202 FileChannel fc = createFileContainingBytes(initialBytes); 203 204 int initialPosition = 4; 205 fc.position(initialPosition); 206 assertEquals(initialPosition, fc.position()); 207 assertEquals(initialFileSize, fc.size()); 208 209 int truncateArg = 5; 210 // truncateArg > initialPosition, truncateArg < initialFileSize: Should affect the file size 211 // and should not move the position. 212 fc.truncate(truncateArg); 213 assertEquals(truncateArg, fc.size()); 214 assertEquals(initialPosition, fc.position()); 215 216 fc.close(); 217 } 218 219 // b/27351214 220 public void test_close_fromFileDescriptor() throws Exception { 221 // Create a valid FileDescriptor 222 File tmp = File.createTempFile("FileChannelTest", "tmp"); 223 FileOutputStream fos = new FileOutputStream(tmp); 224 FileDescriptor fd = fos.getFD(); 225 assertTrue(fd.valid()); 226 227 // Create FileOutputStream from FileDescriptor 228 FileOutputStream fosFromFd = new FileOutputStream(fd); 229 // Create FileChannel from FileOutputStream created from FileDescriptor 230 FileChannel fc = fosFromFd.getChannel(); 231 232 // Invalidate FileDescriptor 233 fos.close(); 234 assertFalse(fd.valid()); 235 236 // Close FileOutputStream and therefore close the FileChannel. 237 // Without the fix for b/27351214 this will throw an exception 238 // due to channel preClosing the file descriptor after it's 239 // closed. 240 fosFromFd.close(); 241 } 242 243 244 private static FileChannel createFileContainingBytes(byte[] bytes) throws IOException { 245 File tmp = File.createTempFile("FileChannelTest", "tmp"); 246 FileOutputStream fos = new FileOutputStream(tmp, true); 247 FileChannel fc = fos.getChannel(); 248 fc.write(ByteBuffer.wrap(bytes)); 249 fc.close(); 250 251 assertEquals(bytes.length, tmp.length()); 252 253 fc = new RandomAccessFile(tmp, "rw").getChannel(); 254 assertEquals(bytes.length, fc.size()); 255 256 return fc; 257 } 258} 259