Skip to content

Commit 449b965

Browse files
committed
Add unit test to demonstrate the breaking change introduced in dotnet#41768, and described in dotnet#44553 (comment)
Verified the test failed without any product change.
1 parent 19c0d73 commit 449b965

File tree

1 file changed

+64
-10
lines changed

1 file changed

+64
-10
lines changed

src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using System;
88
using System.Collections.Generic;
99
using System.Collections.Immutable;
10-
using System.Composition;
1110
using System.Linq;
1211
using System.Threading;
1312
using System.Threading.Tasks;
@@ -97,33 +96,33 @@ public async Task TestGetFixesAsyncWithDuplicateDiagnostics()
9796
public async Task TestGetCodeFixWithExceptionInRegisterMethod()
9897
{
9998
await GetFirstDiagnosticWithFixAsync(new ErrorCases.ExceptionInRegisterMethod());
100-
await GetAddedFixesAsync(new ErrorCases.ExceptionInRegisterMethod());
99+
await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInRegisterMethod());
101100
}
102101

103102
[Fact]
104103
public async Task TestGetCodeFixWithExceptionInRegisterMethodAsync()
105104
{
106105
await GetFirstDiagnosticWithFixAsync(new ErrorCases.ExceptionInRegisterMethodAsync());
107-
await GetAddedFixesAsync(new ErrorCases.ExceptionInRegisterMethodAsync());
106+
await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInRegisterMethodAsync());
108107
}
109108

110109
[Fact]
111110
public async Task TestGetCodeFixWithExceptionInFixableDiagnosticIds()
112111
{
113112
await GetDefaultFixesAsync(new ErrorCases.ExceptionInFixableDiagnosticIds());
114-
await GetAddedFixesAsync(new ErrorCases.ExceptionInFixableDiagnosticIds());
113+
await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInFixableDiagnosticIds());
115114
}
116115

117116
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21533")]
118117
public async Task TestGetCodeFixWithExceptionInFixableDiagnosticIds2()
119118
{
120119
await GetDefaultFixesAsync(new ErrorCases.ExceptionInFixableDiagnosticIds2());
121-
await GetAddedFixesAsync(new ErrorCases.ExceptionInFixableDiagnosticIds2());
120+
await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInFixableDiagnosticIds2());
122121
}
123122

124123
[Fact]
125124
public async Task TestGetCodeFixWithExceptionInGetFixAllProvider()
126-
=> await GetAddedFixesAsync(new ErrorCases.ExceptionInGetFixAllProvider());
125+
=> await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInGetFixAllProvider());
127126

128127
private async Task GetDefaultFixesAsync(CodeFixProvider codefix)
129128
{
@@ -136,7 +135,10 @@ private async Task GetDefaultFixesAsync(CodeFixProvider codefix)
136135
Assert.True(((TestErrorLogger)tuple.errorLogger).Messages.TryGetValue(codefix.GetType().Name, out var message));
137136
}
138137

139-
private async Task GetAddedFixesAsync(CodeFixProvider codefix)
138+
private Task<ImmutableArray<CodeFixCollection>> GetAddedFixesWithExceptionValidationAsync(CodeFixProvider codefix)
139+
=> GetAddedFixesAsync(codefix, diagnosticAnalyzer: new MockAnalyzerReference.MockDiagnosticAnalyzer(), exception: true);
140+
141+
private async Task<ImmutableArray<CodeFixCollection>> GetAddedFixesAsync(CodeFixProvider codefix, DiagnosticAnalyzer diagnosticAnalyzer, bool exception = false)
140142
{
141143
var tuple = ServiceSetup(codefix);
142144

@@ -145,13 +147,18 @@ private async Task GetAddedFixesAsync(CodeFixProvider codefix)
145147
GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager);
146148
var incrementalAnalyzer = (IIncrementalAnalyzerProvider)tuple.analyzerService;
147149
var analyzer = incrementalAnalyzer.CreateIncrementalAnalyzer(workspace);
148-
var reference = new MockAnalyzerReference(codefix);
150+
var reference = new MockAnalyzerReference(codefix, ImmutableArray.Create(diagnosticAnalyzer));
149151
var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference);
150152
document = project.Documents.Single();
151153
var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), includeConfigurationFixes: true, cancellationToken: CancellationToken.None);
152154

153-
Assert.True(extensionManager.IsDisabled(codefix));
154-
Assert.False(extensionManager.IsIgnored(codefix));
155+
if (exception)
156+
{
157+
Assert.True(extensionManager.IsDisabled(codefix));
158+
Assert.False(extensionManager.IsIgnored(codefix));
159+
}
160+
161+
return fixes;
155162
}
156163

157164
private async Task GetFirstDiagnosticWithFixAsync(CodeFixProvider codefix)
@@ -527,5 +534,52 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
527534
return Task.CompletedTask;
528535
}
529536
}
537+
538+
[Theory, WorkItem(44553, "https://github.com/dotnet/roslyn/issues/44553")]
539+
[InlineData(null)]
540+
[InlineData("CodeFixProviderWithDuplicateEquivalenceKeyActions")]
541+
public async Task TestRegisteredCodeActionsWithSameEquivalenceKey(string? equivalenceKey)
542+
{
543+
var diagnosticId = "ID1";
544+
var analyzer = new MockAnalyzerReference.MockDiagnosticAnalyzer(ImmutableArray.Create(diagnosticId));
545+
var fixer = new CodeFixProviderWithDuplicateEquivalenceKeyActions(diagnosticId, equivalenceKey);
546+
547+
// Verify multiple code actions registered with same equivalence key are not de-duped.
548+
var fixes = (await GetAddedFixesAsync(fixer, analyzer)).SelectMany(fixCollection => fixCollection.Fixes).ToList();
549+
Assert.Equal(2, fixes.Count);
550+
}
551+
552+
private sealed class CodeFixProviderWithDuplicateEquivalenceKeyActions : CodeFixProvider
553+
{
554+
private readonly string _diagnosticId;
555+
private readonly string? _equivalenceKey;
556+
557+
public CodeFixProviderWithDuplicateEquivalenceKeyActions(string diagnosticId, string? equivalenceKey)
558+
{
559+
_diagnosticId = diagnosticId;
560+
_equivalenceKey = equivalenceKey;
561+
}
562+
563+
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(_diagnosticId);
564+
565+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
566+
{
567+
// Register duplicate code actions with same equivalence key, but different title.
568+
RegisterCodeFix(context, titleSuffix: "1");
569+
RegisterCodeFix(context, titleSuffix: "2");
570+
571+
return Task.CompletedTask;
572+
}
573+
574+
private void RegisterCodeFix(CodeFixContext context, string titleSuffix)
575+
{
576+
context.RegisterCodeFix(
577+
CodeAction.Create(
578+
nameof(CodeFixProviderWithDuplicateEquivalenceKeyActions) + titleSuffix,
579+
ct => Task.FromResult(context.Document),
580+
_equivalenceKey),
581+
context.Diagnostics);
582+
}
583+
}
530584
}
531585
}

0 commit comments

Comments
 (0)