Skip to content

Commit dadbd48

Browse files
committed
Added draft tests for source generator diagnostics
1 parent 6b6d66a commit dadbd48

File tree

4 files changed

+304
-2
lines changed

4 files changed

+304
-2
lines changed
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Collections.Immutable;
8+
using System.ComponentModel.DataAnnotations;
9+
using System.Linq;
10+
using Microsoft.CodeAnalysis;
11+
using Microsoft.CodeAnalysis.CSharp;
12+
using Microsoft.Toolkit.Mvvm.SourceGenerators;
13+
using Microsoft.VisualStudio.TestTools.UnitTesting;
14+
15+
namespace UnitTests.Mvvm
16+
{
17+
[TestClass]
18+
public class Test_SourceGeneratorsDiagnostics
19+
{
20+
[TestCategory("Mvvm")]
21+
[TestMethod]
22+
public void DuplicateINotifyPropertyChangedInterfaceForINotifyPropertyChangedAttributeError_Explicit()
23+
{
24+
string source = @"
25+
using System.ComponentModel;
26+
using Microsoft.Toolkit.Mvvm.ComponentModel;
27+
28+
namespace MyApp
29+
{
30+
[INotifyPropertyChanged]
31+
public partial class SampleViewModel : INotifyPropertyChanged
32+
{
33+
public event PropertyChangedEventHandler? PropertyChanged;
34+
}
35+
}";
36+
37+
VerifyGeneratedDiagnostics<INotifyPropertyChangedGenerator>(source, "MVVMTK0004");
38+
}
39+
40+
[TestCategory("Mvvm")]
41+
[TestMethod]
42+
public void DuplicateINotifyPropertyChangedInterfaceForINotifyPropertyChangedAttributeError_Inherited()
43+
{
44+
string source = @"
45+
using System.ComponentModel;
46+
using Microsoft.Toolkit.Mvvm.ComponentModel;
47+
48+
namespace Microsoft.Toolkit.Mvvm.ComponentModel
49+
{
50+
public abstract class ObservableObject : INotifyPropertyChanged, INotifyPropertyChanging
51+
{
52+
public event PropertyChangedEventHandler? PropertyChanged;
53+
public event PropertyChangingEventHandler? PropertyChanging;
54+
}
55+
}
56+
57+
namespace MyApp
58+
{
59+
[INotifyPropertyChanged]
60+
public partial class SampleViewModel : ObservableObject
61+
{
62+
}
63+
}";
64+
65+
VerifyGeneratedDiagnostics<INotifyPropertyChangedGenerator>(source, "MVVMTK0004");
66+
}
67+
68+
[TestCategory("Mvvm")]
69+
[TestMethod]
70+
public void DuplicateINotifyPropertyChangedInterfaceForObservableObjectAttributeError_Explicit()
71+
{
72+
string source = @"
73+
using System.ComponentModel;
74+
using Microsoft.Toolkit.Mvvm.ComponentModel;
75+
76+
namespace MyApp
77+
{
78+
[ObservableObject]
79+
public partial class SampleViewModel : INotifyPropertyChanged
80+
{
81+
public event PropertyChangedEventHandler? PropertyChanged;
82+
}
83+
}";
84+
85+
VerifyGeneratedDiagnostics<ObservableObjectGenerator>(source, "MVVMTK0005");
86+
}
87+
88+
[TestCategory("Mvvm")]
89+
[TestMethod]
90+
public void DuplicateINotifyPropertyChangedInterfaceForObservableObjectAttributeError_Inherited()
91+
{
92+
string source = @"
93+
using System.ComponentModel;
94+
using Microsoft.Toolkit.Mvvm.ComponentModel;
95+
96+
namespace Microsoft.Toolkit.Mvvm.ComponentModel
97+
{
98+
public abstract class ObservableObject : INotifyPropertyChanged
99+
{
100+
public event PropertyChangedEventHandler? PropertyChanged;
101+
}
102+
}
103+
104+
namespace MyApp
105+
{
106+
[ObservableObject]
107+
public partial class SampleViewModel : ObservableObject
108+
{
109+
}
110+
}";
111+
112+
VerifyGeneratedDiagnostics<ObservableObjectGenerator>(source, "MVVMTK0005");
113+
}
114+
115+
[TestCategory("Mvvm")]
116+
[TestMethod]
117+
public void DuplicateINotifyPropertyChangingInterfaceForObservableObjectAttributeError_Explicit()
118+
{
119+
string source = @"
120+
using System.ComponentModel;
121+
using Microsoft.Toolkit.Mvvm.ComponentModel;
122+
123+
namespace MyApp
124+
{
125+
[ObservableObject]
126+
public partial class SampleViewModel : INotifyPropertyChanging
127+
{
128+
public event PropertyChangingEventHandler? PropertyChanging;
129+
}
130+
}";
131+
132+
VerifyGeneratedDiagnostics<ObservableObjectGenerator>(source, "MVVMTK0006");
133+
}
134+
135+
[TestCategory("Mvvm")]
136+
[TestMethod]
137+
public void DuplicateINotifyPropertyChangingInterfaceForObservableObjectAttributeError_Inherited()
138+
{
139+
string source = @"
140+
using System.ComponentModel;
141+
using Microsoft.Toolkit.Mvvm.ComponentModel;
142+
143+
namespace MyApp
144+
{
145+
public abstract class MyBaseViewModel : INotifyPropertyChanging
146+
{
147+
public event PropertyChangingEventHandler? PropertyChanging;
148+
}
149+
150+
[ObservableObject]
151+
public partial class SampleViewModel : MyBaseViewModel
152+
{
153+
}
154+
}";
155+
156+
VerifyGeneratedDiagnostics<ObservableObjectGenerator>(source, "MVVMTK0006");
157+
}
158+
159+
[TestCategory("Mvvm")]
160+
[TestMethod]
161+
public void DuplicateObservableRecipientError()
162+
{
163+
string source = @"
164+
using Microsoft.Toolkit.Mvvm.ComponentModel;
165+
166+
namespace Microsoft.Toolkit.Mvvm.ComponentModel
167+
{
168+
public abstract class ObservableRecipient : ObservableObject
169+
{
170+
}
171+
}
172+
173+
namespace MyApp
174+
{
175+
[ObservableRecipient]
176+
public partial class SampleViewModel : ObservableRecipient
177+
{
178+
}
179+
}";
180+
181+
VerifyGeneratedDiagnostics<ObservableRecipientGenerator>(source, "MVVMTK0007");
182+
}
183+
184+
[TestCategory("Mvvm")]
185+
[TestMethod]
186+
public void MissingBaseObservableObjectFunctionalityError()
187+
{
188+
string source = @"
189+
using Microsoft.Toolkit.Mvvm.ComponentModel;
190+
191+
namespace MyApp
192+
{
193+
[ObservableRecipient]
194+
public partial class SampleViewModel
195+
{
196+
}
197+
}";
198+
199+
VerifyGeneratedDiagnostics<ObservableRecipientGenerator>(source, "MVVMTK0008");
200+
}
201+
202+
[TestCategory("Mvvm")]
203+
[TestMethod]
204+
public void MissingObservableValidatorInheritanceError()
205+
{
206+
string source = @"
207+
using System.ComponentModel.DataAnnotations;
208+
using Microsoft.Toolkit.Mvvm.ComponentModel;
209+
210+
namespace MyApp
211+
{
212+
[INotifyPropertyChanged]
213+
public partial class SampleViewModel
214+
{
215+
[ObservableProperty]
216+
[Required]
217+
private string name;
218+
}
219+
}";
220+
221+
VerifyGeneratedDiagnostics<ObservablePropertyGenerator>(source, "MVVMTK0009");
222+
}
223+
224+
/// <summary>
225+
/// Verifies the output of a source generator.
226+
/// </summary>
227+
/// <typeparam name="TGenerator">The generator type to use.</typeparam>
228+
/// <param name="source">The input source to process.</param>
229+
/// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param>
230+
private void VerifyGeneratedDiagnostics<TGenerator>(string source, params string[] diagnosticsIds)
231+
where TGenerator : class, ISourceGenerator, new()
232+
{
233+
Type validationAttributeType = typeof(ValidationAttribute);
234+
235+
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source);
236+
237+
IEnumerable<MetadataReference> references =
238+
from assembly in AppDomain.CurrentDomain.GetAssemblies()
239+
where !assembly.IsDynamic
240+
let reference = MetadataReference.CreateFromFile(assembly.Location)
241+
select reference;
242+
243+
CSharpCompilation compilation = CSharpCompilation.Create("original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
244+
245+
ISourceGenerator generator = new TGenerator();
246+
247+
CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
248+
249+
driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray<Diagnostic> diagnostics);
250+
251+
HashSet<string> resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet();
252+
253+
Assert.IsTrue(resultingIds.SetEquals(diagnosticsIds));
254+
255+
GC.KeepAlive(validationAttributeType);
256+
}
257+
}
258+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net5.0</TargetFrameworks>
5+
<IsPackable>false</IsPackable>
6+
<LangVersion>9.0</LangVersion>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.10.0-1.final" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
12+
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
13+
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="..\..\Microsoft.Toolkit.Mvvm.SourceGenerators\Microsoft.Toolkit.Mvvm.SourceGenerators.csproj" />
18+
</ItemGroup>
19+
20+
</Project>

