@@ -434,60 +434,103 @@ class TestURL : XCTestCase {
434434 XCTAssertTrue ( strncmp ( TestURL . gFileDoesNotExistName, relativePath, lengthOfRelativePath) == 0 , " fileSystemRepresentation of file path is wrong " )
435435 }
436436
437- func test_URLByResolvingSymlinksInPath( ) {
438- let files = [
439- NSTemporaryDirectory ( ) + " ABC/test_URLByResolvingSymlinksInPath "
440- ]
441-
442- guard ensureFiles ( files) else {
443- XCTAssert ( false , " Could create files for testing. " )
444- return
445- }
446-
447- // tmp is special because it is symlinked to /private/tmp and this /private prefix should be dropped,
448- // so tmp is tmp. On Linux tmp is not symlinked so it would be the same.
449- do {
450- let url = URL ( fileURLWithPath: " /.//tmp/ABC/.. " )
451- let result = url. resolvingSymlinksInPath ( ) . absoluteString
452- XCTAssertEqual ( result, " file:///tmp/ " , " URLByResolvingSymlinksInPath removes extraneous path components and resolve symlinks. " )
453- }
437+ func test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators( ) {
438+ let url = URL ( fileURLWithPath: " //foo///bar////baz/ " )
439+ let result = url. resolvingSymlinksInPath ( )
440+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /foo/bar/baz " ) )
441+ }
454442
455- do {
456- let url = URL ( fileURLWithPath: " ~ " )
457- let result = url. resolvingSymlinksInPath ( ) . absoluteString
458- let expected = " file:// " + FileManager. default. currentDirectoryPath + " /~ "
459- XCTAssertEqual ( result, expected, " URLByResolvingSymlinksInPath resolves relative paths using current working directory. " )
460- }
443+ func test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators( ) {
444+ let url = URL ( fileURLWithPath: " /./foo/./.bar/./baz/./ " )
445+ let result = url. resolvingSymlinksInPath ( )
446+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /foo/.bar/baz " ) )
447+ }
461448
462- do {
463- let url = URL ( fileURLWithPath: " anysite.com/search " )
464- let result = url. resolvingSymlinksInPath ( ) . absoluteString
465- let expected = " file:// " + FileManager. default. currentDirectoryPath + " /anysite.com/search "
466- XCTAssertEqual ( result, expected)
467- }
449+ func test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators( ) {
450+ let url = URL ( fileURLWithPath: " /foo/../..bar/../baz/ " )
451+ let result = url. resolvingSymlinksInPath ( )
452+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /baz " ) )
453+ }
468454
469- // tmp is symlinked on macOS only
470- #if os(macOS)
471- do {
472- let url = URL ( fileURLWithPath: " /tmp/.. " )
473- let result = url. resolvingSymlinksInPath ( ) . absoluteString
474- XCTAssertEqual ( result, " file:///private/ " )
475- }
476- #else
477- do {
478- let url = URL ( fileURLWithPath: " /tmp/ABC/test_URLByResolvingSymlinksInPath " )
479- let result = url. resolvingSymlinksInPath ( ) . absoluteString
480- XCTAssertEqual ( result, " file:///tmp/ABC/test_URLByResolvingSymlinksInPath " , " URLByResolvingSymlinksInPath appends trailing slash for existing directories only " )
481- }
482- #endif
455+ func test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory( ) throws {
456+ let fileManager = FileManager . default
457+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
458+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
483459
484- do {
485- let url = URL ( fileURLWithPath: " /tmp/ABC/.. " )
486- let result = url. resolvingSymlinksInPath ( ) . absoluteString
487- XCTAssertEqual ( result, " file:///tmp/ " )
460+ let previousCurrentDirectory = fileManager. currentDirectoryPath
461+ fileManager. changeCurrentDirectoryPath ( writableTestDirectoryURL. path)
462+ defer { fileManager. changeCurrentDirectoryPath ( previousCurrentDirectory) }
463+
464+ // In Darwin, because temporary directory is inside /private,
465+ // writableTestDirectoryURL will be something like /var/folders/...,
466+ // but /var points to /private/var, which is only removed if the
467+ // destination exists, so we create the destination to avoid having to
468+ // compare against /private in Darwin.
469+ try fileManager. createDirectory ( at: writableTestDirectoryURL. appendingPathComponent ( " foo/bar " ) , withIntermediateDirectories: true )
470+ try " " . write ( to: writableTestDirectoryURL. appendingPathComponent ( " foo/bar/baz " ) , atomically: true , encoding: . utf8)
471+
472+ let url = URL ( fileURLWithPath: " foo/bar/baz " )
473+ let result = url. resolvingSymlinksInPath ( )
474+ XCTAssertEqual ( result, URL ( fileURLWithPath: writableTestDirectoryURL. path + " /foo/bar/baz " ) )
475+ }
476+
477+ func test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory( ) throws {
478+ let fileManager = FileManager . default
479+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
480+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
481+
482+ var path = writableTestDirectoryURL. path
483+ if path. hasSuffix ( " / " ) {
484+ path. remove ( at: path. index ( path. endIndex, offsetBy: - 1 ) )
488485 }
486+ let url = URL ( fileURLWithPath: path)
487+ let result = url. resolvingSymlinksInPath ( )
488+ XCTAssertEqual ( result, URL ( fileURLWithPath: path + " / " ) )
489489 }
490-
490+
491+ func test_resolvingSymlinksInPathShouldResolveSymlinks( ) throws {
492+ // NOTE: this test only works on file systems that support symlinks.
493+ let fileManager = FileManager . default
494+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
495+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
496+
497+ let symbolicLink = writableTestDirectoryURL. appendingPathComponent ( " origin " )
498+ let destination = writableTestDirectoryURL. appendingPathComponent ( " destination " )
499+ try " " . write ( to: destination, atomically: true , encoding: . utf8)
500+ try fileManager. createSymbolicLink ( at: symbolicLink, withDestinationURL: destination)
501+
502+ let result = symbolicLink. resolvingSymlinksInPath ( )
503+ XCTAssertEqual ( result, URL ( fileURLWithPath: writableTestDirectoryURL. path + " /destination " ) )
504+ }
505+
506+ func test_resolvingSymlinksInPathShouldRemovePrivatePrefix( ) {
507+ // NOTE: this test only works on Darwin, since the code that removes
508+ // /private relies on /private/tmp existing.
509+ let url = URL ( fileURLWithPath: " /private/tmp " )
510+ let result = url. resolvingSymlinksInPath ( )
511+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /tmp " ) )
512+ }
513+
514+ func test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent( ) {
515+ // NOTE: this test only works on Darwin, since only there /tmp is
516+ // symlinked to /private/tmp.
517+ let url = URL ( fileURLWithPath: " /tmp/.. " )
518+ let result = url. resolvingSymlinksInPath ( )
519+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /private " ) )
520+ }
521+
522+ func test_resolvingSymlinksInPathShouldNotChangeNonFileURLs( ) throws {
523+ let url = try URL ( string: " myscheme://server/foo/bar/baz " ) . unwrapped ( )
524+ let result = url. resolvingSymlinksInPath ( ) . absoluteString
525+ XCTAssertEqual ( result, " myscheme://server/foo/bar/baz " )
526+ }
527+
528+ func test_resolvingSymlinksInPathShouldNotChangePathlessURLs( ) throws {
529+ let url = try URL ( string: " file:// " ) . unwrapped ( )
530+ let result = url. resolvingSymlinksInPath ( ) . absoluteString
531+ XCTAssertEqual ( result, " file:// " )
532+ }
533+
491534 func test_reachable( ) {
492535 #if os(Android)
493536 var url = URL ( fileURLWithPath: " /data " )
@@ -664,7 +707,14 @@ class TestURL : XCTestCase {
664707 // TODO: these tests fail on linux, more investigation is needed
665708 ( " test_fileURLWithPath " , test_fileURLWithPath) ,
666709 ( " test_fileURLWithPath_isDirectory " , test_fileURLWithPath_isDirectory) ,
667- ( " test_URLByResolvingSymlinksInPath " , test_URLByResolvingSymlinksInPath) ,
710+ ( " test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators " , test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators) ,
711+ ( " test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators " , test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators) ,
712+ ( " test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators " , test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators) ,
713+ ( " test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory " , test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory) ,
714+ ( " test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory " , test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory) ,
715+ ( " test_resolvingSymlinksInPathShouldResolveSymlinks " , test_resolvingSymlinksInPathShouldResolveSymlinks) ,
716+ ( " test_resolvingSymlinksInPathShouldNotChangeNonFileURLs " , test_resolvingSymlinksInPathShouldNotChangeNonFileURLs) ,
717+ ( " test_resolvingSymlinksInPathShouldNotChangePathlessURLs " , test_resolvingSymlinksInPathShouldNotChangePathlessURLs) ,
668718 ( " test_reachable " , test_reachable) ,
669719 ( " test_copy " , test_copy) ,
670720 ( " test_itemNSCoding " , test_itemNSCoding) ,
@@ -681,6 +731,13 @@ class TestURL : XCTestCase {
681731 ] )
682732#endif
683733
734+ #if canImport(Darwin)
735+ tests += [
736+ ( " test_resolvingSymlinksInPathShouldRemovePrivatePrefix " , test_resolvingSymlinksInPathShouldRemovePrivatePrefix) ,
737+ ( " test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent " , test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent) ,
738+ ]
739+ #endif
740+
684741 return tests
685742 }
686743}
0 commit comments