Skip to content

Commit 00fdbef

Browse files
committed
Add unit tests for analyzer changes
1 parent a35944f commit 00fdbef

File tree

2 files changed

+292
-10
lines changed

2 files changed

+292
-10
lines changed

tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.UnitTests/Test_SourceGeneratorsCodegen.cs

Lines changed: 235 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ partial class Test_SourceGeneratorsCodegen
2121
public void ObservablePropertyWithValueType_OnPartialProperty_WithNoModifiers_WorksCorrectly()
2222
{
2323
string source = """
24-
using System;
2524
using CommunityToolkit.Mvvm.ComponentModel;
2625
2726
namespace MyApp;
@@ -97,7 +96,6 @@ partial int Number
9796
public void ObservablePropertyWithValueType_OnPartialProperty_RequiredProperty_WorksCorrectly()
9897
{
9998
string source = """
100-
using System;
10199
using CommunityToolkit.Mvvm.ComponentModel;
102100
103101
namespace MyApp;
@@ -168,11 +166,245 @@ private set
168166
VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
169167
}
170168

169+
// See https://github.com/CommunityToolkit/dotnet/issues/1013
170+
[TestMethod]
171+
public void ObservablePropertyWithValueType_OnPartialProperty_NewProperty_WorksCorrectly()
172+
{
173+
string source = """
174+
using CommunityToolkit.Mvvm.ComponentModel;
175+
176+
namespace MyApp;
177+
178+
partial class BaseViewModel : ObservableObject
179+
{
180+
public int Number { get; private set; }
181+
}
182+
183+
partial class MyViewModel : BaseViewModel
184+
{
185+
[ObservableProperty]
186+
public new partial int Number { get; private set; }
187+
}
188+
""";
189+
190+
string result = """
191+
// <auto-generated/>
192+
#pragma warning disable
193+
#nullable enable
194+
namespace MyApp
195+
{
196+
/// <inheritdoc/>
197+
partial class MyViewModel
198+
{
199+
/// <inheritdoc/>
200+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
201+
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
202+
public new partial int Number
203+
{
204+
get => field;
205+
private set
206+
{
207+
if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
208+
{
209+
OnNumberChanging(value);
210+
OnNumberChanging(default, value);
211+
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
212+
field = value;
213+
OnNumberChanged(value);
214+
OnNumberChanged(default, value);
215+
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
216+
}
217+
}
218+
}
219+
220+
/// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
221+
/// <param name="value">The new property value being set.</param>
222+
/// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
223+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
224+
partial void OnNumberChanging(int value);
225+
/// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
226+
/// <param name="oldValue">The previous property value that is being replaced.</param>
227+
/// <param name="newValue">The new property value being set.</param>
228+
/// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
229+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
230+
partial void OnNumberChanging(int oldValue, int newValue);
231+
/// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
232+
/// <param name="value">The new property value that was set.</param>
233+
/// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
234+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
235+
partial void OnNumberChanged(int value);
236+
/// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
237+
/// <param name="oldValue">The previous property value that was replaced.</param>
238+
/// <param name="newValue">The new property value that was set.</param>
239+
/// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
240+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
241+
partial void OnNumberChanged(int oldValue, int newValue);
242+
}
243+
}
244+
""";
245+
246+
VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
247+
}
248+
249+
[TestMethod]
250+
public void ObservablePropertyWithValueType_OnPartialProperty_VirtualProperty_WorksCorrectly()
251+
{
252+
string source = """
253+
using CommunityToolkit.Mvvm.ComponentModel;
254+
255+
namespace MyApp;
256+
257+
partial class MyViewModel : ObservableObject
258+
{
259+
[ObservableProperty]
260+
public virtual partial int Number { get; private set; }
261+
}
262+
""";
263+
264+
string result = """
265+
// <auto-generated/>
266+
#pragma warning disable
267+
#nullable enable
268+
namespace MyApp
269+
{
270+
/// <inheritdoc/>
271+
partial class MyViewModel
272+
{
273+
/// <inheritdoc/>
274+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
275+
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
276+
public virtual partial int Number
277+
{
278+
get => field;
279+
private set
280+
{
281+
if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
282+
{
283+
OnNumberChanging(value);
284+
OnNumberChanging(default, value);
285+
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
286+
field = value;
287+
OnNumberChanged(value);
288+
OnNumberChanged(default, value);
289+
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
290+
}
291+
}
292+
}
293+
294+
/// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
295+
/// <param name="value">The new property value being set.</param>
296+
/// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
297+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
298+
partial void OnNumberChanging(int value);
299+
/// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
300+
/// <param name="oldValue">The previous property value that is being replaced.</param>
301+
/// <param name="newValue">The new property value being set.</param>
302+
/// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
303+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
304+
partial void OnNumberChanging(int oldValue, int newValue);
305+
/// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
306+
/// <param name="value">The new property value that was set.</param>
307+
/// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
308+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
309+
partial void OnNumberChanged(int value);
310+
/// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
311+
/// <param name="oldValue">The previous property value that was replaced.</param>
312+
/// <param name="newValue">The new property value that was set.</param>
313+
/// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
314+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
315+
partial void OnNumberChanged(int oldValue, int newValue);
316+
}
317+
}
318+
""";
319+
320+
VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
321+
}
322+
323+
[TestMethod]
324+
[DataRow("override")]
325+
[DataRow("sealed override")]
326+
public void ObservablePropertyWithValueType_OnPartialProperty_OverrideProperty_WorksCorrectly(string modifiers)
327+
{
328+
string source = $$"""
329+
using CommunityToolkit.Mvvm.ComponentModel;
330+
331+
namespace MyApp;
332+
333+
partial class BaseViewModel : ObservableObject
334+
{
335+
public virtual partial int Number { get; private set; }
336+
}
337+
338+
partial class MyViewModel : BaseViewModel
339+
{
340+
[ObservableProperty]
341+
public {{modifiers}} partial int Number { get; private set; }
342+
}
343+
""";
344+
345+
string result = $$"""
346+
// <auto-generated/>
347+
#pragma warning disable
348+
#nullable enable
349+
namespace MyApp
350+
{
351+
/// <inheritdoc/>
352+
partial class MyViewModel
353+
{
354+
/// <inheritdoc/>
355+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
356+
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
357+
public {{modifiers}} partial int Number
358+
{
359+
get => field;
360+
private set
361+
{
362+
if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
363+
{
364+
OnNumberChanging(value);
365+
OnNumberChanging(default, value);
366+
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
367+
field = value;
368+
OnNumberChanged(value);
369+
OnNumberChanged(default, value);
370+
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
371+
}
372+
}
373+
}
374+
375+
/// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
376+
/// <param name="value">The new property value being set.</param>
377+
/// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
378+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
379+
partial void OnNumberChanging(int value);
380+
/// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
381+
/// <param name="oldValue">The previous property value that is being replaced.</param>
382+
/// <param name="newValue">The new property value being set.</param>
383+
/// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
384+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
385+
partial void OnNumberChanging(int oldValue, int newValue);
386+
/// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
387+
/// <param name="value">The new property value that was set.</param>
388+
/// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
389+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
390+
partial void OnNumberChanged(int value);
391+
/// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
392+
/// <param name="oldValue">The previous property value that was replaced.</param>
393+
/// <param name="newValue">The new property value that was set.</param>
394+
/// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
395+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
396+
partial void OnNumberChanged(int oldValue, int newValue);
397+
}
398+
}
399+
""";
400+
401+
VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
402+
}
403+
171404
[TestMethod]
172405
public void ObservablePropertyWithValueType_OnPartialProperty_WithExplicitModifiers_WorksCorrectly1()
173406
{
174407
string source = """
175-
using System;
176408
using CommunityToolkit.Mvvm.ComponentModel;
177409
178410
namespace MyApp;
@@ -247,7 +479,6 @@ private set
247479
public void ObservablePropertyWithValueType_OnPartialProperty_WithExplicitModifiers_WorksCorrectly2()
248480
{
249481
string source = """
250-
using System;
251482
using CommunityToolkit.Mvvm.ComponentModel;
252483
253484
namespace MyApp;
@@ -397,7 +628,6 @@ private protected set
397628
public void ObservablePropertyWithReferenceType_NotNullable_OnPartialProperty_WorksCorrectly()
398629
{
399630
string source = """
400-
using System;
401631
using CommunityToolkit.Mvvm.ComponentModel;
402632
403633
#nullable enable
@@ -474,7 +704,6 @@ public partial string Name
474704
public void ObservablePropertyWithReferenceType_Nullable_OnPartialProperty_WorksCorrectly()
475705
{
476706
string source = """
477-
using System;
478707
using CommunityToolkit.Mvvm.ComponentModel;
479708
480709
#nullable enable
@@ -551,7 +780,6 @@ public partial string? Name
551780
public void ObservableProperty_OnPartialProperty_AlsoNotifyPropertyChange_WorksCorrectly()
552781
{
553782
string source = """
554-
using System;
555783
using CommunityToolkit.Mvvm.ComponentModel;
556784
557785
namespace MyApp;
@@ -631,7 +859,6 @@ public partial string Name
631859
public void ObservableProperty_OnPartialProperty_AlsoNotifyCanExecuteChange_WorksCorrectly()
632860
{
633861
string source = """
634-
using System;
635862
using CommunityToolkit.Mvvm.ComponentModel;
636863
using CommunityToolkit.Mvvm.Input;
637864
@@ -711,7 +938,6 @@ public partial string Name
711938
public void ObservableProperty_OnPartialProperty_AlsoNotifyRecipients_WorksCorrectly()
712939
{
713940
string source = """
714-
using System;
715941
using System.Windows.Input;
716942
using CommunityToolkit.Mvvm.ComponentModel;
717943
@@ -790,7 +1016,6 @@ public partial string Name
7901016
public void ObservableProperty_OnPartialProperty_AlsoNotifyDataErrorInfo_WorksCorrectly()
7911017
{
7921018
string source = """
793-
using System;
7941019
using System.ComponentModel.DataAnnotations;
7951020
using System.Windows.Input;
7961021
using CommunityToolkit.Mvvm.ComponentModel;

tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.UnitTests/Test_SourceGeneratorsDiagnostics.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,4 +998,61 @@ public partial class SampleViewModel : ObservableObject
998998

999999
await VerifyAnalyzerDiagnosticsAndSuccessfulGeneration<InvalidPartialPropertyLevelObservablePropertyAttributeAnalyzer>(source, LanguageVersion.Preview, [], ["CS9248"]);
10001000
}
1001+
1002+
[TestMethod]
1003+
public async Task InvalidPointerTypeObservablePropertyAttributeAnalyzer_ReturnsValidType_DoesNotWarn()
1004+
{
1005+
const string source = """
1006+
using CommunityToolkit.Mvvm.ComponentModel;
1007+
1008+
namespace MyApp
1009+
{
1010+
public partial class SampleViewModel : ObservableObject
1011+
{
1012+
[ObservableProperty]
1013+
public partial string {|CS9248:Name|} { get; set; }
1014+
}
1015+
}
1016+
""";
1017+
1018+
await VerifyAnalyzerDiagnosticsAndSuccessfulGeneration<InvalidPointerTypeObservablePropertyAttributeAnalyzer>(source, LanguageVersion.Preview, [], ["CS9248"]);
1019+
}
1020+
1021+
[TestMethod]
1022+
public async Task InvalidPointerTypeObservablePropertyAttributeAnalyzer_ReturnsPointerType_Warns()
1023+
{
1024+
const string source = """
1025+
using CommunityToolkit.Mvvm.ComponentModel;
1026+
1027+
namespace MyApp
1028+
{
1029+
public unsafe partial class SampleViewModel : ObservableObject
1030+
{
1031+
[{|MVVMTK0055:ObservableProperty|}]
1032+
public partial int* {|CS9248:Name|} { get; set; }
1033+
}
1034+
}
1035+
""";
1036+
1037+
await CSharpAnalyzerWithLanguageVersionTest<InvalidPointerTypeObservablePropertyAttributeAnalyzer>.VerifyAnalyzerAsync(source, LanguageVersion.Preview);
1038+
}
1039+
1040+
[TestMethod]
1041+
public async Task InvalidPointerTypeObservablePropertyAttributeAnalyzer_ReturnsFunctionPointerType_Warns()
1042+
{
1043+
const string source = """
1044+
using CommunityToolkit.Mvvm.ComponentModel;
1045+
1046+
namespace MyApp
1047+
{
1048+
public unsafe partial class SampleViewModel : ObservableObject
1049+
{
1050+
[{|MVVMTK0055:ObservableProperty|}]
1051+
public partial delegate* unmanaged[Stdcall]<int, void> {|CS9248:Name|} { get; set; }
1052+
}
1053+
}
1054+
""";
1055+
1056+
await CSharpAnalyzerWithLanguageVersionTest<InvalidPointerTypeObservablePropertyAttributeAnalyzer>.VerifyAnalyzerAsync(source, LanguageVersion.Preview);
1057+
}
10011058
}

0 commit comments

Comments
 (0)