From ba00de96162ea2ce7cb0fefff2fbec7418176b22 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 7 Dec 2024 12:30:55 -0800 Subject: [PATCH] Add unit tests for new analyzer --- ...ropertyDefaultValueCallbackTypeAnalyzer.cs | 10 +- .../Test_Analyzers.cs | 231 +++++++++++++++++- 2 files changed, 232 insertions(+), 9 deletions(-) diff --git a/components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.SourceGenerators/Diagnostics/Analyzers/InvalidPropertyDefaultValueCallbackTypeAnalyzer.cs b/components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.SourceGenerators/Diagnostics/Analyzers/InvalidPropertyDefaultValueCallbackTypeAnalyzer.cs index e2577b301..d12d5662c 100644 --- a/components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.SourceGenerators/Diagnostics/Analyzers/InvalidPropertyDefaultValueCallbackTypeAnalyzer.cs +++ b/components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.SourceGenerators/Diagnostics/Analyzers/InvalidPropertyDefaultValueCallbackTypeAnalyzer.cs @@ -108,8 +108,8 @@ public static bool TryFindDefaultValueCallbackMethod(IPropertySymbol propertySym foreach (ISymbol member in memberSymbols) { - // We need methods which are static and with no parameters (and that is not explicitly implemented) - if (member is not IMethodSymbol { IsStatic: true, Parameters: [], ExplicitInterfaceImplementations: [] } candidateSymbol) + // Ignore all other member types + if (member is not IMethodSymbol candidateSymbol) { continue; } @@ -136,6 +136,12 @@ public static bool TryFindDefaultValueCallbackMethod(IPropertySymbol propertySym /// Whether is a valid default value callback method for . public static bool IsDefaultValueCallbackValid(IPropertySymbol propertySymbol, IMethodSymbol methodSymbol) { + // We need methods which are static and with no parameters (and that are not explicitly implemented) + if (methodSymbol is not { IsStatic: true, Parameters: [], ExplicitInterfaceImplementations: [] }) + { + return false; + } + // We have a candidate, now we need to match the return type. First, // we just check whether the return is 'object', or an exact match. if (methodSymbol.ReturnType.SpecialType is SpecialType.System_Object || diff --git a/components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.Tests/Test_Analyzers.cs b/components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.Tests/Test_Analyzers.cs index 3a9c8e330..19657c763 100644 --- a/components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.Tests/Test_Analyzers.cs +++ b/components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.Tests/Test_Analyzers.cs @@ -659,7 +659,7 @@ public partial class MyControl : Control [TestMethod] public async Task InvalidPropertyNonNullableDeclarationAnalyzer_NotNullableType_WithMaybeNullAttribute_DoesNotWarn() { - string source = $$""" + const string source = """ using System.Diagnostics.CodeAnalysis; using CommunityToolkit.WinUI; using Windows.UI.Xaml.Controls; @@ -682,7 +682,7 @@ public partial class MyControl : Control [TestMethod] public async Task InvalidPropertyNonNullableDeclarationAnalyzer_NotNullableType_Required_DoesNotWarn() { - string source = $$""" + const string source = """ using CommunityToolkit.WinUI; using Windows.UI.Xaml.Controls; @@ -703,7 +703,7 @@ public partial class MyControl : Control [TestMethod] public async Task InvalidPropertyNonNullableDeclarationAnalyzer_NotNullableType_NullableDisabled_DoesNotWarn() { - string source = $$""" + const string source = """ using CommunityToolkit.WinUI; using Windows.UI.Xaml.Controls; @@ -722,7 +722,7 @@ public partial class MyControl : Control [TestMethod] public async Task InvalidPropertyNonNullableDeclarationAnalyzer_NotNullableType_WithNonNullDefaultValue_DoesNotWarn() { - string source = $$""" + const string source = """ using CommunityToolkit.WinUI; using Windows.UI.Xaml.Controls; @@ -743,7 +743,7 @@ public partial class MyControl : Control [TestMethod] public async Task InvalidPropertyNonNullableDeclarationAnalyzer_NotNullableType_Warns() { - string source = $$""" + const string source = """ using CommunityToolkit.WinUI; using Windows.UI.Xaml.Controls; @@ -764,7 +764,7 @@ public partial class MyControl : Control [TestMethod] public async Task InvalidPropertyNonNullableDeclarationAnalyzer_NotNullableType_WithNullDefaultValue_Warns() { - string source = $$""" + const string source = """ using CommunityToolkit.WinUI; using Windows.UI.Xaml.Controls; @@ -896,7 +896,7 @@ public partial class MyControl : Control [TestMethod] public async Task InvalidPropertyDefaultValueTypeAnalyzer_NullValue_NonNullable_Warns() { - string source = $$""" + const string source = """ using CommunityToolkit.WinUI; using Windows.UI.Xaml.Controls; @@ -938,4 +938,221 @@ public partial class MyControl : Control await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); } + + [TestMethod] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_NoAttribute_DoesNotWarn() + { + const string source = """ + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control + { + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } + + [TestMethod] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_NoDefaultValueCallback1_DoesNotWarn() + { + const string source = """ + using CommunityToolkit.WinUI; + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control + { + [GeneratedDependencyProperty] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } + + [TestMethod] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_NoDefaultValueCallback2_DoesNotWarn() + { + const string source = """ + using CommunityToolkit.WinUI; + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control + { + [GeneratedDependencyProperty(DefaultValue = "Bob")] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } + + [TestMethod] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_NullDefaultValueCallback_DoesNotWarn() + { + const string source = """ + using CommunityToolkit.WinUI; + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control + { + [GeneratedDependencyProperty(DefaultValueCallback = null)] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } + + [TestMethod] + [DataRow("string", "string")] + [DataRow("string", "string?")] + [DataRow("string", "object")] + [DataRow("string", "object?")] + [DataRow("string?", "string")] + [DataRow("string?", "string?")] + [DataRow("int", "int")] + [DataRow("int", "object")] + [DataRow("int", "object?")] + [DataRow("int?", "int")] + [DataRow("int?", "int?")] + [DataRow("int?", "object")] + [DataRow("int?", "object?")] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_ValidDefaultValueCallback_DoesNotWarn(string propertyType, string returnType) + { + string source = $$""" + using CommunityToolkit.WinUI; + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control + { + [GeneratedDependencyProperty(DefaultValueCallback = nameof(GetDefaultValue))] + public partial {{propertyType}} {|CS9248:Value|} { get; set; } + + private static {{returnType}} GetDefaultValue() => default!; + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } + + [TestMethod] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_BothDefaultValuePropertiesSet_Warns() + { + const string source = """ + using CommunityToolkit.WinUI; + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control + { + [{|WCTDP0013:GeneratedDependencyProperty(DefaultValue = "Bob", DefaultValueCallback = nameof(GetDefaultName))|}] + public partial string? {|CS9248:Name|} { get; set; } + + private static string? GetDefaultName() => "Bob"; + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } + + [TestMethod] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_MethodNotFound_Warns() + { + const string source = """ + using CommunityToolkit.WinUI; + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control + { + [{|WCTDP0014:GeneratedDependencyProperty(DefaultValueCallback = "MissingMethod")|}] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } + + [TestMethod] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_InvalidMethod_ExplicitlyImplemented_Warns() + { + const string source = """ + using CommunityToolkit.WinUI; + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control, IGetDefaultValue + { + [{|WCTDP0014:GeneratedDependencyProperty(DefaultValueCallback = "GetDefaultValue")|}] + public partial string? {|CS9248:Name|} { get; set; } + + static string? IGetDefaultValue.GetDefaultValue() => "Bob"; + } + + public interface IGetDefaultValue + { + static abstract string? GetDefaultValue(); + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } + + [TestMethod] + [DataRow("private string? GetDefaultName()")] + [DataRow("private static string? GetDefaultName(int x)")] + [DataRow("private static int GetDefaultName()")] + [DataRow("private static int GetDefaultName(int x)")] + public async Task InvalidPropertyDefaultValueCallbackTypeAnalyzer_InvalidMethod_Warns(string methodSignature) + { + string source = $$""" + using CommunityToolkit.WinUI; + using Windows.UI.Xaml.Controls; + + #nullable enable + + namespace MyApp; + + public partial class MyControl : Control + { + [{|WCTDP0015:GeneratedDependencyProperty(DefaultValueCallback = "GetDefaultName")|}] + public partial string? {|CS9248:Name|} { get; set; } + + {{methodSignature}} => default!; + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, LanguageVersion.CSharp13); + } }