@@ -502,5 +502,57 @@ describe("filesystem", () => {
502502 const drive = tmp . path [ 0 ] . toLowerCase ( )
503503 expect ( Filesystem . resolve ( `/mnt/${ drive } ` ) ) . toBe ( Filesystem . resolve ( `${ drive . toUpperCase ( ) } :/` ) )
504504 } )
505+
506+ test ( "resolves symlinked directory to canonical path" , async ( ) => {
507+ await using tmp = await tmpdir ( )
508+ const target = path . join ( tmp . path , "real" )
509+ await fs . mkdir ( target )
510+ const link = path . join ( tmp . path , "link" )
511+ await fs . symlink ( target , link )
512+ expect ( Filesystem . resolve ( link ) ) . toBe ( Filesystem . resolve ( target ) )
513+ } )
514+
515+ test ( "returns unresolved path when target does not exist" , async ( ) => {
516+ await using tmp = await tmpdir ( )
517+ const missing = path . join ( tmp . path , "does-not-exist-" + Date . now ( ) )
518+ const result = Filesystem . resolve ( missing )
519+ expect ( result ) . toBe ( Filesystem . normalizePath ( path . resolve ( missing ) ) )
520+ } )
521+
522+ test ( "throws ELOOP on symlink cycle" , async ( ) => {
523+ await using tmp = await tmpdir ( )
524+ const a = path . join ( tmp . path , "a" )
525+ const b = path . join ( tmp . path , "b" )
526+ await fs . symlink ( b , a )
527+ await fs . symlink ( a , b )
528+ expect ( ( ) => Filesystem . resolve ( a ) ) . toThrow ( )
529+ } )
530+
531+ // Windows: chmod(0o000) is a no-op, so EACCES cannot be triggered
532+ test ( "throws EACCES on permission-denied symlink target" , async ( ) => {
533+ if ( process . platform === "win32" ) return
534+ if ( process . getuid ?.( ) === 0 ) return // skip when running as root
535+ await using tmp = await tmpdir ( )
536+ const dir = path . join ( tmp . path , "restricted" )
537+ await fs . mkdir ( dir )
538+ const link = path . join ( tmp . path , "link" )
539+ await fs . symlink ( dir , link )
540+ await fs . chmod ( dir , 0o000 )
541+ try {
542+ expect ( ( ) => Filesystem . resolve ( path . join ( link , "child" ) ) ) . toThrow ( )
543+ } finally {
544+ await fs . chmod ( dir , 0o755 )
545+ }
546+ } )
547+
548+ // Windows: traversing through a file throws ENOENT (not ENOTDIR),
549+ // which resolve() catches as a fallback instead of rethrowing
550+ test ( "rethrows non-ENOENT errors" , async ( ) => {
551+ if ( process . platform === "win32" ) return
552+ await using tmp = await tmpdir ( )
553+ const file = path . join ( tmp . path , "not-a-directory" )
554+ await fs . writeFile ( file , "x" )
555+ expect ( ( ) => Filesystem . resolve ( path . join ( file , "child" ) ) ) . toThrow ( )
556+ } )
505557 } )
506558} )
0 commit comments