1- @_spi ( Internal)   import  SwiftFormat
1+ @_spi ( Internal)   @ _spi ( Testing )   import  SwiftFormat
22import  XCTest
33
4+ extension  URL  { 
5+   /// Assuming this is a file URL, resolves all symlinks in the path.
6+   ///
7+   /// - Note: We need this because `URL.resolvingSymlinksInPath()` not only resolves symlinks but also standardizes the
8+   ///   path by stripping away `private` prefixes. Since sourcekitd is not performing this standardization, using
9+   ///   `resolvingSymlinksInPath` can lead to slightly mismatched URLs between the sourcekit-lsp response and the test
10+   ///   assertion.
11+   fileprivate  var  realpath :  URL  { 
12+     #if canImport(Darwin) 
13+     return  self . path. withCString  {  path in 
14+       guard  let  realpath =  Darwin . realpath ( path,  nil )  else  { 
15+         return  self 
16+       } 
17+       let  result  =  URL ( fileURLWithPath:  String ( cString:  realpath) ) 
18+       free ( realpath) 
19+       return  result
20+     } 
21+     #else 
22+     // Non-Darwin platforms don't have the `/private` stripping issue, so we can just use `self.resolvingSymlinksInPath`
23+     // here.
24+     return  self . resolvingSymlinksInPath ( ) 
25+     #endif 
26+   } 
27+ } 
28+ 
429final  class  FileIteratorTests :  XCTestCase  { 
530  private  var  tmpdir :  URL ! 
631
@@ -10,7 +35,7 @@ final class FileIteratorTests: XCTestCase {
1035      in:  . userDomainMask, 
1136      appropriateFor:  FileManager . default. temporaryDirectory, 
1237      create:  true 
13-     ) 
38+     ) . realpath 
1439
1540    // Create a simple file tree used by the tests below.
1641    try touch ( " project/real1.swift " ) 
@@ -31,8 +56,8 @@ final class FileIteratorTests: XCTestCase {
3156    #endif 
3257    let  seen  =  allFilesSeen ( iteratingOver:  [ tmpdir] ,  followSymlinks:  false ) 
3358    XCTAssertEqual ( seen. count,  2 ) 
34-     XCTAssertTrue ( seen. contains  {  $0. hasSuffix ( " project/real1.swift " )  } ) 
35-     XCTAssertTrue ( seen. contains  {  $0. hasSuffix ( " project/real2.swift " )  } ) 
59+     XCTAssertTrue ( seen. contains  {  $0. path . hasSuffix ( " project/real1.swift " )  } ) 
60+     XCTAssertTrue ( seen. contains  {  $0. path . hasSuffix ( " project/real2.swift " )  } ) 
3661  } 
3762
3863  func  testFollowSymlinks( )  throws  { 
@@ -41,10 +66,10 @@ final class FileIteratorTests: XCTestCase {
4166    #endif 
4267    let  seen  =  allFilesSeen ( iteratingOver:  [ tmpdir] ,  followSymlinks:  true ) 
4368    XCTAssertEqual ( seen. count,  3 ) 
44-     XCTAssertTrue ( seen. contains  {  $0. hasSuffix ( " project/real1.swift " )  } ) 
45-     XCTAssertTrue ( seen. contains  {  $0. hasSuffix ( " project/real2.swift " )  } ) 
69+     XCTAssertTrue ( seen. contains  {  $0. path . hasSuffix ( " project/real1.swift " )  } ) 
70+     XCTAssertTrue ( seen. contains  {  $0. path . hasSuffix ( " project/real2.swift " )  } ) 
4671    // Hidden but found through the visible symlink project/link.swift
47-     XCTAssertTrue ( seen. contains  {  $0. hasSuffix ( " project/.hidden.swift " )  } ) 
72+     XCTAssertTrue ( seen. contains  {  $0. path . hasSuffix ( " project/.hidden.swift " )  } ) 
4873  } 
4974
5075  func  testTraversesHiddenFilesIfExplicitlySpecified( )  throws  { 
@@ -56,8 +81,8 @@ final class FileIteratorTests: XCTestCase {
5681      followSymlinks:  false 
5782    ) 
5883    XCTAssertEqual ( seen. count,  2 ) 
59-     XCTAssertTrue ( seen. contains  {  $0. hasSuffix ( " project/.build/generated.swift " )  } ) 
60-     XCTAssertTrue ( seen. contains  {  $0. hasSuffix ( " project/.hidden.swift " )  } ) 
84+     XCTAssertTrue ( seen. contains  {  $0. path . hasSuffix ( " project/.build/generated.swift " )  } ) 
85+     XCTAssertTrue ( seen. contains  {  $0. path . hasSuffix ( " project/.hidden.swift " )  } ) 
6186  } 
6287
6388  func  testDoesNotFollowSymlinksIfFollowSymlinksIsFalseEvenIfExplicitlySpecified( )  { 
@@ -71,6 +96,25 @@ final class FileIteratorTests: XCTestCase {
7196    ) 
7297    XCTAssertTrue ( seen. isEmpty) 
7398  } 
99+ 
100+   func  testDoesNotTrimFirstCharacterOfPathIfRunningInRoot( )  throws  { 
101+     // Find the root of tmpdir. On Unix systems, this is always `/`. On Windows it is the drive.
102+     var  root  =  tmpdir!
103+     while  !root. isRoot { 
104+       root. deleteLastPathComponent ( ) 
105+     } 
106+     // Make sure that we don't drop the beginning of the path if we are running in root.
107+     // https://github.com/swiftlang/swift-format/issues/862
108+     let  seen  =  allFilesSeen ( iteratingOver:  [ tmpdir] ,  followSymlinks:  false ,  workingDirectory:  root) 
109+     XCTAssertTrue ( seen. allSatisfy  {  $0. relativePath. hasPrefix ( root. path)  } ,  " \( seen)  does not contain root directory " ) 
110+   } 
111+ 
112+   func  testShowsRelativePaths( )  throws  { 
113+     // Make sure that we still show the relative path if using them.
114+     // https://github.com/swiftlang/swift-format/issues/862
115+     let  seen  =  allFilesSeen ( iteratingOver:  [ tmpdir] ,  followSymlinks:  false ,  workingDirectory:  tmpdir) 
116+     XCTAssertEqual ( Set ( seen. map ( \. relativePath) ) ,  [ " project/real1.swift " ,  " project/real2.swift " ] ) 
117+   } 
74118} 
75119
76120extension  FileIteratorTests  { 
@@ -111,11 +155,15 @@ extension FileIteratorTests {
111155  } 
112156
113157  /// Computes the list of all files seen by using `FileIterator` to iterate over the given URLs.
114-   private  func  allFilesSeen( iteratingOver urls:  [ URL ] ,  followSymlinks:  Bool )  ->  [ String ]  { 
115-     let  iterator  =  FileIterator ( urls:  urls,  followSymlinks:  followSymlinks) 
116-     var  seen :  [ String ]  =  [ ] 
158+   private  func  allFilesSeen( 
159+     iteratingOver urls:  [ URL ] , 
160+     followSymlinks:  Bool , 
161+     workingDirectory:  URL  =  URL ( fileURLWithPath:  " . " ) 
162+   )  ->  [ URL ]  { 
163+     let  iterator  =  FileIterator ( urls:  urls,  followSymlinks:  followSymlinks,  workingDirectory:  workingDirectory) 
164+     var  seen :  [ URL ]  =  [ ] 
117165    for  next  in  iterator { 
118-       seen. append ( next. path ) 
166+       seen. append ( next) 
119167    } 
120168    return  seen
121169  } 
0 commit comments