Skip to content

Commit 8e479ba

Browse files
Copilotstephentoub
andcommitted
Refactor tests to use centralized test data and clarify Windows trailing space behavior
Co-authored-by: stephentoub <[email protected]>
1 parent 7012a70 commit 8e479ba

File tree

3 files changed

+88
-82
lines changed

3 files changed

+88
-82
lines changed

src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/Copy.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -498,10 +498,12 @@ public void UnixCopyWithEmbeddedControlCharacters(string sourceFileName, string
498498
[PlatformSpecific(TestPlatforms.Windows)]
499499
public void WindowsCopyWithTrailingSpacePeriod_ViaExtendedSyntax(string sourceFileName, string destFileName)
500500
{
501-
// Files with trailing spaces/periods require \\?\ syntax on Windows for creation.
502-
// However, enumeration APIs like Directory.GetFiles can find them and return their names,
503-
// but regular APIs like File.OpenRead will fail without \\?\ prefix.
504-
// See: https://learn.microsoft.com/windows/win32/fileio/naming-a-file#naming-conventions
501+
// On Windows, files with trailing spaces/periods must use \\?\ prefix for creation
502+
// because path normalization strips these characters. While enumeration APIs like
503+
// Directory.GetFiles can discover these files, direct string-based APIs (File.OpenRead,
504+
// File.Exists) will fail because the trailing characters get stripped during normalization.
505+
// Only FileInfo/DirectoryInfo objects from enumeration use EnsureExtendedPrefixIfNeeded
506+
// internally and can access these files. See TrimmedPaths.cs for comprehensive tests.
505507
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
506508
string sourcePath = Path.Combine(testDir.FullName, sourceFileName);
507509
string destPath = Path.Combine(testDir.FullName, destFileName);

src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/Create.cs

Lines changed: 10 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,8 @@ public void WindowsAlternateDataStream_OnExisting(string streamName)
341341
}
342342
}
343343

344-
[Theory]
345-
[InlineData(" leading")]
346-
[InlineData(" leading")]
347-
[InlineData(" leading")]
348-
public void LeadingSpace(string fileName)
344+
[Theory, MemberData(nameof(TestData.ValidFileNames), MemberType = typeof(TestData))]
345+
public void CreateWithProblematicNames(string fileName)
349346
{
350347
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
351348
string filePath = Path.Combine(testDir.FullName, fileName);
@@ -355,42 +352,9 @@ public void LeadingSpace(string fileName)
355352
}
356353
}
357354

358-
[Theory]
359-
[InlineData(".leading")]
360-
[InlineData("..leading")]
361-
[InlineData("...leading")]
362-
public void LeadingDot(string fileName)
363-
{
364-
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
365-
string filePath = Path.Combine(testDir.FullName, fileName);
366-
using (Create(filePath))
367-
{
368-
Assert.True(File.Exists(filePath));
369-
}
370-
}
371-
372-
[Theory]
373-
[InlineData("-")]
374-
[InlineData("--")]
375-
[InlineData("-filename")]
376-
[InlineData("--filename")]
377-
public void DashPrefixedNames(string fileName)
378-
{
379-
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
380-
string filePath = Path.Combine(testDir.FullName, fileName);
381-
using (Create(filePath))
382-
{
383-
Assert.True(File.Exists(filePath));
384-
}
385-
}
386-
387-
[Theory]
388-
[InlineData("file\tname")]
389-
[InlineData("file\rname")]
390-
[InlineData("file\vname")]
391-
[InlineData("file\fname")]
355+
[Theory, MemberData(nameof(TestData.UnixOnlyFileNames), MemberType = typeof(TestData))]
392356
[PlatformSpecific(TestPlatforms.AnyUnix)]
393-
public void UnixEmbeddedControlCharacters(string fileName)
357+
public void UnixCreateWithControlCharacters(string fileName)
394358
{
395359
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
396360
string filePath = Path.Combine(testDir.FullName, fileName);
@@ -401,16 +365,13 @@ public void UnixEmbeddedControlCharacters(string fileName)
401365
}
402366

