1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.io.test; 18 19 import static org.junit.jupiter.api.Assertions.assertArrayEquals; 20 import static org.junit.jupiter.api.Assertions.assertEquals; 21 import static org.junit.jupiter.api.Assertions.assertTrue; 22 import static org.junit.jupiter.api.Assertions.fail; 23 24 import java.io.BufferedOutputStream; 25 import java.io.File; 26 import java.io.FileNotFoundException; 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.io.OutputStream; 30 import java.io.OutputStreamWriter; 31 import java.io.PrintWriter; 32 import java.io.Reader; 33 import java.io.Writer; 34 import java.nio.charset.StandardCharsets; 35 import java.nio.file.Files; 36 import java.nio.file.Path; 37 import java.time.Duration; 38 39 import org.apache.commons.io.FileUtils; 40 import org.apache.commons.io.output.ByteArrayOutputStream; 41 import org.apache.commons.lang3.ThreadUtils; 42 43 /** 44 * Base class for tests doing tests with files. 45 */ 46 public abstract class TestUtils { 47 48 /** 49 * Assert that the content of a file is equal to that in a byte[]. 50 * 51 * @param b0 the expected contents 52 * @param file the file to check 53 * @throws IOException If an I/O error occurs while reading the file contents 54 */ assertEqualContent(final byte[] b0, final File file)55 public static void assertEqualContent(final byte[] b0, final File file) throws IOException { 56 assertEqualContent(b0, file.toPath()); 57 } 58 59 /** 60 * Assert that the content of a file is equal to that in a byte[]. 61 * 62 * @param b0 the expected contents 63 * @param file the file to check 64 * @throws IOException If an I/O error occurs while reading the file contents 65 */ assertEqualContent(final byte[] b0, final Path file)66 public static void assertEqualContent(final byte[] b0, final Path file) throws IOException { 67 int count = 0, numRead = 0; 68 final byte[] b1 = new byte[b0.length]; 69 try (InputStream is = Files.newInputStream(file)) { 70 while (count < b0.length && numRead >= 0) { 71 numRead = is.read(b1, count, b0.length); 72 count += numRead; 73 } 74 assertEquals(b0.length, count, "Different number of bytes: "); 75 for (int i = 0; i < count; i++) { 76 assertEquals(b0[i], b1[i], "byte " + i + " differs"); 77 } 78 } 79 } 80 81 /** 82 * Assert that the content of a file is equal to that in a char[]. 83 * 84 * @param c0 the expected contents 85 * @param file the file to check 86 * @throws IOException If an I/O error occurs while reading the file contents 87 */ assertEqualContent(final char[] c0, final File file)88 public static void assertEqualContent(final char[] c0, final File file) throws IOException { 89 assertEqualContent(c0, file.toPath()); 90 } 91 92 /** 93 * Assert that the content of a file is equal to that in a char[]. 94 * 95 * @param c0 the expected contents 96 * @param file the file to check 97 * @throws IOException If an I/O error occurs while reading the file contents 98 */ assertEqualContent(final char[] c0, final Path file)99 public static void assertEqualContent(final char[] c0, final Path file) throws IOException { 100 int count = 0, numRead = 0; 101 final char[] c1 = new char[c0.length]; 102 try (Reader ir = Files.newBufferedReader(file)) { 103 while (count < c0.length && numRead >= 0) { 104 numRead = ir.read(c1, count, c0.length); 105 count += numRead; 106 } 107 assertEquals(c0.length, count, "Different number of chars: "); 108 for (int i = 0; i < count; i++) { 109 assertEquals(c0[i], c1[i], "char " + i + " differs"); 110 } 111 } 112 } 113 114 /** 115 * Assert that the content of two files is the same. 116 */ assertEqualContent(final File f0, final File f1)117 private static void assertEqualContent(final File f0, final File f1) 118 throws IOException { 119 /* This doesn't work because the filesize isn't updated until the file 120 * is closed. 121 assertTrue( "The files " + f0 + " and " + f1 + 122 " have differing file sizes (" + f0.length() + 123 " vs " + f1.length() + ")", ( f0.length() == f1.length() ) ); 124 */ 125 try (InputStream is0 = Files.newInputStream(f0.toPath())) { 126 try (InputStream is1 = Files.newInputStream(f1.toPath())) { 127 final byte[] buf0 = new byte[1024]; 128 final byte[] buf1 = new byte[1024]; 129 int n0 = 0; 130 int n1; 131 132 while (-1 != n0) { 133 n0 = is0.read(buf0); 134 n1 = is1.read(buf1); 135 assertEquals(n0, n1, 136 "The files " + f0 + " and " + f1 + 137 " have differing number of bytes available (" + n0 + " vs " + n1 + ")"); 138 139 assertArrayEquals(buf0, buf1, "The files " + f0 + " and " + f1 + " have different content"); 140 } 141 } 142 } 143 } 144 checkFile(final File file, final File referenceFile)145 public static void checkFile(final File file, final File referenceFile) 146 throws Exception { 147 assertTrue(file.exists(), "Check existence of output file"); 148 assertEqualContent(referenceFile, file); 149 } 150 checkWrite(final OutputStream output)151 public static void checkWrite(final OutputStream output) { 152 try { 153 new java.io.PrintStream(output).write(0); 154 } catch (final Throwable t) { 155 fail("The copy() method closed the stream when it shouldn't have. " + t.getMessage()); 156 } 157 } 158 checkWrite(final Writer output)159 public static void checkWrite(final Writer output) { 160 try { 161 new java.io.PrintWriter(output).write('a'); 162 } catch (final Throwable t) { 163 fail("The copy() method closed the stream when it shouldn't have. " + t.getMessage()); 164 } 165 } 166 createFile(final File file, final long size)167 public static void createFile(final File file, final long size) throws IOException { 168 if (!file.getParentFile().exists()) { 169 throw new IOException("Cannot create file " + file + " as the parent directory does not exist"); 170 } 171 try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()))) { 172 generateTestData(output, size); 173 } 174 } 175 createFile(final Path file, final long size)176 public static void createFile(final Path file, final long size) throws IOException { 177 if (!Files.exists(file.getParent())) { 178 throw new IOException("Cannot create file " + file + " as the parent directory does not exist"); 179 } 180 try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file))) { 181 generateTestData(output, size); 182 } 183 } 184 createLineBasedFile(final File file, final String[] data)185 public static void createLineBasedFile(final File file, final String[] data) throws IOException { 186 if (file.getParentFile() != null && !file.getParentFile().exists()) { 187 throw new IOException("Cannot create file " + file + " as the parent directory does not exist"); 188 } 189 try (PrintWriter output = new PrintWriter(new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8))) { 190 for (final String element : data) { 191 output.println(element); 192 } 193 } 194 } 195 deleteFile(final File file)196 public static void deleteFile(final File file) { 197 if (file.exists()) { 198 assertTrue(file.delete(), "Couldn't delete file: " + file); 199 } 200 } 201 generateTestData(final File file, final long size)202 public static void generateTestData(final File file, final long size) throws IOException, FileNotFoundException { 203 try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()))) { 204 generateTestData(output, size); 205 } 206 } 207 generateTestData(final long size)208 public static byte[] generateTestData(final long size) { 209 try { 210 try (ByteArrayOutputStream baout = new ByteArrayOutputStream()) { 211 generateTestData(baout, size); 212 return baout.toByteArray(); 213 } 214 } catch (final IOException ioe) { 215 throw new IllegalStateException("This should never happen: " + ioe.getMessage(), ioe); 216 } 217 } 218 generateTestData(final OutputStream out, final long size)219 public static void generateTestData(final OutputStream out, final long size) throws IOException { 220 for (int i = 0; i < size; i++) { 221 // output.write((byte)'X'); 222 // nice varied byte pattern compatible with Readers and Writers 223 out.write((byte) (i % 127 + 1)); 224 } 225 } 226 newFile(final File testDirectory, final String fileName)227 public static File newFile(final File testDirectory, final String fileName) throws IOException { 228 final File destination = new File(testDirectory, fileName); 229 /* 230 assertTrue(fileName + "Test output data file shouldn't previously exist", 231 !destination.exists()); 232 */ 233 if (destination.exists()) { 234 FileUtils.forceDelete(destination); 235 } 236 return destination; 237 } 238 239 /** 240 * Sleeps for a guaranteed number of milliseconds unless interrupted. 241 * 242 * This method exists because Thread.sleep(100) can sleep for 0, 70, 100 or 200ms or anything else 243 * it deems appropriate. Read the docs on Thread.sleep for further details. 244 * 245 * @param millis the number of milliseconds to sleep. 246 * @throws InterruptedException if interrupted. 247 */ sleep(final long millis)248 public static void sleep(final long millis) throws InterruptedException { 249 ThreadUtils.sleep(Duration.ofMillis(millis)); 250 } 251 252 /** 253 * Sleeps and swallows InterruptedException. 254 * 255 * @param millis the number of milliseconds to sleep. 256 */ sleepQuietly(final long millis)257 public static void sleepQuietly(final long millis) { 258 try { 259 sleep(millis); 260 } catch (final InterruptedException ignored){ 261 // ignore InterruptedException. 262 } 263 } 264 TestUtils()265 private TestUtils() { 266 267 } 268 269 } 270