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 fm. createDirectory ( at: tempDir, withIntermediateDirectories: true )
41
+ defer { try ? fm. 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 fm. 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