1 /* 2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 6191269 6709457 8000330 26 * @summary Test truncate method of FileChannel 27 * @key randomness 28 */ 29 30 import java.io.*; 31 import java.nio.ByteBuffer; 32 import java.nio.channels.*; 33 import java.nio.file.Files; 34 import static java.nio.file.StandardOpenOption.*; 35 import static java.nio.charset.StandardCharsets.*; 36 import java.util.Random; 37 38 39 /** 40 * Testing FileChannel's truncate method. 41 */ 42 43 public class Truncate { 44 private static final Random generator = new Random(); 45 46 public static void main(String[] args) throws Exception { 47 File blah = File.createTempFile("blah", null); 48 blah.deleteOnExit(); 49 try { 50 basicTest(blah); 51 appendTest(blah); 52 exceptionTests(blah); 53 } finally { 54 blah.delete(); 55 } 56 } 57 58 /** 59 * Basic test of asserts in truncate's specification. 60 */ 61 static void basicTest(File blah) throws Exception { 62 for(int i=0; i<100; i++) { 63 long testSize = generator.nextInt(1000) + 10; 64 initTestFile(blah, testSize); 65 66 try (FileChannel fc = (i < 50) ? 67 new RandomAccessFile(blah, "rw").getChannel() : 68 FileChannel.open(blah.toPath(), READ, WRITE)) 69 { 70 if (fc.size() != testSize) 71 throw new RuntimeException("Size failed"); 72 73 long position = generator.nextInt((int)testSize*2); 74 fc.position(position); 75 76 long newSize = generator.nextInt((int)testSize*2); 77 fc.truncate(newSize); 78 79 // check new size 80 if (newSize > testSize) { 81 if (fc.size() != testSize) 82 throw new RuntimeException("Attempt to expand file changed size"); 83 } else { 84 if (fc.size() != newSize) 85 throw new RuntimeException("Unexpected size after truncate"); 86 } 87 88 // check new position 89 if (position > newSize) { 90 if (fc.position() != newSize) 91 throw new RuntimeException("Position greater than size"); 92 } else { 93 if (fc.position() != position) 94 throw new RuntimeException("Truncate changed position"); 95 }; 96 } 97 } 98 } 99 100 /** 101 * Test behavior of truncate method when file is opened for append 102 */ 103 static void appendTest(File blah) throws Exception { 104 for (int i=0; i<10; i++) { 105 long testSize = generator.nextInt(1000) + 10; 106 initTestFile(blah, testSize); 107 try (FileChannel fc = (i < 5) ? 108 new FileOutputStream(blah, true).getChannel() : 109 FileChannel.open(blah.toPath(), APPEND)) 110 { 111 // truncate file 112 long newSize = generator.nextInt((int)testSize); 113 fc.truncate(newSize); 114 if (fc.size() != newSize) 115 throw new RuntimeException("Truncate failed"); 116 117 // write one byte 118 ByteBuffer buf = ByteBuffer.allocate(1); 119 buf.put((byte)'x'); 120 buf.flip(); 121 fc.write(buf); 122 if (fc.size() != (newSize+1)) 123 throw new RuntimeException("Unexpected size"); 124 } 125 } 126 } 127 128 /** 129 * Test exceptions specified by truncate method 130 */ 131 static void exceptionTests(File blah) throws Exception { 132 // check exceptions when channel opened for read access 133 try (FileChannel fc = FileChannel.open(blah.toPath(), READ)) { 134 long size = fc.size(); 135 136 // open channel 137 checkException(fc, 0L, NonWritableChannelException.class); 138 139 checkException(fc, -1L, NonWritableChannelException.class, 140 IllegalArgumentException.class); 141 142 checkException(fc, size+1L, NonWritableChannelException.class); 143 144 // closed channel 145 fc.close(); 146 147 checkException(fc, 0L, ClosedChannelException.class); 148 149 checkException(fc, -1L, ClosedChannelException.class, 150 IllegalArgumentException.class); 151 152 checkException(fc, size+1L, ClosedChannelException.class); 153 } 154 155 // check exceptions when channel opened for write access 156 try (FileChannel fc = FileChannel.open(blah.toPath(), WRITE)) { 157 long size = fc.size(); 158 159 // open channel 160 checkException(fc, -1L, IllegalArgumentException.class); 161 162 // closed channel 163 fc.close(); 164 165 checkException(fc, 0L, ClosedChannelException.class); 166 167 checkException(fc, -1L, ClosedChannelException.class, 168 IllegalArgumentException.class); 169 170 checkException(fc, size+1L, ClosedChannelException.class); 171 } 172 } 173 174 /** 175 * Checks that FileChannel truncate throws one of the expected exceptions 176 * when invoked with the given size. 177 */ 178 private static void checkException(FileChannel fc, long size, Class<?>... expected) 179 throws IOException 180 { 181 Exception exc = null; 182 try { 183 fc.truncate(size); 184 } catch (Exception actual) { 185 exc = actual; 186 } 187 if (exc != null) { 188 for (Class<?> clazz: expected) { 189 if (clazz.isInstance(exc)) { 190 return; 191 } 192 } 193 } 194 System.err.println("Expected one of"); 195 for (Class<?> clazz: expected) { 196 System.err.println(clazz); 197 } 198 if (exc == null) { 199 throw new RuntimeException("No expection thrown"); 200 } else { 201 throw new RuntimeException("Unexpected exception thrown", exc); 202 } 203 } 204 205 /** 206 * Creates file blah of specified size in bytes. 207 */ 208 private static void initTestFile(File blah, long size) throws Exception { 209 try (BufferedWriter writer = Files.newBufferedWriter(blah.toPath(), ISO_8859_1)) { 210 for(int i=0; i<size; i++) { 211 writer.write("e"); 212 } 213 } 214 } 215 }