@@ -455,58 +455,101 @@ class TestURL : XCTestCase {
455
455
XCTAssertTrue ( strncmp ( TestURL . gFileDoesNotExistName, relativePath, lengthOfRelativePath) == 0 , " fileSystemRepresentation of file path is wrong " )
456
456
}
457
457
458
- func test_URLByResolvingSymlinksInPath( ) {
459
- let files = [
460
- NSTemporaryDirectory ( ) + " ABC/test_URLByResolvingSymlinksInPath "
461
- ]
458
+ func test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators( ) {
459
+ let url = URL ( fileURLWithPath: " //foo///bar////baz/ " )
460
+ let result = url. resolvingSymlinksInPath ( )
461
+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /foo/bar/baz " ) )
462
+ }
462
463
463
- guard ensureFiles ( files) else {
464
- XCTAssert ( false , " Could create files for testing. " )
465
- return
466
- }
464
+ func test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators( ) {
465
+ let url = URL ( fileURLWithPath: " /./foo/./.bar/./baz/./ " )
466
+ let result = url. resolvingSymlinksInPath ( )
467
+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /foo/.bar/baz " ) )
468
+ }
467
469
468
- // tmp is special because it is symlinked to /private/tmp and this /private prefix should be dropped,
469
- // so tmp is tmp. On Linux tmp is not symlinked so it would be the same.
470
- do {
471
- let url = URL ( fileURLWithPath: " /.//tmp/ABC/.. " )
472
- let result = url. resolvingSymlinksInPath ( ) . absoluteString
473
- XCTAssertEqual ( result, " file:///tmp/ " , " URLByResolvingSymlinksInPath removes extraneous path components and resolve symlinks. " )
474
- }
470
+ func test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators( ) {
471
+ let url = URL ( fileURLWithPath: " /foo/../..bar/../baz/ " )
472
+ let result = url. resolvingSymlinksInPath ( )
473
+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /baz " ) )
474
+ }
475
475
476
- do {
477
- let url = URL ( fileURLWithPath: " ~ " )
478
- let result = url. resolvingSymlinksInPath ( ) . absoluteString
479
- let expected = " file:// " + FileManager. default. currentDirectoryPath + " /~ "
480
- XCTAssertEqual ( result, expected, " URLByResolvingSymlinksInPath resolves relative paths using current working directory. " )
481
- }
476
+ func test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory( ) throws {
477
+ let fileManager = FileManager . default
478
+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
479
+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
480
+
481
+ let previousCurrentDirectory = fileManager. currentDirectoryPath
482
+ fileManager. changeCurrentDirectoryPath ( writableTestDirectoryURL. path)
483
+ defer { fileManager. changeCurrentDirectoryPath ( previousCurrentDirectory) }
484
+
485
+ // In Darwin, because temporary directory is inside /private,
486
+ // writableTestDirectoryURL will be something like /var/folders/...,
487
+ // but /var points to /private/var, which is only removed if the
488
+ // destination exists, so we create the destination to avoid having to
489
+ // compare against /private in Darwin.
490
+ try fileManager. createDirectory ( at: writableTestDirectoryURL. appendingPathComponent ( " foo/bar " ) , withIntermediateDirectories: true )
491
+ try " " . write ( to: writableTestDirectoryURL. appendingPathComponent ( " foo/bar/baz " ) , atomically: true , encoding: . utf8)
492
+
493
+ let url = URL ( fileURLWithPath: " foo/bar/baz " )
494
+ let result = url. resolvingSymlinksInPath ( )
495
+ XCTAssertEqual ( result, URL ( fileURLWithPath: writableTestDirectoryURL. path + " /foo/bar/baz " ) )
496
+ }
482
497
483
- do {
484
- let url = URL ( fileURLWithPath: " anysite.com/search " )
485
- let result = url. resolvingSymlinksInPath ( ) . absoluteString
486
- let expected = " file:// " + FileManager. default. currentDirectoryPath + " /anysite.com/search "
487
- XCTAssertEqual ( result, expected)
488
- }
498
+ func test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory( ) throws {
499
+ let fileManager = FileManager . default
500
+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
501
+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
489
502
490
- // tmp is symlinked on macOS only
491
- #if os(macOS)
492
- do {
493
- let url = URL ( fileURLWithPath: " /tmp/.. " )
494
- let result = url. resolvingSymlinksInPath ( ) . absoluteString
495
- XCTAssertEqual ( result, " file:///private/ " )
496
- }
497
- #else
498
- do {
499
- let url = URL ( fileURLWithPath: " /tmp/ABC/test_URLByResolvingSymlinksInPath " )
500
- let result = url. resolvingSymlinksInPath ( ) . absoluteString
501
- XCTAssertEqual ( result, " file:///tmp/ABC/test_URLByResolvingSymlinksInPath " , " URLByResolvingSymlinksInPath appends trailing slash for existing directories only " )
503
+ var path = writableTestDirectoryURL. path
504
+ if path. hasSuffix ( " / " ) {
505
+ path. remove ( at: path. index ( path. endIndex, offsetBy: - 1 ) )
502
506
}
503
- #endif
507
+ let url = URL ( fileURLWithPath: path)
508
+ let result = url. resolvingSymlinksInPath ( )
509
+ XCTAssertEqual ( result, URL ( fileURLWithPath: path + " / " ) )
510
+ }
504
511
505
- do {
506
- let url = URL ( fileURLWithPath: " /tmp/ABC/.. " )
507
- let result = url. resolvingSymlinksInPath ( ) . absoluteString
508
- XCTAssertEqual ( result, " file:///tmp/ " )
509
- }
512
+ func test_resolvingSymlinksInPathShouldResolveSymlinks( ) throws {
513
+ // NOTE: this test only works on file systems that support symlinks.
514
+ let fileManager = FileManager . default
515
+ try fileManager. createDirectory ( at: writableTestDirectoryURL, withIntermediateDirectories: true )
516
+ defer { try ? fileManager. removeItem ( at: writableTestDirectoryURL) }
517
+
518
+ let symbolicLink = writableTestDirectoryURL. appendingPathComponent ( " origin " )
519
+ let destination = writableTestDirectoryURL. appendingPathComponent ( " destination " )
520
+ try " " . write ( to: destination, atomically: true , encoding: . utf8)
521
+ try fileManager. createSymbolicLink ( at: symbolicLink, withDestinationURL: destination)
522
+
523
+ let result = symbolicLink. resolvingSymlinksInPath ( )
524
+ XCTAssertEqual ( result, URL ( fileURLWithPath: writableTestDirectoryURL. path + " /destination " ) )
525
+ }
526
+
527
+ func test_resolvingSymlinksInPathShouldRemovePrivatePrefix( ) {
528
+ // NOTE: this test only works on Darwin, since the code that removes
529
+ // /private relies on /private/tmp existing.
530
+ let url = URL ( fileURLWithPath: " /private/tmp " )
531
+ let result = url. resolvingSymlinksInPath ( )
532
+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /tmp " ) )
533
+ }
534
+
535
+ func test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent( ) {
536
+ // NOTE: this test only works on Darwin, since only there /tmp is
537
+ // symlinked to /private/tmp.
538
+ let url = URL ( fileURLWithPath: " /tmp/.. " )
539
+ let result = url. resolvingSymlinksInPath ( )
540
+ XCTAssertEqual ( result, URL ( fileURLWithPath: " /private " ) )
541
+ }
542
+
543
+ func test_resolvingSymlinksInPathShouldNotChangeNonFileURLs( ) throws {
544
+ let url = try XCTUnwrap ( URL ( string: " myscheme://server/foo/bar/baz " ) )
545
+ let result = url. resolvingSymlinksInPath ( ) . absoluteString
546
+ XCTAssertEqual ( result, " myscheme://server/foo/bar/baz " )
547
+ }
548
+
549
+ func test_resolvingSymlinksInPathShouldNotChangePathlessURLs( ) throws {
550
+ let url = try XCTUnwrap ( URL ( string: " file:// " ) )
551
+ let result = url. resolvingSymlinksInPath ( ) . absoluteString
552
+ XCTAssertEqual ( result, " file:// " )
510
553
}
511
554
512
555
func test_reachable( ) {
@@ -689,7 +732,14 @@ class TestURL : XCTestCase {
689
732
// TODO: these tests fail on linux, more investigation is needed
690
733
( " test_fileURLWithPath " , test_fileURLWithPath) ,
691
734
( " test_fileURLWithPath_isDirectory " , test_fileURLWithPath_isDirectory) ,
692
- ( " test_URLByResolvingSymlinksInPath " , test_URLByResolvingSymlinksInPath) ,
735
+ ( " test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators " , test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators) ,
736
+ ( " test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators " , test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators) ,
737
+ ( " test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators " , test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators) ,
738
+ ( " test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory " , test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory) ,
739
+ ( " test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory " , test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory) ,
740
+ ( " test_resolvingSymlinksInPathShouldResolveSymlinks " , test_resolvingSymlinksInPathShouldResolveSymlinks) ,
741
+ ( " test_resolvingSymlinksInPathShouldNotChangeNonFileURLs " , test_resolvingSymlinksInPathShouldNotChangeNonFileURLs) ,
742
+ ( " test_resolvingSymlinksInPathShouldNotChangePathlessURLs " , test_resolvingSymlinksInPathShouldNotChangePathlessURLs) ,
693
743
( " test_reachable " , test_reachable) ,
694
744
( " test_copy " , test_copy) ,
695
745
( " test_itemNSCoding " , test_itemNSCoding) ,
@@ -706,6 +756,13 @@ class TestURL : XCTestCase {
706
756
] )
707
757
#endif
708
758
759
+ #if canImport(Darwin)
760
+ tests += [
761
+ ( " test_resolvingSymlinksInPathShouldRemovePrivatePrefix " , test_resolvingSymlinksInPathShouldRemovePrivatePrefix) ,
762
+ ( " test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent " , test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent) ,
763
+ ]
764
+ #endif
765
+
709
766
return tests
710
767
}
711
768
}
0 commit comments