-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
EnumerableTests.cs
163 lines (140 loc) · 6.19 KB
/
EnumerableTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.IO.Tests
{
public class EnumerableTests : FileSystemTest
{
[Fact]
// we don't guarantee thread safety of enumerators in general, but on Windows we
// currently are thread safe, and this test will help ensure that if we change that
// it's a conscious decision. Discussed in https://github.com/dotnet/runtime/issues/24295.
[PlatformSpecific(TestPlatforms.Windows)]
public void FileEnumeratorIsThreadSafe()
{
string directory = Directory.CreateDirectory(GetTestFilePath()).FullName;
for (int i = 0; i < 100; i++)
File.Create(Path.Combine(directory, GetTestFileName())).Dispose();
// We are really only trying to make sure we don't terminate the process.
// Throwing IOException at this point to try and flush out other problems
// like bad handles. Can narrow the throw if this isn't reliable.
try
{
new ThreadSafeRepro().Execute(directory);
}
catch (Exception e) when (!(e is IOException))
{
}
}
[Fact]
public void EnumerateDirectories_NonBreakingSpace()
{
DirectoryInfo rootDirectory = Directory.CreateDirectory(GetTestFilePath());
DirectoryInfo subDirectory1 = rootDirectory.CreateSubdirectory("\u00A0");
DirectoryInfo subDirectory2 = subDirectory1.CreateSubdirectory(GetTestFileName());
FSAssert.EqualWhenOrdered(new string[] { subDirectory1.FullName, subDirectory2.FullName }, Directory.EnumerateDirectories(rootDirectory.FullName, string.Empty, SearchOption.AllDirectories));
}
[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
public void EnumerateDirectories_TrailingDot()
{
string prefix = @"\\?\";
string tempPath = GetTestFilePath();
string fileName = "Test.txt";
string[] dirPaths = {
Path.Join(prefix, tempPath, "Test"),
Path.Join(prefix, tempPath, "TestDot."),
Path.Join(prefix, tempPath, "TestDotDot..")
};
// Create directories and their files using "\\?\C:\" paths
foreach (string dirPath in dirPaths)
{
if (Directory.Exists(dirPath))
{
Directory.Delete(dirPath, recursive: true);
}
Directory.CreateDirectory(dirPath);
// Directory.Exists should work with directories containing trailing dots and prefixed with \\?\
Assert.True(Directory.Exists(dirPath));
string filePath = Path.Join(dirPath, fileName);
using FileStream fs = File.Create(filePath);
// File.Exists should work with directories containing trailing dots and prefixed with \\?\
Assert.True(File.Exists(filePath));
}
try
{
// Enumerate directories and their files using "C:\" paths
DirectoryInfo sourceInfo = new DirectoryInfo(tempPath);
foreach (DirectoryInfo dirInfo in sourceInfo.EnumerateDirectories("*", SearchOption.AllDirectories))
{
// DirectoryInfo.Exists should work with or without \\?\ for folders with trailing dots
Assert.True(dirInfo.Exists);
if (dirInfo.FullName.EndsWith("."))
{
// Directory.Exists is not expected to work with directories containing trailing dots and not prefixed with \\?\
Assert.False(Directory.Exists(dirInfo.FullName));
}
foreach (FileInfo fileInfo in dirInfo.EnumerateFiles("*.*", SearchOption.TopDirectoryOnly))
{
// FileInfo.Exists should work with or without \\?\ for folders with trailing dots
Assert.True(fileInfo.Exists);
if (fileInfo.Directory.FullName.EndsWith("."))
{
// File.Exists is not expected to work with directories containing trailing dots and not prefixed with \\?\
Assert.False(File.Exists(fileInfo.FullName));
}
}
}
}
finally
{
foreach (string dirPath in dirPaths)
{
Directory.Delete(dirPath, recursive: true);
}
}
}
class ThreadSafeRepro
{
volatile IEnumerator<string> _enumerator;
void Enumerate(IEnumerator<string> s)
{
while (s.MoveNext())
{ }
s.Dispose();
}
public void Execute(string directory)
{
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
void Work()
{
do
{
IEnumerator<string> x = _enumerator;
if (x != null)
Enumerate(x);
} while (!token.IsCancellationRequested);
}
Task taskOne = Task.Run(action: Work);
Task taskTwo = Task.Run(action: Work);
try
{
for (int i = 0; i < 1000; i++)
{
_enumerator = Directory.EnumerateFiles(directory).GetEnumerator();
Enumerate(_enumerator);
}
}
finally
{
source.Cancel();
Task.WaitAll(taskOne, taskTwo);
}
}
}
}
}