@@ -473,70 +473,101 @@ class TestURL : XCTestCase {
473473 XCTAssertTrue ( strncmp ( TestURL . gFileDoesNotExistName, relativePath, lengthOfRelativePath) == 0 , " fileSystemRepresentation of file path is wrong " )
474474 }
475475
476- func test_URLByResolvingSymlinksInPath( ) {
477- let files = [
478- NSTemporaryDirectory ( ) + " ABC/test_URLByResolvingSymlinksInPath "
479- ]
476+ func test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators( ) {
477+ let url = URL ( fileURLWithPath: " //foo///bar////baz/ " )
478+ let result = url. resolvingSymlinksInPath ( )
479+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /foo/bar/baz " ) )
480+ }
480481
481- guard ensureFiles ( files) else {
482- XCTAssert ( false , " Could create files for testing. " )
483- return
484- }
482+ func test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators( ) {
483+ let url = URL ( fileURLWithPath: " /./foo/./.bar/./baz/./ " )
484+ let result = url. resolvingSymlinksInPath ( )
485+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /foo/.bar/baz " ) )
486+ }
485487
486- // tmp is special because it is symlinked to /private/tmp and this /private prefix should be dropped,
487- // so tmp is tmp. On Linux tmp is not symlinked so it would be the same.
488- do {
489- let url = URL ( fileURLWithPath: " /.//tmp/ABC/.. " )
490- let result = url. resolvingSymlinksInPath ( ) . absoluteString
491- XCTAssertEqual ( result, " file:///tmp/ " , " URLByResolvingSymlinksInPath removes extraneous path components and resolve symlinks. " )
492- }
488+ func test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators( ) {
489+ let url = URL ( fileURLWithPath: " /foo/../..bar/../baz/ " )
490+ let result = url. resolvingSymlinksInPath ( )
491+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /baz " ) )
492+ }
493493
494- do {
495- let url = URL ( fileURLWithPath: " ~ " )
496- let result = url. resolvingSymlinksInPath ( ) . absoluteString
497- #if os(Windows)
498- // On Windows `currentDirectoryPath` will return something like
499- // `C:/Users/...` which doesn't have a leading slash
500- let expected = " file:/// " + FileManager. default. currentDirectoryPath + " /~ "
501- #else
502- let expected = " file:// " + FileManager. default. currentDirectoryPath + " /~ "
503- #endif
504- XCTAssertEqual ( result, expected, " URLByResolvingSymlinksInPath resolves relative paths using current working directory. " )
505- }
494+ func test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory( ) throws {
495+ let fileManager = FileManager . default
496+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
497+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
498+
499+ let previousCurrentDirectory = fileManager. currentDirectoryPath
500+ fileManager. changeCurrentDirectoryPath ( writableTestDirectoryURL. path)
501+ defer { fileManager. changeCurrentDirectoryPath ( previousCurrentDirectory) }
502+
503+ // In Darwin, because temporary directory is inside /private,
504+ // writableTestDirectoryURL will be something like /var/folders/...,
505+ // but /var points to /private/var, which is only removed if the
506+ // destination exists, so we create the destination to avoid having to
507+ // compare against /private in Darwin.
508+ try fileManager. createDirectory ( at: writableTestDirectoryURL. appendingPathComponent ( " foo/bar " ) , withIntermediateDirectories: true )
509+ try " " . write ( to: writableTestDirectoryURL. appendingPathComponent ( " foo/bar/baz " ) , atomically: true , encoding: . utf8)
510+
511+ let url = URL ( fileURLWithPath: " foo/bar/baz " )
512+ let result = url. resolvingSymlinksInPath ( )
513+ XCTAssertEqual ( result, URL ( fileURLWithPath: writableTestDirectoryURL. path + " /foo/bar/baz " ) )
514+ }
506515
507- do {
508- let url = URL ( fileURLWithPath: " anysite.com/search " )
509- let result = url. resolvingSymlinksInPath ( ) . absoluteString
510- #if os(Windows)
511- // On Windows `currentDirectoryPath` will return something like
512- // `C:/Users/...` which doesn't have a leading slash
513- let expected = " file:/// " + FileManager. default. currentDirectoryPath + " /anysite.com/search "
514- #else
515- let expected = " file:// " + FileManager. default. currentDirectoryPath + " /anysite.com/search "
516- #endif
517- XCTAssertEqual ( result, expected)
518- }
516+ func test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory( ) throws {
517+ let fileManager = FileManager . default
518+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
519+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
519520
520- // tmp is symlinked on macOS only
521- #if os(macOS)
522- do {
523- let url = URL ( fileURLWithPath: " /tmp/.. " )
524- let result = url. resolvingSymlinksInPath ( ) . absoluteString
525- XCTAssertEqual ( result, " file:///private/ " )
521+ var path = writableTestDirectoryURL. path
522+ if path. hasSuffix ( " / " ) {
523+ path. remove ( at: path. index ( path. endIndex, offsetBy: - 1 ) )
526524 }
527- #else
528- do {
529- let url = URL ( fileURLWithPath: " /tmp/ABC/test_URLByResolvingSymlinksInPath " )
530- let result = url. resolvingSymlinksInPath ( ) . absoluteString
531- XCTAssertEqual ( result, " file:///tmp/ABC/test_URLByResolvingSymlinksInPath " , " URLByResolvingSymlinksInPath appends trailing slash for existing directories only " )
532- }
533- #endif
525+ let url = URL ( fileURLWithPath: path)
526+ let result = url. resolvingSymlinksInPath ( )
527+ XCTAssertEqual ( result, URL ( fileURLWithPath: path + " / " ) )
528+ }
534529
535- do {
536- let url = URL ( fileURLWithPath: " /tmp/ABC/.. " )
537- let result = url. resolvingSymlinksInPath ( ) . absoluteString
538- XCTAssertEqual ( result, " file:///tmp/ " )
539- }
530+ func test_resolvingSymlinksInPathShouldResolveSymlinks( ) throws {
531+ // NOTE: this test only works on file systems that support symlinks.
532+ let fileManager = FileManager . default
533+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
534+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
535+
536+ let symbolicLink = writableTestDirectoryURL. appendingPathComponent ( " origin " )
537+ let destination = writableTestDirectoryURL. appendingPathComponent ( " destination " )
538+ try " " . write ( to: destination, atomically: true , encoding: . utf8)
539+ try fileManager. createSymbolicLink ( at: symbolicLink, withDestinationURL: destination)
540+
541+ let result = symbolicLink. resolvingSymlinksInPath ( )
542+ XCTAssertEqual ( result, URL ( fileURLWithPath: writableTestDirectoryURL. path + " /destination " ) )
543+ }
544+
545+ func test_resolvingSymlinksInPathShouldRemovePrivatePrefix( ) {
546+ // NOTE: this test only works on Darwin, since the code that removes
547+ // /private relies on /private/tmp existing.
548+ let url = URL ( fileURLWithPath: " /private/tmp " )
549+ let result = url. resolvingSymlinksInPath ( )
550+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /tmp " ) )
551+ }
552+
553+ func test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent( ) {
554+ // NOTE: this test only works on Darwin, since only there /tmp is
555+ // symlinked to /private/tmp.
556+ let url = URL ( fileURLWithPath: " /tmp/.. " )
557+ let result = url. resolvingSymlinksInPath ( )
558+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /private " ) )
559+ }
560+
561+ func test_resolvingSymlinksInPathShouldNotChangeNonFileURLs( ) throws {
562+ let url = try XCTUnwrap ( URL ( string: " myscheme://server/foo/bar/baz " ) )
563+ let result = url. resolvingSymlinksInPath ( ) . absoluteString
564+ XCTAssertEqual ( result, " myscheme://server/foo/bar/baz " )
565+ }
566+
567+ func test_resolvingSymlinksInPathShouldNotChangePathlessURLs( ) throws {
568+ let url = try XCTUnwrap ( URL ( string: " file:// " ) )
569+ let result = url. resolvingSymlinksInPath ( ) . absoluteString
570+ XCTAssertEqual ( result, " file:// " )
540571 }
541572
542573 func test_reachable( ) {
@@ -719,7 +750,14 @@ class TestURL : XCTestCase {
719750 // TODO: these tests fail on linux, more investigation is needed
720751 ( " test_fileURLWithPath " , test_fileURLWithPath) ,
721752 ( " test_fileURLWithPath_isDirectory " , test_fileURLWithPath_isDirectory) ,
722- ( " test_URLByResolvingSymlinksInPath " , test_URLByResolvingSymlinksInPath) ,
753+ ( " test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators " , test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators) ,
754+ ( " test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators " , test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators) ,
755+ ( " test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators " , test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators) ,
756+ ( " test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory " , test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory) ,
757+ ( " test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory " , test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory) ,
758+ ( " test_resolvingSymlinksInPathShouldResolveSymlinks " , test_resolvingSymlinksInPathShouldResolveSymlinks) ,
759+ ( " test_resolvingSymlinksInPathShouldNotChangeNonFileURLs " , test_resolvingSymlinksInPathShouldNotChangeNonFileURLs) ,
760+ ( " test_resolvingSymlinksInPathShouldNotChangePathlessURLs " , test_resolvingSymlinksInPathShouldNotChangePathlessURLs) ,
723761 ( " test_reachable " , test_reachable) ,
724762 ( " test_copy " , test_copy) ,
725763 ( " test_itemNSCoding " , test_itemNSCoding) ,
@@ -736,6 +774,13 @@ class TestURL : XCTestCase {
736774 ] )
737775#endif
738776
777+ #if canImport(Darwin)
778+ tests += [
779+ ( " test_resolvingSymlinksInPathShouldRemovePrivatePrefix " , test_resolvingSymlinksInPathShouldRemovePrivatePrefix) ,
780+ ( " test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent " , test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent) ,
781+ ]
782+ #endif
783+
739784 return tests
740785 }
741786}
0 commit comments