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    *      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.juneau.commons.utils;
18  
19  import static org.apache.juneau.TestUtils.assertThrowsWithMessage;
20  import static org.junit.jupiter.api.Assertions.*;
21  
22  import java.io.*;
23  import java.nio.file.*;
24  
25  import org.apache.juneau.*;
26  import org.junit.jupiter.api.*;
27  import org.junit.jupiter.api.io.TempDir;
28  
29  /**
30   * Tests for {@link FileUtils}.
31   */
32  class FileUtils_Test extends TestBase {
33  
34  	@TempDir
35  	Path tempDir;
36  
37  	//====================================================================================================
38  	// Constructor (line 32)
39  	//====================================================================================================
40  	@Test
41  	void a00_constructor() {
42  		// Test line 32: class instantiation
43  		// FileUtils has an implicit public no-arg constructor
44  		var instance = new FileUtils();
45  		assertNotNull(instance);
46  	}
47  
48  	//====================================================================================================
49  	// create(File)
50  	//====================================================================================================
51  	@Test
52  	void a001_create() {
53  		var f = new File(tempDir.toFile(), "test.txt");
54  		assertFalse(f.exists());
55  		FileUtils.create(f);
56  		assertTrue(f.exists());
57  		assertTrue(f.isFile());
58  	}
59  
60  	@Test
61  	void a002_create_existingFile() throws IOException {
62  		var f = new File(tempDir.toFile(), "test.txt");
63  		f.createNewFile();
64  		assertTrue(f.exists());
65  		var lastModified = f.lastModified();
66  		FileUtils.create(f);
67  		assertTrue(f.exists());
68  		// Should not modify existing file
69  		assertEquals(lastModified, f.lastModified());
70  	}
71  
72  	@Test
73  	void a003_create_parentDirectoryDoesNotExist() {
74  		var f = new File(tempDir.toFile(), "nonexistent/test.txt");
75  		var e = assertThrows(RuntimeException.class, () -> {
76  			FileUtils.create(f);
77  		});
78  		// When parent directory doesn't exist, createNewFile() throws IOException
79  		// which gets wrapped in RuntimeException by toRex()
80  		assertTrue(e.getCause() instanceof IOException);
81  		assertNotNull(e.getCause().getMessage());
82  	}
83  
84  	//====================================================================================================
85  	// createTempFile(String)
86  	//====================================================================================================
87  	@Test
88  	void a004_createTempFile() throws IOException {
89  		var f = FileUtils.createTempFile("test.txt");
90  		assertNotNull(f);
91  		assertTrue(f.exists());
92  		assertTrue(f.getName().startsWith("test"));
93  		assertTrue(f.getName().endsWith(".txt"));
94  		f.delete();
95  	}
96  
97  	@Test
98  	void a005_createTempFile_multipleDots() throws IOException {
99  		var f = FileUtils.createTempFile("test.backup.txt");
100 		assertNotNull(f);
101 		assertTrue(f.exists());
102 		assertTrue(f.getName().startsWith("test"));
103 		// createTempFile splits by '.' and uses first two parts: prefix="test", suffix=".backup"
104 		// So the file name will contain ".backup", not ".txt"
105 		assertTrue(f.getName().contains(".backup"));
106 		f.delete();
107 	}
108 
109 	@Test
110 	void a006_createTempFile_noExtension() {
111 		// When there's no dot, split("\\.") returns array with one element
112 		// This will cause ArrayIndexOutOfBoundsException when accessing parts[1]
113 		// Note: This tests the current behavior, which may be a bug in the implementation
114 		assertThrows(ArrayIndexOutOfBoundsException.class, () -> {
115 			FileUtils.createTempFile("test");
116 		});
117 	}
118 
119 	//====================================================================================================
120 	// createTempFile(String, String)
121 	//====================================================================================================
122 	@Test
123 	void a007_createTempFile_withContents() throws IOException {
124 		var contents = "test content\nline 2";
125 		var f = FileUtils.createTempFile("test.txt", contents);
126 		assertNotNull(f);
127 		assertTrue(f.exists());
128 
129 		try (BufferedReader reader = new BufferedReader(new FileReader(f))) {
130 			var sb = new StringBuilder();
131 			String line;
132 			while ((line = reader.readLine()) != null) {
133 				if (sb.length() > 0)
134 					sb.append('\n');
135 				sb.append(line);
136 			}
137 			assertEquals(contents, sb.toString());
138 		}
139 		f.delete();
140 	}
141 
142 	@Test
143 	void a008_createTempFile_withEmptyContents() throws IOException {
144 		var f = FileUtils.createTempFile("test.txt", "");
145 		assertNotNull(f);
146 		assertTrue(f.exists());
147 		assertEquals(0, f.length());
148 		f.delete();
149 	}
150 
151 	@Test
152 	void a009_createTempFile_withNullContents() throws IOException {
153 		var f = FileUtils.createTempFile("test.txt", null);
154 		assertNotNull(f);
155 		assertTrue(f.exists());
156 		// null contents should result in empty file
157 		assertEquals(0, f.length());
158 		f.delete();
159 	}
160 
161 	//====================================================================================================
162 	// deleteFile(File)
163 	//====================================================================================================
164 	@Test
165 	void a010_deleteFile() throws IOException {
166 		var f = new File(tempDir.toFile(), "test.txt");
167 		f.createNewFile();
168 		assertTrue(f.exists());
169 		assertTrue(FileUtils.deleteFile(f));
170 		assertFalse(f.exists());
171 	}
172 
173 	@Test
174 	void a011_deleteFile_null() {
175 		assertTrue(FileUtils.deleteFile(null));
176 	}
177 
178 	@Test
179 	void a012_deleteFile_nonexistent() {
180 		var f = new File(tempDir.toFile(), "nonexistent.txt");
181 		assertFalse(f.exists());
182 		assertFalse(FileUtils.deleteFile(f));
183 	}
184 
185 	@Test
186 	void a013_deleteFile_directory() throws IOException {
187 		var dir = new File(tempDir.toFile(), "testdir");
188 		dir.mkdirs();
189 		var f1 = new File(dir, "file1.txt");
190 		var f2 = new File(dir, "file2.txt");
191 		f1.createNewFile();
192 		f2.createNewFile();
193 		assertTrue(dir.exists());
194 		assertTrue(f1.exists());
195 		assertTrue(f2.exists());
196 		assertTrue(FileUtils.deleteFile(dir));
197 		assertFalse(dir.exists());
198 		assertFalse(f1.exists());
199 		assertFalse(f2.exists());
200 	}
201 
202 	@Test
203 	void a014_deleteFile_nestedDirectories() throws IOException {
204 		var dir1 = new File(tempDir.toFile(), "dir1");
205 		var dir2 = new File(dir1, "dir2");
206 		var f = new File(dir2, "file.txt");
207 		dir2.mkdirs();
208 		f.createNewFile();
209 		assertTrue(dir1.exists());
210 		assertTrue(dir2.exists());
211 		assertTrue(f.exists());
212 		assertTrue(FileUtils.deleteFile(dir1));
213 		assertFalse(dir1.exists());
214 		assertFalse(dir2.exists());
215 		assertFalse(f.exists());
216 	}
217 
218 	@Test
219 	void a015_deleteFile_emptyDirectory() {
220 		var dir = new File(tempDir.toFile(), "emptydir");
221 		dir.mkdirs();
222 		assertTrue(dir.exists());
223 		assertTrue(FileUtils.deleteFile(dir));
224 		assertFalse(dir.exists());
225 	}
226 
227 	//====================================================================================================
228 	// fileExists(File, String)
229 	//====================================================================================================
230 	@Test
231 	void a016_fileExists() throws IOException {
232 		var dir = tempDir.toFile();
233 		var f = new File(dir, "test.txt");
234 		f.createNewFile();
235 		assertTrue(FileUtils.fileExists(dir, "test.txt"));
236 	}
237 
238 	@Test
239 	void a017_fileExists_nonexistentFile() {
240 		var dir = tempDir.toFile();
241 		assertFalse(FileUtils.fileExists(dir, "nonexistent.txt"));
242 	}
243 
244 	@Test
245 	void a018_fileExists_nullDir() {
246 		assertFalse(FileUtils.fileExists(null, "test.txt"));
247 	}
248 
249 	@Test
250 	void a019_fileExists_nullFileName() {
251 		var dir = tempDir.toFile();
252 		assertFalse(FileUtils.fileExists(dir, null));
253 	}
254 
255 	@Test
256 	void a020_fileExists_bothNull() {
257 		assertFalse(FileUtils.fileExists(null, null));
258 	}
259 
260 	@Test
261 	void a021_fileExists_subdirectory() throws IOException {
262 		var dir = tempDir.toFile();
263 		var subdir = new File(dir, "subdir");
264 		subdir.mkdirs();
265 		var f = new File(subdir, "test.txt");
266 		f.createNewFile();
267 		assertTrue(FileUtils.fileExists(subdir, "test.txt"));
268 	}
269 
270 	//====================================================================================================
271 	// getBaseName(String)
272 	//====================================================================================================
273 	@Test
274 	void a022_getBaseName() {
275 		assertEquals("test", FileUtils.getBaseName("test.txt"));
276 		assertEquals("file.backup", FileUtils.getBaseName("file.backup.txt"));
277 	}
278 
279 	@Test
280 	void a023_getBaseName_noExtension() {
281 		assertEquals("test", FileUtils.getBaseName("test"));
282 		assertEquals("file", FileUtils.getBaseName("file"));
283 	}
284 
285 	@Test
286 	void a024_getBaseName_null() {
287 		assertNull(FileUtils.getBaseName(null));
288 	}
289 
290 	@Test
291 	void a025_getBaseName_onlyExtension() {
292 		assertEquals("", FileUtils.getBaseName(".txt"));
293 	}
294 
295 	@Test
296 	void a026_getBaseName_multipleDots() {
297 		assertEquals("test.backup", FileUtils.getBaseName("test.backup.txt"));
298 	}
299 
300 	//====================================================================================================
301 	// getFileExtension(String)
302 	//====================================================================================================
303 	@Test
304 	void a027_getFileExtension() {
305 		assertEquals("txt", FileUtils.getFileExtension("test.txt"));
306 		assertEquals("java", FileUtils.getFileExtension("FileUtils.java"));
307 	}
308 
309 	@Test
310 	void a028_getFileExtension_noExtension() {
311 		assertEquals("", FileUtils.getFileExtension("test"));
312 		assertEquals("", FileUtils.getFileExtension("file"));
313 	}
314 
315 	@Test
316 	void a029_getFileExtension_null() {
317 		assertNull(FileUtils.getFileExtension(null));
318 	}
319 
320 	@Test
321 	void a030_getFileExtension_onlyExtension() {
322 		assertEquals("txt", FileUtils.getFileExtension(".txt"));
323 	}
324 
325 	@Test
326 	void a031_getFileExtension_multipleDots() {
327 		assertEquals("txt", FileUtils.getFileExtension("test.backup.txt"));
328 	}
329 
330 	@Test
331 	void a032_getFileExtension_emptyString() {
332 		assertEquals("", FileUtils.getFileExtension(""));
333 	}
334 
335 	//====================================================================================================
336 	// getFileName(String)
337 	//====================================================================================================
338 	@Test
339 	void a033_getFileName() {
340 		assertEquals("test.txt", FileUtils.getFileName("test.txt"));
341 	}
342 
343 	@Test
344 	void a034_getFileName_withPath() {
345 		assertEquals("test.txt", FileUtils.getFileName("/path/to/test.txt"));
346 		assertEquals("file.java", FileUtils.getFileName("dir/subdir/file.java"));
347 	}
348 
349 	@Test
350 	void a035_getFileName_withTrailingSlash() {
351 		assertEquals("test.txt", FileUtils.getFileName("/path/to/test.txt/"));
352 		assertEquals("dir", FileUtils.getFileName("/path/to/dir/"));
353 	}
354 
355 	@Test
356 	void a036_getFileName_null() {
357 		assertNull(FileUtils.getFileName(null));
358 	}
359 
360 	@Test
361 	void a037_getFileName_emptyString() {
362 		assertNull(FileUtils.getFileName(""));
363 	}
364 
365 	@Test
366 	void a038_getFileName_onlySlashes() {
367 		assertNull(FileUtils.getFileName("/"));
368 		assertNull(FileUtils.getFileName("//"));
369 	}
370 
371 	@Test
372 	void a039_getFileName_windowsPath() {
373 		assertEquals("test.txt", FileUtils.getFileName("C:\\path\\to\\test.txt"));
374 	}
375 
376 	//====================================================================================================
377 	// hasExtension(String, String)
378 	//====================================================================================================
379 	@Test
380 	void a040_hasExtension() {
381 		assertTrue(FileUtils.hasExtension("test.txt", "txt"));
382 		assertTrue(FileUtils.hasExtension("file.java", "java"));
383 	}
384 
385 	@Test
386 	void a041_hasExtension_notMatching() {
387 		assertFalse(FileUtils.hasExtension("test.txt", "java"));
388 		assertFalse(FileUtils.hasExtension("file.java", "txt"));
389 	}
390 
391 	@Test
392 	void a042_hasExtension_noExtension() {
393 		assertFalse(FileUtils.hasExtension("test", "txt"));
394 	}
395 
396 	@Test
397 	void a043_hasExtension_nullName() {
398 		assertFalse(FileUtils.hasExtension(null, "txt"));
399 	}
400 
401 	@Test
402 	void a044_hasExtension_nullExt() {
403 		assertFalse(FileUtils.hasExtension("test.txt", null));
404 	}
405 
406 	@Test
407 	void a045_hasExtension_bothNull() {
408 		assertFalse(FileUtils.hasExtension(null, null));
409 	}
410 
411 	@Test
412 	void a046_hasExtension_caseSensitive() {
413 		assertFalse(FileUtils.hasExtension("test.TXT", "txt"));
414 		assertTrue(FileUtils.hasExtension("test.TXT", "TXT"));
415 	}
416 
417 	@Test
418 	void a047_hasExtension_multipleDots() {
419 		assertTrue(FileUtils.hasExtension("test.backup.txt", "txt"));
420 		assertFalse(FileUtils.hasExtension("test.backup.txt", "backup"));
421 	}
422 
423 	//====================================================================================================
424 	// mkdirs(File, boolean)
425 	//====================================================================================================
426 	@Test
427 	void a048_mkdirs() {
428 		var dir = new File(tempDir.toFile(), "newdir");
429 		assertFalse(dir.exists());
430 		var result = FileUtils.mkdirs(dir, false);
431 		assertTrue(dir.exists());
432 		assertTrue(dir.isDirectory());
433 		assertSame(dir, result);
434 	}
435 
436 	@Test
437 	void a049_mkdirs_nestedDirectories() {
438 		var dir = new File(tempDir.toFile(), "dir1/dir2/dir3");
439 		assertFalse(dir.exists());
440 		var result = FileUtils.mkdirs(dir, false);
441 		assertTrue(dir.exists());
442 		assertTrue(dir.isDirectory());
443 		assertSame(dir, result);
444 	}
445 
446 	@Test
447 	void a050_mkdirs_existingDirectory_cleanFalse() {
448 		var dir = new File(tempDir.toFile(), "existingdir");
449 		dir.mkdirs();
450 		assertTrue(dir.exists());
451 		var result = FileUtils.mkdirs(dir, false);
452 		assertTrue(dir.exists());
453 		assertSame(dir, result);
454 	}
455 
456 	@Test
457 	void a051_mkdirs_existingDirectory_cleanTrue() throws IOException {
458 		var dir = new File(tempDir.toFile(), "cleandir");
459 		dir.mkdirs();
460 		var f = new File(dir, "test.txt");
461 		f.createNewFile();
462 		assertTrue(dir.exists());
463 		assertTrue(f.exists());
464 		var result = FileUtils.mkdirs(dir, true);
465 		assertTrue(dir.exists());
466 		assertFalse(f.exists());
467 		assertSame(dir, result);
468 	}
469 
470 	@Test
471 	void a052_mkdirs_null() {
472 		assertThrows(IllegalArgumentException.class, () -> {
473 			FileUtils.mkdirs((File)null, false);
474 		});
475 	}
476 
477 	//====================================================================================================
478 	// mkdirs(String, boolean)
479 	//====================================================================================================
480 	@Test
481 	void a053_mkdirs_string() {
482 		var dir = new File(tempDir.toFile(), "newdir");
483 		var path = dir.getAbsolutePath();
484 		var result = FileUtils.mkdirs(path, false);
485 		assertTrue(dir.exists());
486 		assertTrue(dir.isDirectory());
487 		assertEquals(dir.getAbsolutePath(), result.getAbsolutePath());
488 	}
489 
490 	@Test
491 	void a054_mkdirs_string_nestedDirectories() {
492 		var dir = new File(tempDir.toFile(), "dir1/dir2/dir3");
493 		var path = dir.getAbsolutePath();
494 		var result = FileUtils.mkdirs(path, false);
495 		assertTrue(dir.exists());
496 		assertTrue(dir.isDirectory());
497 		assertEquals(dir.getAbsolutePath(), result.getAbsolutePath());
498 	}
499 
500 	@Test
501 	void a055_mkdirs_string_existingDirectory_cleanTrue() throws IOException {
502 		var dir = new File(tempDir.toFile(), "cleandir");
503 		dir.mkdirs();
504 		var f = new File(dir, "test.txt");
505 		f.createNewFile();
506 		var path = dir.getAbsolutePath();
507 		var result = FileUtils.mkdirs(path, true);
508 		assertTrue(dir.exists());
509 		assertFalse(f.exists());
510 		assertEquals(dir.getAbsolutePath(), result.getAbsolutePath());
511 	}
512 
513 	@Test
514 	void a056_mkdirs_string_null() {
515 		assertThrows(IllegalArgumentException.class, () -> {
516 			FileUtils.mkdirs((String)null, false);
517 		});
518 	}
519 
520 	//====================================================================================================
521 	// modifyTimestamp(File)
522 	//====================================================================================================
523 	@Test
524 	void a057_modifyTimestamp() throws IOException, InterruptedException {
525 		var f = new File(tempDir.toFile(), "test.txt");
526 		f.createNewFile();
527 		var originalTime = f.lastModified();
528 
529 		// Wait a bit to ensure time difference
530 		Thread.sleep(10);
531 
532 		FileUtils.modifyTimestamp(f);
533 		var newTime = f.lastModified();
534 		assertTrue(newTime > originalTime || newTime == originalTime + 1000,
535 			"Expected newTime > originalTime or newTime == originalTime + 1000, but newTime=" + newTime + ", originalTime=" + originalTime);
536 	}
537 
538 	@Test
539 	void a058_modifyTimestamp_nonexistentFile() {
540 		var f = new File(tempDir.toFile(), "nonexistent.txt");
541 		assertFalse(f.exists());
542 		assertThrowsWithMessage(RuntimeException.class, "Could not modify timestamp", () -> {
543 			FileUtils.modifyTimestamp(f);
544 		});
545 	}
546 
547 	@Test
548 	void a059_modifyTimestamp_directory() throws InterruptedException {
549 		var dir = new File(tempDir.toFile(), "testdir");
550 		dir.mkdirs();
551 		var originalTime = dir.lastModified();
552 
553 		// Wait a bit to ensure time difference
554 		Thread.sleep(10);
555 
556 		FileUtils.modifyTimestamp(dir);
557 		var newTime = dir.lastModified();
558 		assertTrue(newTime > originalTime || newTime == originalTime + 1000);
559 	}
560 }
561