Windows Community Toolkit (NET).slnf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"UnitTests\\UnitTests.HighPerformance.NetCore\\UnitTests.HighPerformance.NetCore.csproj",
1111
"UnitTests\\UnitTests.HighPerformance.Shared\\UnitTests.HighPerformance.Shared.shproj",
1212
"UnitTests\\UnitTests.NetCore\\UnitTests.NetCore.csproj",
13-
"UnitTests\\UnitTests.Shared\\UnitTests.Shared.shproj"
13+
"UnitTests\\UnitTests.Shared\\UnitTests.Shared.shproj",
14+
"UnitTests\\UnitTests.SourceGenerators\\UnitTests.SourceGenerators.csproj",
1415
]
1516
}
1617
}

Windows Community Toolkit.sln

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Toolkit.Uwp.UI.Co
157157
EndProject
158158
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.UI.Controls", "Microsoft.Toolkit.Uwp.UI.Controls\Microsoft.Toolkit.Uwp.UI.Controls.csproj", "{099B60FD-DAD6-4648-9DE2-8DBF9DCD9557}"
159159
EndProject
160-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Toolkit.Mvvm.SourceGenerators", "Microsoft.Toolkit.Mvvm.SourceGenerators\Microsoft.Toolkit.Mvvm.SourceGenerators.csproj", "{E24D1146-5AD8-498F-A518-4890D8BF4937}"
160+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Mvvm.SourceGenerators", "Microsoft.Toolkit.Mvvm.SourceGenerators\Microsoft.Toolkit.Mvvm.SourceGenerators.csproj", "{E24D1146-5AD8-498F-A518-4890D8BF4937}"
161+
EndProject
162+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.SourceGenerators", "UnitTests\UnitTests.SourceGenerators\UnitTests.SourceGenerators.csproj", "{338C3BE4-2E71-4F21-AD30-03FDBB47A272}"
161163
EndProject
162164
Global
163165
GlobalSection(SharedMSBuildProjectFiles) = preSolution
@@ -1132,6 +1134,26 @@ Global
11321134
{E24D1146-5AD8-498F-A518-4890D8BF4937}.Release|x64.Build.0 = Release|Any CPU
11331135
{E24D1146-5AD8-498F-A518-4890D8BF4937}.Release|x86.ActiveCfg = Release|Any CPU
11341136
{E24D1146-5AD8-498F-A518-4890D8BF4937}.Release|x86.Build.0 = Release|Any CPU
1137+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1138+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|Any CPU.Build.0 = Debug|Any CPU
1139+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|ARM.ActiveCfg = Debug|Any CPU
1140+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|ARM.Build.0 = Debug|Any CPU
1141+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|ARM64.ActiveCfg = Debug|Any CPU
1142+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|ARM64.Build.0 = Debug|Any CPU
1143+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|x64.ActiveCfg = Debug|Any CPU
1144+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|x64.Build.0 = Debug|Any CPU
1145+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|x86.ActiveCfg = Debug|Any CPU
1146+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Debug|x86.Build.0 = Debug|Any CPU
1147+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|Any CPU.ActiveCfg = Release|Any CPU
1148+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|Any CPU.Build.0 = Release|Any CPU
1149+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|ARM.ActiveCfg = Release|Any CPU
1150+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|ARM.Build.0 = Release|Any CPU
1151+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|ARM64.ActiveCfg = Release|Any CPU
1152+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|ARM64.Build.0 = Release|Any CPU
1153+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|x64.ActiveCfg = Release|Any CPU
1154+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|x64.Build.0 = Release|Any CPU
1155+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|x86.ActiveCfg = Release|Any CPU
1156+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|x86.Build.0 = Release|Any CPU
11351157
EndGlobalSection
11361158
GlobalSection(SolutionProperties) = preSolution
11371159
HideSolutionNode = FALSE
@@ -1181,6 +1203,7 @@ Global
11811203
{AF1BE4E9-E2E1-4729-B076-B3725D8E21EE} = {F1AFFFA7-28FE-4770-BA48-10D76F3E59BC}
11821204
{3307BC1D-5D71-41C6-A1B3-B113B8242D08} = {F1AFFFA7-28FE-4770-BA48-10D76F3E59BC}
11831205
{099B60FD-DAD6-4648-9DE2-8DBF9DCD9557} = {F1AFFFA7-28FE-4770-BA48-10D76F3E59BC}
1206+
{338C3BE4-2E71-4F21-AD30-03FDBB47A272} = {B30036C4-D514-4E5B-A323-587A061772CE}
11841207
EndGlobalSection
11851208
GlobalSection(ExtensibilityGlobals) = postSolution
11861209
SolutionGuid = {5403B0C4-F244-4F73-A35C-FE664D0F4345}

0 commit comments

Comments
 (0)