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