4
4
using System ;
5
5
using System . Collections . Generic ;
6
6
using System . IO ;
7
+ using System . Runtime . InteropServices ;
8
+ using System . Text ;
7
9
using Xunit ;
8
10
9
11
public static class PathTests
10
12
{
11
- [ Fact ]
12
- public static void ChangeExtension ( )
13
+ [ Theory ]
14
+ [ InlineData ( null , null , null ) ]
15
+ [ InlineData ( null , null , "exe" ) ]
16
+ [ InlineData ( "" , "" , "" ) ]
17
+ [ InlineData ( "file" , "file.exe" , null ) ]
18
+ [ InlineData ( "file." , "file.exe" , "" ) ]
19
+ [ InlineData ( "file.exe" , "file" , "exe" ) ]
20
+ [ InlineData ( "file.exe" , "file" , ".exe" ) ]
21
+ [ InlineData ( "file.exe" , "file.txt" , "exe" ) ]
22
+ [ InlineData ( "file.exe" , "file.txt" , ".exe" ) ]
23
+ [ InlineData ( "file.txt.exe" , "file.txt.bin" , "exe" ) ]
24
+ [ InlineData ( "dir/file.exe" , "dir/file.t" , "exe" ) ]
25
+ [ InlineData ( "dir/file.t" , "dir/file.exe" , "t" ) ]
26
+ [ InlineData ( "dir/file.exe" , "dir/file" , "exe" ) ]
27
+ public static void ChangeExtension ( string expected , string path , string newExtension )
13
28
{
14
- Assert . Null ( Path . ChangeExtension ( null , null ) ) ;
15
- Assert . Equal ( "file" , Path . ChangeExtension ( "file.exe" , null ) ) ;
16
- Assert . Equal ( "file.exe" , Path . ChangeExtension ( "file.txt" , "exe" ) ) ;
29
+ if ( expected != null )
30
+ expected = expected . Replace ( '/' , Path . DirectorySeparatorChar ) ;
31
+ if ( path != null )
32
+ path = path . Replace ( '/' , Path . DirectorySeparatorChar ) ;
33
+ Assert . Equal ( expected , Path . ChangeExtension ( path , newExtension ) ) ;
17
34
}
18
35
19
36
[ Fact ]
20
37
public static void GetDirectoryName ( )
21
38
{
39
+ Assert . Null ( Path . GetDirectoryName ( null ) ) ;
22
40
Assert . Equal ( "dir" , Path . GetDirectoryName ( Path . Combine ( "dir" , "baz" ) ) ) ;
41
+ Assert . Equal ( Path . GetDirectoryName ( "." ) , Path . GetDirectoryName ( "dir" ) ) ;
23
42
Assert . Equal ( null , Path . GetDirectoryName ( Path . GetPathRoot ( Directory . GetCurrentDirectory ( ) ) ) ) ;
24
43
}
25
44
26
- [ Fact ]
27
- public static void GetExtension ( )
45
+ [ Theory ]
46
+ [ InlineData ( ".exe" , "file.exe" ) ]
47
+ [ InlineData ( "" , "file" ) ]
48
+ [ InlineData ( null , null ) ]
49
+ [ InlineData ( "" , "file." ) ]
50
+ [ InlineData ( ".s" , "file.s" ) ]
51
+ [ InlineData ( "" , "test/file" ) ]
52
+ [ InlineData ( ".extension" , "test/file.extension" ) ]
53
+ public static void GetExtension ( string expected , string path )
28
54
{
29
- Assert . Equal ( ".exe" , Path . GetExtension ( "file.exe" ) ) ;
30
- Assert . True ( Path . HasExtension ( "file.exe" ) ) ;
31
-
32
- Assert . Equal ( string . Empty , Path . GetExtension ( "file" ) ) ;
33
- Assert . False ( Path . HasExtension ( "file" ) ) ;
34
-
35
- Assert . Null ( Path . GetExtension ( null ) ) ;
36
- Assert . False ( Path . HasExtension ( null ) ) ;
37
-
38
- Assert . Equal ( "" , Path . GetExtension ( "file." ) ) ;
39
- Assert . False ( Path . HasExtension ( "file." ) ) ;
40
-
41
- Assert . Equal ( "" , Path . GetExtension ( Path . Combine ( "test" , "file" ) ) ) ;
42
- Assert . False ( Path . HasExtension ( Path . Combine ( "test" , "file" ) ) ) ;
55
+ if ( path != null )
56
+ path = path . Replace ( '/' , Path . DirectorySeparatorChar ) ;
57
+ Assert . Equal ( expected , Path . GetExtension ( path ) ) ;
58
+ Assert . Equal ( ! string . IsNullOrEmpty ( expected ) , Path . HasExtension ( path ) ) ;
43
59
}
44
60
45
61
[ Fact ]
@@ -60,21 +76,32 @@ public static void GetFileNameWithoutExtension()
60
76
[ Fact ]
61
77
public static void GetPathRoot ( )
62
78
{
79
+ Assert . Null ( Path . GetPathRoot ( null ) ) ;
80
+
63
81
string cwd = Directory . GetCurrentDirectory ( ) ;
64
82
Assert . Equal ( cwd . Substring ( 0 , cwd . IndexOf ( Path . DirectorySeparatorChar ) + 1 ) , Path . GetPathRoot ( cwd ) ) ;
65
83
Assert . True ( Path . IsPathRooted ( cwd ) ) ;
84
+
66
85
Assert . Equal ( string . Empty , Path . GetPathRoot ( @"file.exe" ) ) ;
67
86
Assert . False ( Path . IsPathRooted ( "file.exe" ) ) ;
87
+
88
+ if ( Interop . IsWindows ) // UNC paths
89
+ {
90
+ Assert . Equal ( @"\\test\unc" , Path . GetPathRoot ( @"\\test\unc\path\to\something" ) ) ;
91
+ Assert . True ( Path . IsPathRooted ( @"\\test\unc\path\to\something" ) ) ;
92
+ }
68
93
}
69
94
70
95
[ Fact ]
71
96
public static void GetRandomFileName ( )
72
97
{
98
+ var fileNames = new HashSet < string > ( ) ;
73
99
for ( int i = 0 ; i < 100 ; i ++ )
74
100
{
75
- String s = Path . GetRandomFileName ( ) ;
101
+ string s = Path . GetRandomFileName ( ) ;
76
102
Assert . Equal ( s . Length , 8 + 1 + 3 ) ;
77
103
Assert . Equal ( s [ 8 ] , '.' ) ;
104
+ Assert . True ( fileNames . Add ( s ) ) ;
78
105
}
79
106
}
80
107
@@ -85,6 +112,22 @@ public static void GetInvalidPathChars()
85
112
Assert . NotSame ( Path . GetInvalidPathChars ( ) , Path . GetInvalidPathChars ( ) ) ;
86
113
Assert . Equal ( ( IEnumerable < char > ) Path . GetInvalidPathChars ( ) , ( IEnumerable < char > ) Path . GetInvalidPathChars ( ) ) ;
87
114
Assert . True ( Path . GetInvalidPathChars ( ) . Length > 0 ) ;
115
+ Assert . All ( Path . GetInvalidPathChars ( ) , c =>
116
+ {
117
+ string bad = c . ToString ( ) ;
118
+ Assert . Throws < ArgumentException > ( ( ) => Path . ChangeExtension ( bad , "ok" ) ) ;
119
+ Assert . Throws < ArgumentException > ( ( ) => Path . Combine ( bad , "ok" ) ) ;
120
+ Assert . Throws < ArgumentException > ( ( ) => Path . Combine ( "ok" , "ok" , bad ) ) ;
121
+ Assert . Throws < ArgumentException > ( ( ) => Path . Combine ( "ok" , "ok" , bad , "ok" ) ) ;
122
+ Assert . Throws < ArgumentException > ( ( ) => Path . Combine ( bad , bad , bad , bad , bad ) ) ;
123
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetDirectoryName ( bad ) ) ;
124
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetExtension ( bad ) ) ;
125
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFileName ( bad ) ) ;
126
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFileNameWithoutExtension ( bad ) ) ;
127
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( bad ) ) ;
128
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetPathRoot ( bad ) ) ;
129
+ Assert . Throws < ArgumentException > ( ( ) => Path . IsPathRooted ( bad ) ) ;
130
+ } ) ;
88
131
}
89
132
90
133
[ Fact ]
@@ -106,6 +149,53 @@ public static void GetTempPath()
106
149
Assert . True ( Directory . Exists ( tmpPath ) ) ;
107
150
}
108
151
152
+ [ PlatformSpecific ( PlatformID . Windows ) ]
153
+ [ Theory ]
154
+ [ InlineData ( @"C:\Users\someuser\AppData\Local\Temp\" , @"C:\Users\someuser\AppData\Local\Temp" ) ]
155
+ [ InlineData ( @"C:\Users\someuser\AppData\Local\Temp\" , @"C:\Users\someuser\AppData\Local\Temp\" ) ]
156
+ [ InlineData ( @"C:\" , @"C:\" ) ]
157
+ [ InlineData ( @"C:\tmp\" , @"C:\tmp" ) ]
158
+ [ InlineData ( @"C:\tmp\" , @"C:\tmp\" ) ]
159
+ public static void GetTempPath_SetEnvVar_Windows ( string expected , string newTempPath )
160
+ {
161
+ GetTempPath_SetEnvVar ( "TMP" , expected , newTempPath ) ;
162
+ }
163
+
164
+ [ PlatformSpecific ( PlatformID . AnyUnix ) ]
165
+ [ Theory ]
166
+ [ InlineData ( "/tmp/" , "/tmp" ) ]
167
+ [ InlineData ( "/tmp/" , "/tmp/" ) ]
168
+ [ InlineData ( "/" , "/" ) ]
169
+ [ InlineData ( "/var/tmp/" , "/var/tmp" ) ]
170
+ [ InlineData ( "/var/tmp/" , "/var/tmp/" ) ]
171
+ [ InlineData ( "~/" , "~" ) ]
172
+ [ InlineData ( "~/" , "~/" ) ]
173
+ [ InlineData ( ".tmp/" , ".tmp" ) ]
174
+ [ InlineData ( "./tmp/" , "./tmp" ) ]
175
+ [ InlineData ( "/home/someuser/sometempdir/" , "/home/someuser/sometempdir/" ) ]
176
+ public static void GetTempPath_SetEnvVar_Unix ( string expected , string newTempPath )
177
+ {
178
+ GetTempPath_SetEnvVar ( "TMPDIR" , expected , newTempPath ) ;
179
+ }
180
+
181
+ private static void GetTempPath_SetEnvVar ( string envVar , string expected , string newTempPath )
182
+ {
183
+ string original = Path . GetTempPath ( ) ;
184
+ Assert . NotNull ( original ) ;
185
+ try
186
+ {
187
+ Environment . SetEnvironmentVariable ( envVar , newTempPath ) ;
188
+ Assert . Equal (
189
+ Path . GetFullPath ( expected ) ,
190
+ Path . GetFullPath ( Path . GetTempPath ( ) ) ) ;
191
+ }
192
+ finally
193
+ {
194
+ Environment . SetEnvironmentVariable ( envVar , null ) ;
195
+ Assert . Equal ( original , Path . GetTempPath ( ) ) ;
196
+ }
197
+ }
198
+
109
199
[ Fact ]
110
200
public static void GetTempFileName ( )
111
201
{
@@ -127,12 +217,106 @@ public static void GetTempFileName()
127
217
[ Fact ]
128
218
public static void GetFullPath ( )
129
219
{
220
+ // Basic invalid arg checks
130
221
Assert . Throws < ArgumentNullException > ( ( ) => Path . GetFullPath ( null ) ) ;
222
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( "" ) ) ;
223
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( "http://www.microsoft.com" ) ) ;
224
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( "file://www.microsoft.com" ) ) ;
131
225
226
+ // Basic expansions (e.g. self to self, period to self, normalization of lots of periods, etc.)
132
227
string curDir = Directory . GetCurrentDirectory ( ) ;
228
+ Assert . Equal ( curDir , Path . GetFullPath ( curDir ) ) ;
229
+ Assert . Equal ( curDir , Path . GetFullPath ( "." ) ) ;
133
230
Assert . Equal ( curDir , Path . GetFullPath ( Path . Combine ( curDir , "." , "." , "." , "." , "." ) ) ) ;
134
231
Assert . Equal ( curDir , Path . GetFullPath ( curDir + Path . DirectorySeparatorChar + Path . DirectorySeparatorChar + Path . DirectorySeparatorChar + "." ) ) ;
135
232
Assert . Equal ( curDir , Path . GetFullPath ( Path . Combine ( curDir , ".." , Path . GetFileName ( curDir ) , "." , ".." , Path . GetFileName ( curDir ) ) ) ) ;
233
+ Assert . Equal ( Path . GetPathRoot ( curDir ) , Path . GetFullPath ( Path . Combine ( Path . GetPathRoot ( curDir ) , "somedir" , ".." ) ) ) ;
234
+ Assert . Equal ( Path . GetPathRoot ( curDir ) , Path . GetFullPath ( Path . Combine ( Path . GetPathRoot ( curDir ) , "." ) ) ) ;
235
+
236
+ // Try out a long path that normalizes down to less than MaxPath
237
+ var longPath = new StringBuilder ( curDir ) ;
238
+ for ( int i = 0 ; i < 1000 ; i ++ )
239
+ longPath . Append ( Path . DirectorySeparatorChar ) . Append ( '.' ) ;
240
+ Assert . Equal ( curDir , Path . GetFullPath ( longPath . ToString ( ) ) ) ;
241
+
242
+ // Some Windows-only checks
243
+ if ( Interop . IsWindows )
244
+ {
245
+ // Try out a long path that normalizes down to more than MaxPath
246
+ for ( int i = 0 ; i < 500 ; i ++ )
247
+ longPath . Append ( Path . DirectorySeparatorChar ) . Append ( 'a' ) . Append ( Path . DirectorySeparatorChar ) . Append ( '.' ) ;
248
+ Assert . Throws < PathTooLongException > ( ( ) => Path . GetFullPath ( longPath . ToString ( ) ) ) ;
249
+
250
+ // alternate data streams aren't supported
251
+ Assert . Throws < NotSupportedException > ( ( ) => Path . GetFullPath ( @"C:\some\bad:path" ) ) ;
252
+ Assert . Throws < NotSupportedException > ( ( ) => Path . GetFullPath ( @"bad:path" ) ) ;
253
+
254
+ // Some Windows-specific bad paths
255
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( Path . DirectorySeparatorChar + ".. ." + Path . DirectorySeparatorChar ) ) ;
256
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( Path . DirectorySeparatorChar + ". ." + Path . DirectorySeparatorChar ) ) ;
257
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( Path . DirectorySeparatorChar + " ." + Path . DirectorySeparatorChar ) ) ;
258
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( "C:..." ) ) ;
259
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"C:...\somedir" ) ) ;
260
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"C :" ) ) ;
261
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"C :\somedir" ) ) ;
262
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"bad::$DATA" ) ) ;
263
+ Assert . Throws < PathTooLongException > ( ( ) => Path . GetFullPath ( @"C:\" + new string ( 'a' , 255 ) + @"\" ) ) ;
264
+
265
+ // Some Windows-specific strange but legal paths
266
+ Assert . Equal (
267
+ Path . GetFullPath ( curDir + Path . DirectorySeparatorChar ) ,
268
+ Path . GetFullPath ( curDir + Path . DirectorySeparatorChar + ". " + Path . DirectorySeparatorChar ) ) ;
269
+ Assert . Equal (
270
+ Path . GetFullPath ( Path . GetDirectoryName ( curDir ) + Path . DirectorySeparatorChar ) ,
271
+ Path . GetFullPath ( curDir + Path . DirectorySeparatorChar + "..." + Path . DirectorySeparatorChar ) ) ;
272
+ Assert . Equal (
273
+ Path . GetFullPath ( Path . GetDirectoryName ( curDir ) + Path . DirectorySeparatorChar ) ,
274
+ Path . GetFullPath ( curDir + Path . DirectorySeparatorChar + ".. " + Path . DirectorySeparatorChar ) ) ;
275
+
276
+ // Windows-specific UNC paths
277
+ Assert . Equal ( @"\\server\share" , Path . GetFullPath ( @"\\server\share" ) ) ;
278
+ Assert . Equal ( @"\\server\share" , Path . GetFullPath ( @" \\server\share" ) ) ;
279
+ Assert . Equal ( @"\\server\share\dir" , Path . GetFullPath ( @"\\server\share\dir" ) ) ;
280
+ Assert . Equal ( @"\\server\share" , Path . GetFullPath ( @"\\server\share\." ) ) ;
281
+ Assert . Equal ( @"\\server\share" , Path . GetFullPath ( @"\\server\share\.." ) ) ;
282
+ Assert . Equal ( @"\\server\share\" , Path . GetFullPath ( @"\\server\share\ " ) ) ;
283
+ Assert . Equal ( @"\\server\ share\" , Path . GetFullPath ( @"\\server\ share\" ) ) ;
284
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"\\" ) ) ;
285
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"\\server" ) ) ;
286
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"\\server\" ) ) ;
287
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"\\server\.." ) ) ;
288
+ Assert . Throws < ArgumentException > ( ( ) => Path . GetFullPath ( @"\\?\GLOBALROOT\" ) ) ;
289
+
290
+ // Windows short paths
291
+ string tempFilePath = Path . Combine ( Path . GetTempPath ( ) , Guid . NewGuid ( ) . ToString ( "N" ) + ".txt" ) ;
292
+ File . Create ( tempFilePath ) . Dispose ( ) ;
293
+ try
294
+ {
295
+ // Validate a short name can be expanded
296
+ var sb = new StringBuilder ( 260 ) ;
297
+ if ( GetShortPathName ( tempFilePath , sb , sb . Capacity ) > 0 ) // only proceed if we could successfully create the short name
298
+ {
299
+ Assert . Equal ( tempFilePath , Path . GetFullPath ( sb . ToString ( ) ) ) ;
300
+
301
+ // Validate case where short name doesn't expand to a real file
302
+ string invalidShortName = @"S:\DOESNT~1\USERNA~1.RED\LOCALS~1\Temp\bg3ylpzp" ;
303
+ Assert . Equal ( invalidShortName , Path . GetFullPath ( invalidShortName ) ) ;
304
+
305
+ // Same thing, but with a long path that normalizes down to a short enough one
306
+ var shortLongName = new StringBuilder ( invalidShortName ) ;
307
+ for ( int i = 0 ; i < 1000 ; i ++ )
308
+ shortLongName . Append ( Path . DirectorySeparatorChar ) . Append ( '.' ) ;
309
+ Assert . Equal ( invalidShortName , Path . GetFullPath ( shortLongName . ToString ( ) ) ) ;
310
+ }
311
+ }
312
+ finally
313
+ {
314
+ File . Delete ( tempFilePath ) ;
315
+ }
316
+ }
136
317
}
137
318
319
+ // Windows-only P/Invoke to create 8.3 short names from long names
320
+ [ DllImport ( "kernel32.dll" , CharSet = CharSet . Ansi ) ]
321
+ private static extern uint GetShortPathName ( string lpszLongPath , StringBuilder lpszShortPath , int cchBuffer ) ;
138
322
}
0 commit comments