View Javadoc
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    *      https://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.PrintStream;
32  import java.io.PrintWriter;
33  import java.io.Reader;
34  import java.io.Writer;
35  import java.nio.charset.StandardCharsets;
36  import java.nio.file.Files;
37  import java.nio.file.Path;
38  import java.time.Duration;
39  
40  import org.apache.commons.io.FileUtils;
41  import org.apache.commons.io.output.ByteArrayOutputStream;
42  import org.apache.commons.lang3.ThreadUtils;
43  
44  /**
45   * Base class for tests doing tests with files.
46   */
47  public abstract class TestUtils {
48  
49      /**
50       * Assert that the content of a file is equal to that in a byte[].
51       *
52       * @param b0   the expected contents.
53       * @param file the file to check.
54       * @throws IOException If an I/O error occurs while reading the file contents.
55       */
56      public static void assertEqualContent(final byte[] b0, final File file) throws IOException {
57          assertEqualContent(b0, file.toPath());
58      }
59  
60      /**
61       * Assert that the content of a file is equal to that in a byte[].
62       *
63       * @param b0   the expected contents.
64       * @param file the file to check.
65       * @throws IOException If an I/O error occurs while reading the file contents.
66       */
67      public static void assertEqualContent(final byte[] b0, final Path file) throws IOException {
68          int count = 0;
69          int numRead = 0;
70          final byte[] b1 = new byte[b0.length];
71          try (InputStream is = Files.newInputStream(file)) {
72              while (count < b0.length && numRead >= 0) {
73                  numRead = is.read(b1, count, b0.length);
74                  count += numRead;
75              }
76              assertEquals(b0.length, count, "Different number of bytes: ");
77              for (int i = 0; i < count; i++) {
78                  assertEquals(b0[i], b1[i], "byte " + i + " differs");
79              }
80          }
81      }
82  
83      /**
84       * Assert that the content of a file is equal to that in a char[].
85       *
86       * @param c0   the expected contents.
87       * @param file the file to check.
88       * @throws IOException If an I/O error occurs while reading the file contents.
89       */
90      public static void assertEqualContent(final char[] c0, final File file) throws IOException {
91          assertEqualContent(c0, file.toPath());
92      }
93  
94      /**
95       * Assert that the content of a file is equal to that in a char[].
96       *
97       * @param c0   the expected contents.
98       * @param file the file to check.
99       * @throws IOException If an I/O error occurs while reading the file contents.
100      */
101     public static void assertEqualContent(final char[] c0, final Path file) throws IOException {
102         int count = 0;
103         int numRead = 0;
104         final char[] c1 = new char[c0.length];
105         try (Reader ir = Files.newBufferedReader(file)) {
106             while (count < c0.length && numRead >= 0) {
107                 numRead = ir.read(c1, count, c0.length);
108                 count += numRead;
109             }
110             assertEquals(c0.length, count, "Different number of chars: ");
111             for (int i = 0; i < count; i++) {
112                 assertEquals(c0[i], c1[i], "char " + i + " differs");
113             }
114         }
115     }
116 
117     /**
118      * Assert that the content of two files is the same.
119      */
120     private static void assertEqualContent(final File f0, final File f1)
121             throws IOException {
122         /* This doesn't work because the file size isn't updated until the file
123          * is closed.
124         assertTrue( "The files " + f0 + " and " + f1 +
125                     " have differing file sizes (" + f0.length() +
126                     " vs " + f1.length() + ")", ( f0.length() == f1.length() ) );
127         */
128         try (InputStream is0 = Files.newInputStream(f0.toPath())) {
129             try (InputStream is1 = Files.newInputStream(f1.toPath())) {
130                 final byte[] buf0 = new byte[1024];
131                 final byte[] buf1 = new byte[1024];
132                 int n0 = 0;
133                 int n1;
134 
135                 while (-1 != n0) {
136                     n0 = is0.read(buf0);
137                     n1 = is1.read(buf1);
138                     assertEquals(n0, n1,
139                             "The files " + f0 + " and " + f1 +
140                             " have differing number of bytes available (" + n0 + " vs " + n1 + ")");
141 
142                     assertArrayEquals(buf0, buf1, "The files " + f0 + " and " + f1 + " have different content");
143                 }
144             }
145         }
146     }
147 
148     public static void checkFile(final File file, final File referenceFile)
149             throws Exception {
150         assertTrue(file.exists(), "Check existence of output file");
151         assertEqualContent(referenceFile, file);
152     }
153 
154     public static void checkWrite(final OutputStream output) {
155         try {
156             new PrintStream(output).write(0);
157         } catch (final Throwable t) {
158             fail("The copy() method closed the stream when it shouldn't have. " + t.getMessage());
159         }
160     }
161 
162     public static void checkWrite(final Writer output) {
163         try {
164             new PrintWriter(output).write('a');
165         } catch (final Throwable t) {
166             fail("The copy() method closed the stream when it shouldn't have. " + t.getMessage());
167         }
168     }
169 
170     public static void createFile(final File file, final long size) throws IOException {
171         if (!file.getParentFile().exists()) {
172             throw new IOException("Cannot create file " + file + " as the parent directory does not exist");
173         }
174         try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()))) {
175             generateTestData(output, size);
176         }
177     }
178 
179     public static void createFile(final Path file, final long size) throws IOException {
180         if (!Files.exists(file.getParent())) {
181             throw new IOException("Cannot create file " + file + " as the parent directory does not exist");
182         }
183         try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file))) {
184             generateTestData(output, size);
185         }
186     }
187 
188     public static void createLineFileUtf8(final File file, final String[] data) throws IOException {
189         if (file.getParentFile() != null && !file.getParentFile().exists()) {
190             throw new IOException("Cannot create file " + file + " as the parent directory does not exist");
191         }
192         try (PrintWriter output = new PrintWriter(new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8))) {
193             for (final String element : data) {
194                 output.println(element);
195             }
196         }
197     }
198 
199     public static void deleteFile(final File file) {
200         if (file.exists()) {
201             assertTrue(file.delete(), "Couldn't delete file: " + file);
202         }
203     }
204 
205     public static void generateTestData(final File file, final long size) throws IOException, FileNotFoundException {
206         try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()))) {
207             generateTestData(output, size);
208         }
209     }
210 
211     public static byte[] generateTestData(final long size) {
212         try {
213             try (ByteArrayOutputStream baout = new ByteArrayOutputStream()) {
214                 generateTestData(baout, size);
215                 return baout.toByteArray();
216             }
217         } catch (final IOException ioe) {
218             throw new IllegalStateException("This should never happen: " + ioe.getMessage(), ioe);
219         }
220     }
221 
222     public static void generateTestData(final OutputStream out, final long size) throws IOException {
223         for (int i = 0; i < size; i++) {
224             // output.write((byte)'X');
225             // nice varied byte pattern compatible with Readers and Writers
226             out.write((byte) (i % 127 + 1));
227         }
228     }
229 
230     public static File newFile(final File testDirectory, final String fileName) throws IOException {
231         final File destination = new File(testDirectory, fileName);
232         /*
233         assertTrue(fileName + "Test output data file shouldn't previously exist",
234                     !destination.exists());
235         */
236         if (destination.exists()) {
237             FileUtils.forceDelete(destination);
238         }
239         return destination;
240     }
241 
242     /**
243      * Sleeps for a guaranteed number of milliseconds unless interrupted.
244      *
245      * This method exists because Thread.sleep(100) can sleep for 0, 70, 100 or 200ms or anything else it deems appropriate. Read the docs on Thread.sleep for
246      * further details.
247      *
248      * @param millis the number of milliseconds to sleep.
249      * @throws InterruptedException if {@code interrupt()} was called for this Thread while it was sleeping.
250      */
251     public static void sleep(final long millis) throws InterruptedException {
252         ThreadUtils.sleep(Duration.ofMillis(millis));
253     }
254 
255     /**
256      * Sleeps and swallows InterruptedException.
257      *
258      * @param millis the number of milliseconds to sleep.
259      */
260     public static void sleepQuietly(final long millis) {
261         try {
262             sleep(millis);
263         } catch (final InterruptedException ignored) {
264             Thread.currentThread().interrupt();
265         }
266     }
267 
268     /**
269      * Sleeps to the next full second boundary.
270      * <p>
271      * Use this method when to set a guaranteed newer file system timestamp. POSIX file systems only guarantee one second resolution, for example some macOS
272      * file systems.
273      * </p>
274      *
275      * @throws InterruptedException if {@code interrupt()} was called for this Thread while it was sleeping.
276      */
277     public static void sleepToNextSecond() throws InterruptedException {
278         sleep(1001 - System.currentTimeMillis() % 1000);
279     }
280 
281     private TestUtils() {
282 
283     }
284 
285 }