403367
[ConditionalTheory(nameof(UsingNewNormalization))]
404-
[InlineData("trailing ")]
405-
[InlineData("trailing ")]
406-
[InlineData("trailing.")]
407-
[InlineData("trailing..")]
408-
[InlineData("trailing .")]
409-
[InlineData("trailing. ")]
368+
[MemberData(nameof(TestData.WindowsTrailingProblematicFileNames), MemberType = typeof(TestData))]
410369
[PlatformSpecific(TestPlatforms.Windows)]
411-
public void WindowsTrailingSpacePeriod_CreateViaExtendedSyntax(string fileName)
370+
public void WindowsCreateWithTrailingSpacePeriod(string fileName)
412371
{
413-
// Files with trailing spaces/periods require \\?\ syntax on Windows
372+
// On Windows, files with trailing spaces/periods must be created using \\?\ prefix.
373+
// This is by design - Windows path normalization strips these characters unless
374+
// the extended path syntax is used. See TrimmedPaths.cs for more detailed tests.
414375
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
415376
string filePath = Path.Combine(testDir.FullName, fileName);
416377
string extendedPath = @"\\?\" + filePath;
@@ -420,40 +381,11 @@ public void WindowsTrailingSpacePeriod_CreateViaExtendedSyntax(string fileName)
420381
Assert.True(File.Exists(extendedPath));
421382
}
422383

423-
// Verify we can find it via enumeration
384+
// Verify the file can be found via enumeration
424385
string[] files = Directory.GetFiles(testDir.FullName);
425386
Assert.Contains(files, f => Path.GetFileName(f) == fileName);
426387
}
427388

428-
[Theory]
429-
[InlineData("name with spaces")]
430-
[InlineData("name with multiple spaces")]
431-
[InlineData("name.with.periods")]
432-
[InlineData("name with spaces.txt")]
433-
public void EmbeddedSpacesPeriods(string fileName)
434-
{
435-
// Embedded spaces and periods should work fine on all platforms
436-
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
437-
string filePath = Path.Combine(testDir.FullName, fileName);
438-
using (Create(filePath))
439-
{
440-
Assert.True(File.Exists(filePath));
441-
}
442-
}
443-
444-
[Theory]
445-
[InlineData("name\twith\ttabs")]
446-
[PlatformSpecific(TestPlatforms.AnyUnix)]
447-
public void UnixEmbeddedTabs(string fileName)
448-
{
449-
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
450-
string filePath = Path.Combine(testDir.FullName, fileName);
451-
using (Create(filePath))
452-
{
453-
Assert.True(File.Exists(filePath));
454-
}
455-
}
456-
457389
#endregion
458390
}
459391

src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/TestData.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,76 @@ public static TheoryData<char> TrailingCharacters
9191
return data;
9292
}
9393
}
94+
95+
/// <summary>
96+
/// Filenames with problematic but valid characters that work on all platforms.
97+
/// These test scenarios from: https://www.dwheeler.com/essays/fixing-unix-linux-filenames.html
98+
/// </summary>
99+
public static TheoryData<string> ValidFileNames
100+
{
101+
get
102+
{
103+
TheoryData<string> data = new TheoryData<string>
104+
{
105+
// Leading spaces
106+
" leading",
107+
" leading",
108+
" leading",
109+
// Leading dots
110+
".leading",
111+
"..leading",
112+
"...leading",
113+
// Dash-prefixed names
114+
"-",
115+
"--",
116+
"-filename",
117+
"--filename",
118+
// Embedded spaces and periods
119+
"name with spaces",
120+
"name with multiple spaces",
121+
"name.with.periods",
122+
"name with spaces.txt"
123+
};
124+
125+
return data;
126+
}
127+
}
128+
129+
/// <summary>
130+
/// Filenames with control characters that are only valid on Unix.
131+
/// Windows reserves control characters 0-31 as invalid.
132+
/// </summary>
133+
public static TheoryData<string> UnixOnlyFileNames
134+
{
135+
get
136+
{
137+
return new TheoryData<string>
138+
{
139+
"file\tname", // tab
140+
"file\rname", // carriage return
141+
"file\vname", // vertical tab
142+
"file\fname" // form feed
143+
};
144+
}
145+
}
146+
147+
/// <summary>
148+
/// Filenames with trailing spaces or periods. On Windows, these require \\?\ prefix for creation
149+
/// but can be enumerated. Direct string-based APIs will have the trailing characters stripped.
150+
/// </summary>
151+
public static TheoryData<string> WindowsTrailingProblematicFileNames
152+
{
153+
get
154+
{
155+
return new TheoryData<string>
156+
{
157+
"trailing ",
158+
"trailing ",
159+
"trailing.",
160+
"trailing..",
161+
"trailing .",
162+
"trailing. "
163+
};
164+
}
165+
}
94166
}

0 commit comments

Comments
 (0)