Skip to content

Commit 8573d4b

Browse files
authored
fix: cancel async methods when requested (#658)
Fixes #647
1 parent e34dd9b commit 8573d4b

12 files changed

Lines changed: 169 additions & 52 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "C# (.NET Core)",
3+
"image": "mcr.microsoft.com/vscode/devcontainers/dotnetcore:3.1",
4+
"settings": {
5+
"terminal.integrated.shell.linux": "/bin/bash"
6+
},
7+
"extensions": [
8+
"ms-dotnettools.csharp"
9+
],
10+
"postCreateCommand": "dotnet restore"
11+
}

.github/stale.yml

Lines changed: 0 additions & 13 deletions
This file was deleted.

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
3-
"version": "3.1.302",
3+
"version": "3.1.300",
44
"rollForward": "latestMinor"
55
}
66
}

src/System.IO.Abstractions.TestingHelpers/MockFile.Async.cs

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,93 +9,83 @@ namespace System.IO.Abstractions.TestingHelpers
99
{
1010
partial class MockFile
1111
{
12-
public override Task AppendAllLinesAsync(string path, IEnumerable<string> contents, CancellationToken cancellationToken = default(CancellationToken))
13-
{
14-
AppendAllLines(path, contents);
15-
return Task.CompletedTask;
16-
}
12+
public override Task AppendAllLinesAsync(string path, IEnumerable<string> contents, CancellationToken cancellationToken = default(CancellationToken)) =>
13+
AppendAllLinesAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);
1714

1815
public override Task AppendAllLinesAsync(string path, IEnumerable<string> contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
1916
{
17+
cancellationToken.ThrowIfCancellationRequested();
2018
AppendAllLines(path, contents, encoding);
2119
return Task.CompletedTask;
2220
}
2321

24-
public override Task AppendAllTextAsync(string path, string contents, CancellationToken cancellationToken = default(CancellationToken))
25-
{
26-
AppendAllText(path, contents);
27-
return Task.CompletedTask;
28-
}
22+
public override Task AppendAllTextAsync(string path, string contents, CancellationToken cancellationToken = default(CancellationToken)) =>
23+
AppendAllTextAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);
2924

3025
public override Task AppendAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
3126
{
27+
cancellationToken.ThrowIfCancellationRequested();
3228
AppendAllText(path, contents, encoding);
3329
return Task.CompletedTask;
3430
}
3531

3632
public override Task<byte[]> ReadAllBytesAsync(string path, CancellationToken cancellationToken = default(CancellationToken))
3733
{
34+
cancellationToken.ThrowIfCancellationRequested();
3835
return Task.FromResult(ReadAllBytes(path));
3936
}
4037

41-
public override Task<string[]> ReadAllLinesAsync(string path, CancellationToken cancellationToken = default(CancellationToken))
42-
{
43-
return Task.FromResult(ReadAllLines(path));
44-
}
38+
public override Task<string[]> ReadAllLinesAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) =>
39+
ReadAllLinesAsync(path, MockFileData.DefaultEncoding, cancellationToken);
4540

4641
public override Task<string[]> ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
4742
{
43+
cancellationToken.ThrowIfCancellationRequested();
4844
return Task.FromResult(ReadAllLines(path, encoding));
4945
}
5046

51-
public override Task<string> ReadAllTextAsync(string path, CancellationToken cancellationToken)
52-
{
53-
return Task.FromResult(ReadAllText(path));
54-
}
47+
public override Task<string> ReadAllTextAsync(string path, CancellationToken cancellationToken) =>
48+
ReadAllTextAsync(path, MockFileData.DefaultEncoding, cancellationToken);
5549

5650
public override Task<string> ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken)
5751
{
52+
cancellationToken.ThrowIfCancellationRequested();
5853
return Task.FromResult(ReadAllText(path, encoding));
5954
}
6055

6156
public override Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken)
6257
{
58+
cancellationToken.ThrowIfCancellationRequested();
6359
WriteAllBytes(path, bytes);
6460
return Task.CompletedTask;
6561
}
6662

67-
public override Task WriteAllLinesAsync(string path, IEnumerable<string> contents, CancellationToken cancellationToken)
68-
{
69-
WriteAllLines(path, contents);
70-
return Task.CompletedTask;
71-
}
63+
public override Task WriteAllLinesAsync(string path, IEnumerable<string> contents, CancellationToken cancellationToken) =>
64+
WriteAllLinesAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);
7265

