@@ -434,60 +434,103 @@ class TestURL : XCTestCase {
434
434
XCTAssertTrue ( strncmp ( TestURL . gFileDoesNotExistName, relativePath, lengthOfRelativePath) == 0 , " fileSystemRepresentation of file path is wrong " )
435
435
}
436
436
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
+ }
454
442
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
+ }
461
448
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
+ }
468
454
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) }
483
459
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 ) )
488
485
}
486
+ let url = URL ( fileURLWithPath: path)
487
+ let result = url. resolvingSymlinksInPath ( )
488
+ XCTAssertEqual ( result, URL ( fileURLWithPath: path + " / " ) )
489
489
}
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
+
491
534
func test_reachable( ) {
492
535
#if os(Android)
493
536
var url = URL ( fileURLWithPath: " /data " )
@@ -664,7 +707,14 @@ class TestURL : XCTestCase {
664
707
// TODO: these tests fail on linux, more investigation is needed
665
708
( " test_fileURLWithPath " , test_fileURLWithPath) ,
666
709
( " 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) ,
668
718
( " test_reachable " , test_reachable) ,
669
719
( " test_copy " , test_copy) ,
670
720
( " test_itemNSCoding " , test_itemNSCoding) ,
@@ -681,6 +731,13 @@ class TestURL : XCTestCase {
681
731
] )
682
732
#endif
683
733
734
+ #if canImport(Darwin)
735
+ tests += [
736
+ ( " test_resolvingSymlinksInPathShouldRemovePrivatePrefix " , test_resolvingSymlinksInPathShouldRemovePrivatePrefix) ,
737
+ ( " test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent " , test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent) ,
738
+ ]
739
+ #endif
740
+
684
741
return tests
685
742
}
686
743
}
0 commit comments