1+ // This source file is part of the Swift.org open source project
2+ //
3+ // Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
4+ // Licensed under Apache License v2.0 with Runtime Library Exception
5+ //
6+ // See http://swift.org/LICENSE.txt for license information
7+ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8+ //
9+ 
10+ #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT 
11+     #if canImport(SwiftFoundation) && !DEPLOYMENT_RUNTIME_OBJC 
12+         @testable   import  SwiftFoundation
13+     #else 
14+         @testable   import  Foundation
15+     #endif 
16+ #endif 
17+ 
18+ import  XCTest
19+ 
20+ #if os(Windows) 
21+ // Import Windows C functions
22+ import  WinSDK
23+ 
24+ // Declare _NS_getcwd function for testing
25+ @_silgen_name ( " _NS_getcwd " )  
26+ func  _NS_getcwd( _ buffer:  UnsafeMutablePointer < CChar > ,  _ size:  Int )  ->  UnsafeMutablePointer < CChar > ? 
27+ #endif 
28+ 
29+ class  TestCFPlatformGetcwd :  XCTestCase { 
30+     
31+     #if os(Windows) 
32+     func  test_NS_getcwd_UNC_prefix_stripping( )  { 
33+         // Test that _NS_getcwd properly strips UNC long path prefixes using PathCchStripPrefix
34+         
35+         // Create a temporary directory to work with
36+         let  fm  =  FileManager . default
37+         let  tempDir  =  fm. temporaryDirectory. appendingPathComponent ( " test_getcwd_ \( UUID ( ) . uuidString) " ) 
38+         
39+         do  { 
40+             try . createDirectory ( at:  tempDir,  withIntermediateDirectories:  true ) 
41+             defer  {  try ? . removeItem ( at:  tempDir)  } 
42+             
43+             // Get original directory for restoration
44+             var  originalBuffer  =  [ CChar] ( repeating:  0 ,  count:  Int ( MAX_PATH) ) 
45+             guard  _NS_getcwd ( & originalBuffer,  originalBuffer. count)  !=  nil  else  { 
46+                 XCTFail ( " Failed to get original directory " ) 
47+                 return 
48+             } 
49+             let  originalDir  =  String ( cString:  originalBuffer) 
50+             
51+             defer  { 
52+                 // Restore original directory
53+                 originalDir. withCString  {  _chdir ( $0)  } 
54+             } 
55+             
56+             // Test with UNC long path prefix \\?\
57+             let  uncLongPathPrefix  =  " \\ \\ ? \\ "  +  tempDir. path
58+             let  uncLongPathCString  =  uncLongPathPrefix. cString ( using:  . utf8) !
59+             let  uncChdirResult  =  uncLongPathCString. withUnsafeBufferPointer  {  buffer in 
60+                 return  _chdir ( buffer. baseAddress!) 
61+             } 
62+             XCTAssertEqual ( uncChdirResult,  0 ,  " Failed to change directory using UNC long path prefix " ) 
63+             
64+             // Test _NS_getcwd directly after changing to UNC prefixed path
65+             var  buffer  =  [ CChar] ( repeating:  0 ,  count:  Int ( MAX_PATH) ) 
66+             guard  let  result =  _NS_getcwd ( & buffer,  buffer. count)  else  { 
67+                 XCTFail ( " _NS_getcwd returned null " ) 
68+                 return 
69+             } 
70+             
71+             let  currentDir  =  String ( cString:  result) 
72+             
73+             // Verify that the path doesn't contain UNC prefixes (this is the key test!)
74+             XCTAssertFalse ( currentDir. hasPrefix ( " \\ \\ ? \\ " ) ,  " Current directory path should not contain  \\ \\ ? \\  UNC prefix after stripping " ) 
75+             
76+             // Verify that we can still access the directory (it's a valid path)
77+             XCTAssertTrue ( fm. fileExists ( atPath:  currentDir) ,  " Current directory path should be valid and accessible " ) 
78+             
79+             // Verify the path ends with our test directory name
80+             XCTAssertTrue ( currentDir. hasSuffix ( tempDir. lastPathComponent) ,  " Current directory should end with our test directory name " ) 
81+                        
82+             // Test with a deeper nested directory using UNC prefix to ensure stripping works with longer paths
83+             let  deepDir  =  tempDir. appendingPathComponent ( " level1 " ) . appendingPathComponent ( " level2 " ) . appendingPathComponent ( " level3 " ) 
84+             try . createDirectory ( at:  deepDir,  withIntermediateDirectories:  true ) 
85+             
86+             let  deepUncPath  =  " \\ \\ ? \\ "  +  deepDir. path
87+             let  deepUncCString  =  deepUncPath. cString ( using:  . utf8) !
88+             let  deepChdirResult  =  deepUncCString. withUnsafeBufferPointer  {  buffer in 
89+                 return  _chdir ( buffer. baseAddress!) 
90+             } 
91+             XCTAssertEqual ( deepChdirResult,  0 ,  " Failed to change to deep directory with UNC prefix " ) 
92+             
93+             // Test _NS_getcwd with deep UNC prefixed path
94+             var  deepBuffer  =  [ CChar] ( repeating:  0 ,  count:  Int ( MAX_PATH) ) 
95+             guard  let  deepResult =  _NS_getcwd ( & deepBuffer,  deepBuffer. count)  else  { 
96+                 XCTFail ( " _NS_getcwd returned null for deep UNC path " ) 
97+                 return 
98+             } 
99+             
100+             let  deepCurrentDir  =  String ( cString:  deepResult) 
101+             
102+             // Verify UNC prefixes are stripped from deeper paths too
103+             XCTAssertFalse ( deepCurrentDir. hasPrefix ( " \\ \\ ? \\ " ) ,  " Deep directory path should not contain  \\ \\ ? \\  UNC prefix after stripping " ) 
104+             XCTAssertTrue ( fm. fileExists ( atPath:  deepCurrentDir) ,  " Deep directory path should be valid and accessible " ) 
105+             XCTAssertTrue ( deepCurrentDir. hasSuffix ( " level3 " ) ,  " Deep directory should end with level3 " ) 
106+             
107+         }  catch  { 
108+             XCTFail ( " Failed to set up test environment:  \( error) " ) 
109+         } 
110+     } 
111+            
112+     func  test_NS_getcwd_small_buffer( )  { 
113+         // Test that _NS_getcwd handles small buffer correctly
114+         var  smallBuffer  =  [ CChar] ( repeating:  0 ,  count:  1 ) 
115+         let  result  =  _NS_getcwd ( & smallBuffer,  smallBuffer. count) 
116+         // This should either return null or handle the small buffer gracefully
117+         // The exact behavior depends on the implementation, but it shouldn't crash
118+         XCTAssertTrue ( result ==  nil  || result !=  nil ,  " Function should not crash with small buffer " ) 
119+     } 
120+     #endif 
121+ } 
0 commit comments