7366
public override Task WriteAllLinesAsync(string path, IEnumerable<string> contents, Encoding encoding, CancellationToken cancellationToken)
7467
{
68+
cancellationToken.ThrowIfCancellationRequested();
7569
WriteAllLines(path, contents, encoding);
7670
return Task.CompletedTask;
7771
}
7872

79-
public override Task WriteAllLinesAsync(string path, string[] contents, CancellationToken cancellationToken)
80-
{
81-
WriteAllLines(path, contents);
82-
return Task.CompletedTask;
83-
}
73+
public override Task WriteAllLinesAsync(string path, string[] contents, CancellationToken cancellationToken) =>
74+
WriteAllLinesAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);
8475

8576
public override Task WriteAllLinesAsync(string path, string[] contents, Encoding encoding, CancellationToken cancellationToken)
8677
{
78+
cancellationToken.ThrowIfCancellationRequested();
8779
WriteAllLines(path, contents, encoding);
8880
return Task.CompletedTask;
8981
}
9082

91-
public override Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken)
92-
{
93-
WriteAllText(path, contents);
94-
return Task.CompletedTask;
95-
}
83+
public override Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken) =>
84+
WriteAllTextAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);
9685

9786
public override Task WriteAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken)
9887
{
88+
cancellationToken.ThrowIfCancellationRequested();
9989
WriteAllText(path, contents, encoding);
10090
return Task.CompletedTask;
10191
}

src/System.IO.Abstractions.TestingHelpers/MockFile.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,18 @@ public override void AppendAllLines(string path, IEnumerable<string> contents, E
4141

4242
public override void AppendAllText(string path, string contents)
4343
{
44-
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");
45-
4644
AppendAllText(path, contents, MockFileData.DefaultEncoding);
4745
}
4846

4947
public override void AppendAllText(string path, string contents, Encoding encoding)
5048
{
49+
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");
50+
5151
if (encoding == null)
5252
{
5353
throw new ArgumentNullException(nameof(encoding));
5454
}
5555

56-
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");
57-
5856
if (!mockFileDataAccessor.FileExists(path))
5957
{
6058
VerifyDirectoryExists(path);

tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileAppendAllLinesTests.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using NUnit.Framework;
33
using XFS = System.IO.Abstractions.TestingHelpers.MockUnixSupport;
44
using System.Threading.Tasks;
5+
using System.Threading;
56

67
namespace System.IO.Abstractions.TestingHelpers.Tests
78
{
@@ -159,7 +160,30 @@ public async Task MockFile_AppendAllLinesAsync_ShouldPersistNewLinesToNewFile()
159160
// Assert
160161
Assert.AreEqual(
161162
"line 1" + Environment.NewLine + "line 2" + Environment.NewLine + "line 3" + Environment.NewLine,
162-
file.ReadAllText(path));
163+
file.ReadAllText(path)
164+
);
165+
}
166+
167+
[Test]
168+
public void MockFile_AppendAllLinesAsync_ShouldThrowOperationCanceledExceptionIfCancelled()
169+
{
170+
// Arrange
171+
const string path = "test.txt";
172+
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
173+
{
174+
{ path, new MockFileData("line 1") }
175+
});
176+
177+
// Act
178+
Assert.ThrowsAsync<OperationCanceledException>(async () =>
179+
await fileSystem.File.AppendAllLinesAsync(
180+
path,
181+
new[] { "line 2" },
182+
new CancellationToken(canceled: true))
183+
);
184+
185+
// Assert
186+
Assert.AreEqual("line 1", fileSystem.File.ReadAllText(path));
163187
}
164188

165189
[Test]

tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileAppendAllTextTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace System.IO.Abstractions.TestingHelpers.Tests
1010
using XFS = MockUnixSupport;
1111

1212
using System.Threading.Tasks;
13+
using System.Threading;
1314

1415
public class MockFileAppendAllTextTests
1516
{
@@ -178,6 +179,28 @@ public async Task MockFile_AppendAllTextAsync_ShouldPersistNewText()
178179
file.ReadAllText(path));
179180
}
180181

