@@ -251,4 +251,165 @@ void testParseRanges_NullInput() {
251251 },
252252 "Should throw NullPointerException for null input" );
253253 }
254+
255+ // ==================== validatePath Tests ====================
256+
257+ @ Test
258+ @ DisplayName ("Should validate relative path with baseDir" )
259+ void testValidatePath_RelativePathWithBaseDir () throws IOException {
260+ Path baseDir = tempDir ;
261+ Path subDir = tempDir .resolve ("subdir" );
262+ Files .createDirectories (subDir );
263+
264+ // Relative path should be resolved relative to baseDir
265+ Path result = FileToolUtils .validatePath ("subdir/test.txt" , baseDir );
266+
267+ assertNotNull (result );
268+ assertTrue (result .isAbsolute (), "Result should be absolute" );
269+ assertTrue (result .startsWith (baseDir ), "Result should be within baseDir" );
270+ assertEquals (subDir .resolve ("test.txt" ), result , "Should resolve to correct path" );
271+ }
272+
273+ @ Test
274+ @ DisplayName ("Should validate simple relative path with baseDir" )
275+ void testValidatePath_SimpleRelativePathWithBaseDir () throws IOException {
276+ Path baseDir = tempDir ;
277+
278+ Path result = FileToolUtils .validatePath ("test.txt" , baseDir );
279+
280+ assertNotNull (result );
281+ assertTrue (result .isAbsolute (), "Result should be absolute" );
282+ assertTrue (result .startsWith (baseDir ), "Result should be within baseDir" );
283+ assertEquals (baseDir .resolve ("test.txt" ), result , "Should resolve to correct path" );
284+ }
285+
286+ @ Test
287+ @ DisplayName ("Should reject path traversal attack with baseDir" )
288+ void testValidatePath_PathTraversalAttackWithBaseDir () {
289+ Path baseDir = tempDir ;
290+
291+ // Try to escape baseDir using ../
292+ IOException exception =
293+ assertThrows (
294+ IOException .class ,
295+ () -> FileToolUtils .validatePath ("../../etc/passwd" , baseDir ),
296+ "Should reject path traversal attack" );
297+
298+ assertTrue (
299+ exception .getMessage ().contains ("Access denied" ),
300+ "Error message should indicate access denied" );
301+ assertTrue (
302+ exception .getMessage ().contains ("outside the allowed base directory" ),
303+ "Error message should mention base directory restriction" );
304+ }
305+
306+ @ Test
307+ @ DisplayName ("Should validate absolute path within baseDir" )
308+ void testValidatePath_AbsolutePathWithinBaseDir () throws IOException {
309+ Path baseDir = tempDir ;
310+ Path targetFile = tempDir .resolve ("test.txt" );
311+
312+ Path result = FileToolUtils .validatePath (targetFile .toString (), baseDir );
313+
314+ assertNotNull (result );
315+ assertTrue (result .isAbsolute (), "Result should be absolute" );
316+ assertEquals (targetFile , result , "Should return the same absolute path" );
317+ }
318+
319+ @ Test
320+ @ DisplayName ("Should reject absolute path outside baseDir" )
321+ void testValidatePath_AbsolutePathOutsideBaseDir () {
322+ Path baseDir = tempDir ;
323+ Path outsidePath = tempDir .getParent ().resolve ("outside.txt" );
324+
325+ IOException exception =
326+ assertThrows (
327+ IOException .class ,
328+ () -> FileToolUtils .validatePath (outsidePath .toString (), baseDir ),
329+ "Should reject path outside baseDir" );
330+
331+ assertTrue (
332+ exception .getMessage ().contains ("Access denied" ),
333+ "Error message should indicate access denied" );
334+ }
335+
336+ @ Test
337+ @ DisplayName ("Should validate relative path without baseDir" )
338+ void testValidatePath_RelativePathWithoutBaseDir () throws IOException {
339+ // Without baseDir, relative path should be converted to absolute
340+ Path result = FileToolUtils .validatePath ("test.txt" , null );
341+
342+ assertNotNull (result );
343+ assertTrue (result .isAbsolute (), "Result should be absolute" );
344+ assertTrue (result .toString ().endsWith ("test.txt" ), "Result should end with the file name" );
345+ }
346+
347+ @ Test
348+ @ DisplayName ("Should validate absolute path without baseDir" )
349+ void testValidatePath_AbsolutePathWithoutBaseDir () throws IOException {
350+ Path absolutePath = tempDir .resolve ("test.txt" );
351+
352+ Path result = FileToolUtils .validatePath (absolutePath .toString (), null );
353+
354+ assertNotNull (result );
355+ assertTrue (result .isAbsolute (), "Result should be absolute" );
356+ assertEquals (absolutePath , result , "Should return the same absolute path" );
357+ }
358+
359+ @ Test
360+ @ DisplayName ("Should reject null file path" )
361+ void testValidatePath_NullFilePath () {
362+ IOException exception =
363+ assertThrows (
364+ IOException .class ,
365+ () -> FileToolUtils .validatePath (null , tempDir ),
366+ "Should reject null file path" );
367+
368+ assertTrue (
369+ exception .getMessage ().contains ("cannot be null or empty" ),
370+ "Error message should mention null or empty" );
371+ }
372+
373+ @ Test
374+ @ DisplayName ("Should reject empty file path" )
375+ void testValidatePath_EmptyFilePath () {
376+ IOException exception =
377+ assertThrows (
378+ IOException .class ,
379+ () -> FileToolUtils .validatePath ("" , tempDir ),
380+ "Should reject empty file path" );
381+
382+ assertTrue (
383+ exception .getMessage ().contains ("cannot be null or empty" ),
384+ "Error message should mention null or empty" );
385+ }
386+
387+ @ Test
388+ @ DisplayName ("Should reject whitespace-only file path" )
389+ void testValidatePath_WhitespaceFilePath () {
390+ IOException exception =
391+ assertThrows (
392+ IOException .class ,
393+ () -> FileToolUtils .validatePath (" " , tempDir ),
394+ "Should reject whitespace-only file path" );
395+
396+ assertTrue (
397+ exception .getMessage ().contains ("cannot be null or empty" ),
398+ "Error message should mention null or empty" );
399+ }
400+
401+ @ Test
402+ @ DisplayName ("Should handle path with . and .. correctly within baseDir" )
403+ void testValidatePath_DotPathWithinBaseDir () throws IOException {
404+ Path baseDir = tempDir ;
405+ Path subDir = tempDir .resolve ("subdir" );
406+ Files .createDirectories (subDir );
407+
408+ // ./subdir/../test.txt should normalize to test.txt in baseDir
409+ Path result = FileToolUtils .validatePath ("./subdir/../test.txt" , baseDir );
410+
411+ assertNotNull (result );
412+ assertTrue (result .startsWith (baseDir ), "Result should be within baseDir" );
413+ assertEquals (baseDir .resolve ("test.txt" ), result , "Should normalize correctly" );
414+ }
254415}
0 commit comments