|
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
#pragma warning disable CA1305 // Specify IFormatProvider in string.Format
namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
public class PreferStreamReadAsyncMemoryOverloadsTest : PreferStreamAsyncMemoryOverloadsTestBase
{
#region C# - No diagnostic
[Fact]
public Task CS_Analyzer_NoDiagnostic_ReadAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System.IO;
class C
{
public void M()
{
using (FileStream s = File.Open(""file.txt"", FileMode.Open))
{
byte[] buffer = new byte[s.Length];
s.Read(buffer, 0, (int)s.Length);
}
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_ReadAsync_ByteMemoryAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = new FileStream(""path.txt"", FileMode.Create))
{
byte[] buffer = new byte[s.Length];
Memory<byte> memory = new Memory<byte>(buffer);
await s.ReadAsync(memory, new CancellationToken()).ConfigureAwait(false);
}
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_ReadAsync_AsMemoryAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = File.Open(""file.txt"", FileMode.Open))
{
byte[] buffer = new byte[s.Length];
await s.ReadAsync(buffer.AsMemory(), new CancellationToken());
}
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_NoAwait_SaveAsTaskAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class C
{
public void M()
{
using (FileStream s = File.Open(""file.txt"", FileMode.Open))
{
byte[] buffer = new byte[s.Length];
Task t = s.ReadAsync(buffer, 0, (int)s.Length);
}
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_FileStream_NoAwait_ReturnMethodAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class C
{
public Task M(FileStream s, byte[] buffer)
{
return s.ReadAsync(buffer, 0, (int)s.Length);
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_Stream_NoAwait_VoidMethodAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class C
{
public void M(Stream s, byte[] buffer)
{
s.ReadAsync(buffer, 0, 1);
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_Stream_NoAwait_VoidMethod_InvokeGetBufferMethodAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class C
{
public byte[] GetBuffer()
{
return new byte[] { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
}
public void M(Stream s)
{
s.ReadAsync(GetBuffer(), 0, 1);
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_NoAwait_ExpressionBodyMethodAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class C
{
public Task M(FileStream s, byte[] buffer) => s.ReadAsync(buffer, 0, (int)s.Length);
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_ContinueWith_ConfigureAwaitAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = File.Open(""file.txt"", FileMode.Open))
{
byte[] buffer = new byte[s.Length];
await s.ReadAsync(buffer, 0, (int)s.Length).ContinueWith(c => {}).ConfigureAwait(false);
}
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_ContinueWith_ContinueWith_ConfigureAwaitAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = File.Open(""file.txt"", FileMode.Open))
{
byte[] buffer = new byte[s.Length];
await s.ReadAsync(buffer, 0, (int)s.Length).ContinueWith(c => {}).ContinueWith(c => {}).ConfigureAwait(false);
}
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_AutoCastedToMemoryAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = File.Open(""path.txt"", FileMode.Open))
{
byte[] buffer = new byte[s.Length];
await s.ReadAsync(buffer);
}
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_AutoCastedToMemory_CancellationTokenAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = File.Open(""path.txt"", FileMode.Open))
{
byte[] buffer = new byte[s.Length];
await s.ReadAsync(buffer, new CancellationToken());
}
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_AwaitInvocationOutsideStreamInvocationAsync()
{
return CSharpVerifyAnalyzerAsync(@"
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class C
{
public async void M()
{
using (FileStream s = new FileStream(""file.txt"", FileMode.Create))
{
byte[] buffer = new byte[s.Length];
await PrintTotalBytesWrittenAsync(s.ReadAsync(buffer, 0, buffer.Length)).ConfigureAwait(false);
}
}
private static async Task PrintTotalBytesWrittenAsync(Task<int> readAsyncTask)
{
Console.WriteLine(await readAsyncTask.ConfigureAwait(false));
}
}
");
}
[Fact]
public Task CS_Analyzer_NoDiagnostic_UnsupportedVersionAsync()
{
return CSharpVerifyAnalyzerForUnsupportedVersionAsync(@"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = File.Open(""file.txt"", FileMode.Open))
{
byte[] buffer = new byte[s.Length];
await s.ReadAsync(buffer, 0, (int)s.Length);
}
}
}
");
}
#endregion
#region VB - No diagnostic
[Fact]
public Task VB_Analyzer_NoDiagnostic_ReadAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System.IO
Class C
Public Sub M()
Using s As FileStream = File.Open(""file.txt"", FileMode.Open)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
s.Read(buffer, 0, s.Length)
End Using
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_ReadAsync_ByteMemoryAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) {}
Dim memory As Memory(Of Byte) = New Memory(Of Byte)(buffer)
Await s.ReadAsync(memory, New CancellationToken()).ConfigureAwait(False)
End Using
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_ReadAsync_AsMemoryAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = File.Open(""file.txt"", FileMode.Open)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await s.ReadAsync(buffer.AsMemory(), New CancellationToken())
End Using
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_NoAwait_SaveAsTaskAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Class C
Public Sub M()
Using s As FileStream = File.Open(""file.txt"", FileMode.Open)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Dim t As Task = s.ReadAsync(buffer, 0, CInt(s.Length))
End Using
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_FileStream_NoAwait_ReturnMethodAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Friend Class C
Public Function M(ByVal s As FileStream, ByVal buffer As Byte()) As Task
Return s.ReadAsync(buffer, 0, s.Length)
End Function
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_Stream_NoAwait_VoidMethodAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Class C
Public Sub M(ByVal s As Stream, ByVal buffer As Byte())
s.ReadAsync(buffer, 0, 1)
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_Stream_NoAwait_VoidMethod_InvokeGetBufferMethodAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Class C
Public Function GetBuffer() As Byte()
Return New Byte() {&HBA, &H5E, &HBA, &H11, &HF0, &H07, &HBA, &H11}
End Function
Public Sub M(ByVal s As Stream)
s.ReadAsync(GetBuffer(), 0, 1)
End Sub
End Class
");
}
// The method VB_Analyzer_NoDiagnostic_NoAwait_ExpressionBodyMethod()
// is skipped because VB does not support expression bodies for methods
[Fact]
public Task VB_Analyzer_NoDiagnostic_ContinueWith_ConfigureAwaitAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = File.Open(""file.txt"", FileMode.Open)
Dim buffer As Byte() = New Byte(s.Length - 1) {}
Await s.ReadAsync(buffer, 0, s.Length).ContinueWith(Sub(c)
End Sub).ConfigureAwait(False)
End Using
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_ContinueWith_ContinueWith_ConfigureAwaitAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = File.Open(""file.txt"", FileMode.Open)
Dim buffer As Byte() = New Byte(s.Length - 1) {}
Await s.ReadAsync(buffer, 0, s.Length).ContinueWith(Sub(c)
End Sub).ContinueWith(Sub(c)
End Sub).ConfigureAwait(False)
End Using
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_AutoCastedToMemoryAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = File.Open(""path.txt"", FileMode.Open)
Dim buffer As Byte() = New Byte(s.Length - 1) {}
Await s.ReadAsync(buffer)
End Using
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_AutoCastedToMemory_CancellationTokenAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = File.Open(""path.txt"", FileMode.Open)
Dim buffer As Byte() = New Byte(s.Length - 1) {}
Await s.ReadAsync(buffer, New CancellationToken())
End Using
End Sub
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_AwaitInvocationOutsideStreamInvocationAsync()
{
return VisualBasicVerifyAnalyzerAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""file.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await PrintTotalBytesWrittenAsync(s.ReadAsync(buffer, 0, buffer.Length)).ConfigureAwait(False)
End Using
End Sub
Private Shared Async Function PrintTotalBytesWrittenAsync(ByVal readAsyncTask As Task(Of Integer)) As Task
Console.WriteLine(Await readAsyncTask.ConfigureAwait(False))
End Function
End Class
");
}
[Fact]
public Task VB_Analyzer_NoDiagnostic_UnsupportedVersionAsync()
{
return VisualBasicVerifyAnalyzerForUnsupportedVersionAsync(@"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = File.Open(""file.txt"", FileMode.Open)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await s.ReadAsync(buffer, 0, s.Length)
End Using
End Sub
End Class
");
}
#endregion
#region C# - Diagnostic
private const string _sourceCSharp = @"
using System;
using System.IO;
using System.Threading;
class C
{{
public async void M()
{{
using (FileStream s = File.Open(""path.txt"", FileMode.Open))
{{
{0}
await s.ReadAsync({1}){2};
}}
}}
}}
";
public static IEnumerable<object[]> CSharpInlineByteArrayTestData()
{
yield return new object[] { "new byte[s.Length], 0, (int)s.Length",
"(new byte[s.Length]).AsMemory(0, (int)s.Length)" };
yield return new object[] { "new byte[s.Length], 0, (int)s.Length, new CancellationToken()",
"(new byte[s.Length]).AsMemory(0, (int)s.Length), new CancellationToken()" };
}
[WindowsOnlyFact] // https://github.com/dotnet/roslyn/issues/65081
public Task CS_Fixer_Diagnostic_EnsureSystemNamespaceAutoAddedAsync()
{
string originalCode = @"
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = new FileStream(""path.txt"", FileMode.Create))
{
byte[] buffer = new byte[s.Length];
await s.ReadAsync(new byte[s.Length], 0, (int)s.Length);
}
}
}";
string fixedCode = @"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = new FileStream(""path.txt"", FileMode.Create))
{
byte[] buffer = new byte[s.Length];
await s.ReadAsync((new byte[s.Length]).AsMemory(0, (int)s.Length));
}
}
}";
return CSharpVerifyExpectedCodeFixDiagnosticsAsync(originalCode, fixedCode, GetCSharpResult(11, 19, 11, 68));
}
[Theory]
[MemberData(nameof(UnnamedArgumentsFullBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsFullBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsWithCancellationTokenFullBufferTestData))]
[MemberData(nameof(CSharpUnnamedArgumentsPartialBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsPartialBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsWithCancellationTokenPartialBufferTestData))]
public Task CS_Fixer_Diagnostic_ArgumentNamingAsync(string originalArgs, string fixedArgs) =>
CSharpVerifyCodeFixAsync(originalArgs, fixedArgs, isEmptyByteDeclaration: false, isEmptyConfigureAwait: false);
[Theory]
[MemberData(nameof(UnnamedArgumentsFullBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsFullBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsWithCancellationTokenFullBufferTestData))]
[MemberData(nameof(CSharpUnnamedArgumentsPartialBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsPartialBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsWithCancellationTokenPartialBufferTestData))]
public Task CS_Fixer_Diagnostic_ArgumentNaming_WithConfigureAwaitAsync(string originalArgs, string fixedArgs) =>
CSharpVerifyCodeFixAsync(originalArgs, fixedArgs, isEmptyByteDeclaration: false, isEmptyConfigureAwait: true);
[Theory]
[MemberData(nameof(CSharpInlineByteArrayTestData))]
public Task CS_Fixer_Diagnostic_InlineByteArrayAsync(string originalArgs, string fixedArgs) =>
CSharpVerifyCodeFixAsync(originalArgs, fixedArgs, isEmptyByteDeclaration: true, isEmptyConfigureAwait: false);
[Theory]
[MemberData(nameof(CSharpInlineByteArrayTestData))]
public Task CS_Fixer_Diagnostic_InlineByteArray_WithConfigureAwaitAsync(string originalArgs, string fixedArgs) =>
CSharpVerifyCodeFixAsync(originalArgs, fixedArgs, isEmptyByteDeclaration: true, isEmptyConfigureAwait: true);
[Theory]
[MemberData(nameof(UnnamedArgumentsFullBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsFullBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsWithCancellationTokenFullBufferTestData))]
[MemberData(nameof(CSharpUnnamedArgumentsPartialBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsPartialBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsWithCancellationTokenPartialBufferTestData))]
public Task CS_Fixer_Diagnostic_AwaitInvocationPassedAsArgumentAsync(string originalArgs, string fixedArgs) =>
CS_Fixer_Diagnostic_AwaitInvocationPassedAsArgument_InternalAsync(originalArgs, fixedArgs, isEmptyConfigureAwait: true);
[Theory]
[MemberData(nameof(UnnamedArgumentsFullBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsFullBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsWithCancellationTokenFullBufferTestData))]
[MemberData(nameof(CSharpUnnamedArgumentsPartialBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsPartialBufferTestData))]
[MemberData(nameof(CSharpNamedArgumentsWithCancellationTokenPartialBufferTestData))]
public Task CS_Fixer_Diagnostic_AwaitInvocationPassedAsArgument_WithConfigureAwaitAsync(string originalArgs, string fixedArgs) =>
CS_Fixer_Diagnostic_AwaitInvocationPassedAsArgument_InternalAsync(originalArgs, fixedArgs, isEmptyConfigureAwait: false);
private Task CS_Fixer_Diagnostic_AwaitInvocationPassedAsArgument_InternalAsync(string originalArgs, string fixedArgs, bool isEmptyConfigureAwait)
{
string originalSource = @"
using System;
using System.IO;
using System.Threading;
class C
{{
public async void M()
{{
using (FileStream s = new FileStream(""path.txt"", FileMode.Create))
{{
byte[] buffer = new byte[s.Length];
PrintTotalBytesWritten(await s.ReadAsync({0}){1});
}}
}}
private void PrintTotalBytesWritten(int bytesWritten) => Console.WriteLine(bytesWritten);
}}
";
int columnsBeforeStreamInvocation = 42;
int columnsBeforeArguments = columnsBeforeStreamInvocation + " s.ReadAsync(".Length;
return CSharpVerifyExpectedCodeFixDiagnosticsAsync(
string.Format(originalSource, originalArgs, GetConfigureAwaitCSharp(isEmptyConfigureAwait)),
string.Format(originalSource, fixedArgs, GetConfigureAwaitCSharp(isEmptyConfigureAwait)),
GetCSharpResult(12, columnsBeforeStreamInvocation, 12, columnsBeforeArguments + originalArgs.Length));
}
[Fact]
public Task CS_Fixer_Diagnostic_WithTriviaAsync()
{
// Notes:
// The invocation trivia is not part of the squiggle
// If trivia is added before a method argument, it does not get saved as "leading trivia" for the argument, which is why this test only verifies argument trailing trivia
// Trivia from await should remain untouched
string originalSource = @"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = new FileStream(""path.txt"", FileMode.Create))
{
byte[] buffer = new byte[s.Length];
/* AwaitLeadingTrivia */ await /* InvocationLeadingTrivia */ s.ReadAsync(buffer /* BufferTrailingTrivia */, 1 /* OffsetTrailingTrivia */, buffer.Length /* CountTrailingTrivia */, new CancellationToken() /* CancellationTokenTrailingTrivia */) /* InvocationTrailingTrivia */; /* AwaitTrailingTrivia */
}
}
}
";
string fixedSource = @"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = new FileStream(""path.txt"", FileMode.Create))
{
byte[] buffer = new byte[s.Length];
/* AwaitLeadingTrivia */ await /* InvocationLeadingTrivia */ s.ReadAsync(buffer.AsMemory(1 /* OffsetTrailingTrivia */, buffer.Length /* CountTrailingTrivia */) /* BufferTrailingTrivia */, new CancellationToken() /* CancellationTokenTrailingTrivia */) /* InvocationTrailingTrivia */; /* AwaitTrailingTrivia */
}
}
}
";
return CSharpVerifyExpectedCodeFixDiagnosticsAsync(originalSource, fixedSource, GetCSharpResult(12, 74, 12, 254));
}
[Fact]
public Task CS_Fixer_Diagnostic_WithTrivia_WithConfigureAwaitAsync()
{
// Notes:
// The invocation trivia is not part of the squiggle
// If trivia is added before a method argument, it does not get saved as "leading trivia" for the argument, which is why this test only verifies argument trailing trivia
// Trivia from await and ConfigureAwait should remain untouched
string originalSource = @"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = new FileStream(""path.txt"", FileMode.Create))
{
byte[] buffer = new byte[s.Length];
/* AwaitLeadingTrivia */ await /* InvocationLeadingTrivia */ s.ReadAsync(buffer /* BufferTrailingTrivia */, 1 /* OffsetTrailingTrivia */, buffer.Length /* CountTrailingTrivia */, new CancellationToken() /* CancellationTokenTrailingTrivia */).ConfigureAwait(/* ConfigureAwaitArgLeadingTrivia */ false /* ConfigureAwaitArgTrailngTrivia */) /* InvocationTrailingTrivia */; /* AwaitTrailingTrivia */
}
}
}
";
string fixedSource = @"
using System;
using System.IO;
using System.Threading;
class C
{
public async void M()
{
using (FileStream s = new FileStream(""path.txt"", FileMode.Create))
{
byte[] buffer = new byte[s.Length];
/* AwaitLeadingTrivia */ await /* InvocationLeadingTrivia */ s.ReadAsync(buffer.AsMemory(1 /* OffsetTrailingTrivia */, buffer.Length /* CountTrailingTrivia */) /* BufferTrailingTrivia */, new CancellationToken() /* CancellationTokenTrailingTrivia */).ConfigureAwait(/* ConfigureAwaitArgLeadingTrivia */ false /* ConfigureAwaitArgTrailngTrivia */) /* InvocationTrailingTrivia */; /* AwaitTrailingTrivia */
}
}
}
";
return CSharpVerifyExpectedCodeFixDiagnosticsAsync(originalSource, fixedSource, GetCSharpResult(12, 74, 12, 254));
}
[Fact]
public Task CS_Fixer_PreserveNullabilityAsync()
{
// The differences with the WriteAsync test are "condition ? 0 : 1" and "buffer!.Length".
string originalSource = @"
#nullable enable
using System;
using System.IO;
using System.Threading.Tasks;
public class C
{
async void M(FileStream? stream, byte[]? buffer, bool condition)
{
await stream!.ReadAsync(buffer!, offset: condition ? 0 : 1, count: buffer!.Length).ConfigureAwait(false);
}
}
";
string fixedSource = @"
#nullable enable
using System;
using System.IO;
using System.Threading.Tasks;
public class C
{
async void M(FileStream? stream, byte[]? buffer, bool condition)
{
await stream!.ReadAsync(buffer!.AsMemory(start: condition ? 0 : 1, length: buffer!.Length)).ConfigureAwait(false);
}
}
";
return CSharpVerifyForVersionAsync(
originalSource,
fixedSource,
ReferenceAssemblies.Net.Net50,
CodeAnalysis.CSharp.LanguageVersion.CSharp8,
GetCSharpResult(11, 15, 11, 91));
}
[Fact]
public Task CS_Fixer_PreserveNullabilityWithCancellationTOkenAsync()
{
// The differences with the WriteAsync test are "condition ? 0 : 1" and "buffer!.Length".
string originalSource = @"
#nullable enable
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
public class C
{
async void M(FileStream? stream, byte[]? buffer, bool condition, CancellationToken ct)
{
await stream!.ReadAsync(buffer!, offset: condition ? 0 : 1, count: buffer!.Length, ct).ConfigureAwait(false);
}
}
";
string fixedSource = @"
#nullable enable
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
public class C
{
async void M(FileStream? stream, byte[]? buffer, bool condition, CancellationToken ct)
{
await stream!.ReadAsync(buffer!.AsMemory(start: condition ? 0 : 1, length: buffer!.Length), ct).ConfigureAwait(false);
}
}
";
return CSharpVerifyForVersionAsync(
originalSource,
fixedSource,
ReferenceAssemblies.Net.Net50,
CodeAnalysis.CSharp.LanguageVersion.CSharp8,
GetCSharpResult(12, 15, 12, 95));
}
#endregion
#region VB - Diagnostic
private const string _sourceVisualBasic = @"
Imports System
Imports System.IO
Imports System.Threading
Public Module C
Public Async Sub M()
Using s As FileStream = File.Open(""file.txt"", FileMode.Open)
{0}
Await s.ReadAsync({1}){2}
End Using
End Sub
End Module
";
public static IEnumerable<object[]> VisualBasicInlineByteArrayTestData()
{
yield return new object[] { @"New Byte(s.Length - 1) {}, 0, s.Length",
@"(New Byte(s.Length - 1) {}).AsMemory(0, s.Length)" };
yield return new object[] { @"New Byte(s.Length - 1) {}, 0, s.Length, New CancellationToken()",
@"(New Byte(s.Length - 1) {}).AsMemory(0, s.Length), New CancellationToken()" };
}
[WindowsOnlyFact] // https://github.com/dotnet/roslyn/issues/65081
public Task VB_Fixer_Diagnostic_EnsureSystemNamespaceAutoAddedAsync()
{
string originalCode = @"
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) {}
Await s.ReadAsync(New Byte(s.Length - 1) {}, 0, s.Length)
End Using
End Sub
End Class
";
string fixedCode = @"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) {}
Await s.ReadAsync((New Byte(s.Length - 1) {}).AsMemory(0, s.Length))
End Using
End Sub
End Class
";
return VisualBasicVerifyExpectedCodeFixDiagnosticsAsync(originalCode, fixedCode, GetVisualBasicResult(8, 19, 8, 70));
}
[Theory]
[InlineData("System")]
[InlineData("system")]
[InlineData("SYSTEM")]
[InlineData("systEM")]
public Task VB_Fixer_Diagnostic_EnsureSystemNamespaceNotAddedWhenAlreadyPresentAsync(string systemNamespace)
{
string originalCode = $@"
Imports System.IO
Imports System.Threading
Imports {systemNamespace}
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) {{}}
Await s.ReadAsync(New Byte(s.Length - 1) {{}}, 0, s.Length)
End Using
End Sub
End Class
";
string fixedCode = $@"
Imports System.IO
Imports System.Threading
Imports {systemNamespace}
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) {{}}
Await s.ReadAsync((New Byte(s.Length - 1) {{}}).AsMemory(0, s.Length))
End Using
End Sub
End Class
";
return VisualBasicVerifyExpectedCodeFixDiagnosticsAsync(originalCode, fixedCode, GetVisualBasicResult(10, 19, 10, 70));
}
[Theory]
[MemberData(nameof(UnnamedArgumentsFullBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsFullBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWithCancellationTokenFullBufferTestData))]
[MemberData(nameof(VisualBasicUnnamedArgumentsPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWithCancellationTokenPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWrongCaseTestData))]
public Task VB_Fixer_Diagnostic_ArgumentNamingAsync(string originalArgs, string fixedArgs) =>
VisualBasicVerifyCodeFixAsync(originalArgs, fixedArgs, isEmptyByteDeclaration: false, isEmptyConfigureAwait: true);
[Theory]
[MemberData(nameof(UnnamedArgumentsFullBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsFullBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWithCancellationTokenFullBufferTestData))]
[MemberData(nameof(VisualBasicUnnamedArgumentsPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWithCancellationTokenPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWrongCaseTestData))]
public Task VB_Fixer_Diagnostic_ArgumentNaming_WithConfigureAwaitAsync(string originalArgs, string fixedArgs) =>
VisualBasicVerifyCodeFixAsync(originalArgs, fixedArgs, isEmptyByteDeclaration: false, isEmptyConfigureAwait: false);
[Theory]
[MemberData(nameof(VisualBasicInlineByteArrayTestData))]
public Task VB_Fixer_Diagnostic_InlineByteArrayAsync(string originalArgs, string fixedArgs) =>
VisualBasicVerifyCodeFixAsync(originalArgs, fixedArgs, isEmptyByteDeclaration: true, isEmptyConfigureAwait: true);
[Theory]
[MemberData(nameof(VisualBasicInlineByteArrayTestData))]
public Task VB_Fixer_Diagnostic_InlineByteArray_WithConfigureAwaitAsync(string originalArgs, string fixedArgs) =>
VisualBasicVerifyCodeFixAsync(originalArgs, fixedArgs, isEmptyByteDeclaration: true, isEmptyConfigureAwait: false);
[Theory]
[MemberData(nameof(UnnamedArgumentsFullBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsFullBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWithCancellationTokenFullBufferTestData))]
[MemberData(nameof(VisualBasicUnnamedArgumentsPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWithCancellationTokenPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWrongCaseTestData))]
public Task VB_Fixer_Diagnostic_AwaitInvocationPassedAsArgumentAsync(string originalArgs, string fixedArgs) =>
VB_Fixer_Diagnostic_AwaitInvocationPassedAsArgument_InternalAsync(originalArgs, fixedArgs, isEmptyConfigureAwait: true);
[Theory]
[MemberData(nameof(UnnamedArgumentsFullBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsFullBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWithCancellationTokenFullBufferTestData))]
[MemberData(nameof(VisualBasicUnnamedArgumentsPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWithCancellationTokenPartialBufferTestData))]
[MemberData(nameof(VisualBasicNamedArgumentsWrongCaseTestData))]
public Task VB_Fixer_Diagnostic_AwaitInvocationPassedAsArgument_WithConfigureAwaitAsync(string originalArgs, string fixedArgs) =>
VB_Fixer_Diagnostic_AwaitInvocationPassedAsArgument_InternalAsync(originalArgs, fixedArgs, isEmptyConfigureAwait: false);
private Task VB_Fixer_Diagnostic_AwaitInvocationPassedAsArgument_InternalAsync(string originalArgs, string fixedArgs, bool isEmptyConfigureAwait)
{
string originalSource = @"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) {{ }}
PrintTotalBytesWritten(Await s.ReadAsync({0}){1})
End Using
End Sub
Private Sub PrintTotalBytesWritten(ByVal bytesWritten As Integer)
Console.WriteLine(bytesWritten)
End Sub
End Class
";
int columnsBeforeStreamInvocation = 42;
int columnsBeforeArguments = columnsBeforeStreamInvocation + " s.ReadAsync(".Length;
return VisualBasicVerifyExpectedCodeFixDiagnosticsAsync(
string.Format(originalSource, originalArgs, GetConfigureAwaitVisualBasic(isEmptyConfigureAwait)),
string.Format(originalSource, fixedArgs, GetConfigureAwaitVisualBasic(isEmptyConfigureAwait)),
GetVisualBasicResult(9, columnsBeforeStreamInvocation, 9, columnsBeforeArguments + originalArgs.Length));
}
[Fact]
public Task VB_Fixer_Diagnostic_WithTriviaAsync()
{
// Notes:
// - Visual Basic does not allow inline comments like in C#: /**/, only at the end of the line
// - Only the last comment in the arguments section remains ("CancellationTokenComment"), the rest get discarded
string originalSource = @"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await s.ReadAsync( ' OpeningParenthesisComment
buffer, ' BufferComment
1, ' OffsetComment
buffer.Length, ' CountComment
New CancellationToken() ' CancellationTokenComment
) ' InvocationTrailingComment
' AwaitComment
End Using
End Sub
End Class
";
string fixedSource = @"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await s.ReadAsync(buffer.AsMemory(1, buffer.Length), New CancellationToken() ' CancellationTokenComment
) ' InvocationTrailingComment
' AwaitComment
End Using
End Sub
End Class
";
return VisualBasicVerifyExpectedCodeFixDiagnosticsAsync(originalSource, fixedSource, GetVisualBasicResult(9, 19, 14, 18));
}
[Fact]
public Task VB_Fixer_Diagnostic_WithTrivia_WithConfigureAwait_PartialBufferAsync()
{
// Notes:
// - Visual Basic does not allow inline comments like in C#: /**/, only at the end of the line
// - Only the last comment in the arguments section remains ("CancellationTokenComment"), the rest get discarded
string originalSource = @"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await s.ReadAsync( ' OpeningParenthesisComment
buffer, ' BufferComment
1, ' OffsetComment
buffer.Length, ' CountComment
New CancellationToken() ' CancellationTokenComment
).ConfigureAwait(False) ' InvocationTrailingComment
' AwaitComment
End Using
End Sub
End Class
";
string fixedSource = @"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await s.ReadAsync(buffer.AsMemory(1, buffer.Length), New CancellationToken() ' CancellationTokenComment
).ConfigureAwait(False) ' InvocationTrailingComment
' AwaitComment
End Using
End Sub
End Class
";
return VisualBasicVerifyExpectedCodeFixDiagnosticsAsync(originalSource, fixedSource, GetVisualBasicResult(9, 19, 14, 18));
}
[Fact]
public Task VB_Fixer_Diagnostic_WithTrivia_WithConfigureAwait_FullBufferAsync()
{
// Notes:
// - Visual Basic does not allow inline comments like in C#: /**/, only at the end of the line
// - Only the last comment in the arguments section remains ("CancellationTokenComment"), the rest get discarded
string originalSource = @"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await s.ReadAsync( ' OpeningParenthesisComment
buffer, ' BufferComment
0, ' OffsetComment
buffer.Length, ' CountComment
New CancellationToken() ' CancellationTokenComment
).ConfigureAwait(False) ' InvocationTrailingComment
' AwaitComment
End Using
End Sub
End Class
";
string fixedSource = @"
Imports System
Imports System.IO
Imports System.Threading
Class C
Public Async Sub M()
Using s As FileStream = New FileStream(""path.txt"", FileMode.Create)
Dim buffer As Byte() = New Byte(s.Length - 1) { }
Await s.ReadAsync(buffer, New CancellationToken() ' CancellationTokenComment
).ConfigureAwait(False) ' InvocationTrailingComment
' AwaitComment
End Using
End Sub
End Class
";
return VisualBasicVerifyExpectedCodeFixDiagnosticsAsync(originalSource, fixedSource, GetVisualBasicResult(9, 19, 14, 18));
}
#endregion
#region Helpers
private const int _columnBeforeStreamInvocation = 19;
private readonly int _columnsBeforeArguments = _columnBeforeStreamInvocation + " s.ReadAsync(".Length;
private Task CSharpVerifyCodeFixAsync(string originalArgs, string fixedArgs, bool isEmptyByteDeclaration, bool isEmptyConfigureAwait) =>
CSharpVerifyExpectedCodeFixDiagnosticsAsync(
string.Format(_sourceCSharp, GetByteArrayWithoutDataCSharp(isEmptyByteDeclaration), originalArgs, GetConfigureAwaitCSharp(isEmptyConfigureAwait)),
string.Format(_sourceCSharp, GetByteArrayWithoutDataCSharp(isEmptyByteDeclaration), fixedArgs, GetConfigureAwaitCSharp(isEmptyConfigureAwait)),
GetCSharpResult(12, _columnBeforeStreamInvocation, 12, _columnsBeforeArguments + originalArgs.Length));
private Task VisualBasicVerifyCodeFixAsync(string originalArgs, string fixedArgs, bool isEmptyByteDeclaration, bool isEmptyConfigureAwait) =>
VisualBasicVerifyExpectedCodeFixDiagnosticsAsync(
string.Format(_sourceVisualBasic, GetByteArrayWithoutDataVisualBasic(isEmptyByteDeclaration), originalArgs, GetConfigureAwaitVisualBasic(isEmptyConfigureAwait)),
string.Format(_sourceVisualBasic, GetByteArrayWithoutDataVisualBasic(isEmptyByteDeclaration), fixedArgs, GetConfigureAwaitVisualBasic(isEmptyConfigureAwait)),
GetVisualBasicResult(9, _columnBeforeStreamInvocation, 9, _columnsBeforeArguments + originalArgs.Length));
// Returns a C# diagnostic result using the specified rule, lines, columns and preferred method signature for the ReadAsync method.
private DiagnosticResult GetCSharpResult(int startLine, int startColumn, int endLine, int endColumn)
=> GetCSResultForRule(startLine, startColumn, endLine, endColumn,
PreferStreamAsyncMemoryOverloads.PreferStreamReadAsyncMemoryOverloadsRule,
"ReadAsync", "Stream.ReadAsync(Memory<byte>, CancellationToken)");
// Returns a VB diagnostic result using the specified rule, lines, columns and preferred method signature for the ReadAsync method.
private DiagnosticResult GetVisualBasicResult(int startLine, int startColumn, int endLine, int endColumn)
=> GetVBResultForRule(startLine, startColumn, endLine, endColumn,
PreferStreamAsyncMemoryOverloads.PreferStreamReadAsyncMemoryOverloadsRule,
"ReadAsync", "Stream.ReadAsync(Memory(Of Byte), CancellationToken)");
#endregion
}
}
|