182+
[Test]
183+
public void MockFile_AppendAllTextAsync_ShouldThrowOperationCanceledExceptionIfCancelled()
184+
{
185+
// Arrange
186+
const string path = "test.txt";
187+
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
188+
{
189+
{ path, new MockFileData("line 1") }
190+
});
191+
192+
// Act
193+
Assert.ThrowsAsync<OperationCanceledException>(async () =>
194+
await fileSystem.File.AppendAllTextAsync(
195+
path,
196+
"line 2",
197+
new CancellationToken(canceled: true))
198+
);
199+
200+
// Assert
201+
Assert.AreEqual("line 1", fileSystem.File.ReadAllText(path));
202+
}
203+
181204
[Test]
182205
public async Task MockFile_AppendAllTextAsync_ShouldPersistNewTextWithDifferentEncoding()
183206
{

tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileReadAllBytesTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using NUnit.Framework;
33
using XFS = System.IO.Abstractions.TestingHelpers.MockUnixSupport;
44
using System.Threading.Tasks;
5+
using System.Threading;
56

67
namespace System.IO.Abstractions.TestingHelpers.Tests
78
{
@@ -104,6 +105,17 @@ public void MockFile_ReadAllBytesAsync_ShouldThrowFileNotFoundExceptionIfFileDoe
104105
Assert.ThrowsAsync<FileNotFoundException>(action);
105106
}
106107

108+
[Test]
109+
public void MockFile_ReadAllBytesAsync_ShouldThrowOperationCanceledExceptionIfCanceled()
110+
{
111+
var fileSystem = new MockFileSystem();
112+
113+
AsyncTestDelegate action = async () =>
114+
await fileSystem.File.ReadAllBytesAsync(@"C:\a.txt", new CancellationToken(canceled: true));
115+
116+
Assert.ThrowsAsync<OperationCanceledException>(action);
117+
}
118+
107119
[Test]
108120
public async Task MockFile_ReadAllBytesAsync_ShouldTolerateAltDirectorySeparatorInPath()
109121
{

tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileReadAllLinesTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace System.IO.Abstractions.TestingHelpers.Tests
99
using XFS = MockUnixSupport;
1010

1111
using System.Threading.Tasks;
12+
using System.Threading;
1213

1314
public class MockFileReadAllLinesTests
1415
{
@@ -130,6 +131,17 @@ public async Task MockFile_ReadAllLinesAsync_ShouldReturnOriginalDataWithCustomE
130131
result);
131132
}
132133

134+
[Test]
135+
public void MockFile_ReadAllLinesAsync_ShouldThrowOperationCanceledExceptionIfCanceled()
136+
{
137+
var fileSystem = new MockFileSystem();
138+
139+
AsyncTestDelegate action = async () =>
140+
await fileSystem.File.ReadAllLinesAsync(@"C:\a.txt", new CancellationToken(canceled: true));
141+
142+
Assert.ThrowsAsync<OperationCanceledException>(action);
143+
}
144+
133145
[Test]
134146
public void MockFile_ReadAllLinesAsync_NotExistingFile_ThrowsCorrectFileNotFoundException()
135147
{

tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileWriteAllBytesTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using NUnit.Framework;
33
using XFS = System.IO.Abstractions.TestingHelpers.MockUnixSupport;
44
using System.Threading.Tasks;
5+
using System.Threading;
56

67
namespace System.IO.Abstractions.TestingHelpers.Tests
78
{
@@ -95,6 +96,25 @@ public void MockFile_WriteAllBytesAsync_ShouldThrowDirectoryNotFoundExceptionIfP
9596
Assert.ThrowsAsync<DirectoryNotFoundException>(action);
9697
}
9798

99+
[Test]
100+
public void MockFile_WriteAllTextAsync_ShouldThrowOperationCanceledExceptionIfCancelled()
101+
{
102+
// Arrange
103+
const string path = "test.txt";
104+
var fileSystem = new MockFileSystem();
105+
106+
// Act
107+
Assert.ThrowsAsync<OperationCanceledException>(async () =>
108+
await fileSystem.File.WriteAllTextAsync(
109+
path,
110+
"content",
111+
new CancellationToken(canceled: true))
112+
);
113+
114+
// Assert
115+
Assert.IsFalse(fileSystem.File.Exists(path));
116+
}
117+
98118
[Test]
99119
public async Task MockFile_WriteAllBytesAsync_ShouldWriteDataToMemoryFileSystem()
100120
{

0 commit comments

Comments
 (0)