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