// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; #if NET472 using System.ComponentModel.DataAnnotations; #endif namespace CommunityToolkit.Mvvm.SourceGenerators.UnitTests.Helpers; /// /// A custom that uses a specific C# language version to parse code. /// /// The type of the analyzer to test. internal sealed class CSharpAnalyzerWithLanguageVersionTest : CSharpAnalyzerTest where TAnalyzer : DiagnosticAnalyzer, new() { /// /// The C# language version to use to parse code. /// private readonly LanguageVersion languageVersion; /// /// Creates a new instance with the specified parameters. /// /// The C# language version to use to parse code. private CSharpAnalyzerWithLanguageVersionTest(LanguageVersion languageVersion) { this.languageVersion = languageVersion; } /// protected override ParseOptions CreateParseOptions() { return new CSharpParseOptions(this.languageVersion, DocumentationMode.Diagnose); } /// /// The language version to use to run the test. public static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion, params DiagnosticResult[] expected) { CSharpAnalyzerWithLanguageVersionTest test = new(languageVersion) { TestCode = source }; #if NET8_0_OR_GREATER test.TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net80; #elif NET6_0_OR_GREATER test.TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net60; #else test.TestState.ReferenceAssemblies = ReferenceAssemblies.NetFramework.Net472.Default; test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(RequiredAttribute).Assembly.Location)); #endif test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ObservableObject).Assembly.Location)); test.SolutionTransforms.Add((solution, projectId) => solution.AddAnalyzerConfigDocument(DocumentId.CreateNewId(projectId), "UseMarshalType.editorconfig", SourceText.From(""" is_global = true build_property.LibraryImportGenerator_UseMarshalType = true """, Encoding.UTF8), filePath: "/UseMarshalType.editorconfig")); test.ExpectedDiagnostics.AddRange(expected); return test.RunAsync(CancellationToken.None); } /// /// The language version to use to run the test. public static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion, (string PropertyName, object PropertyValue)[] editorconfig) { CSharpAnalyzerWithLanguageVersionTest test = new(languageVersion) { TestCode = source }; #if NET8_0_OR_GREATER test.TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net80; #elif NET6_0_OR_GREATER test.TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net60; #else test.TestState.ReferenceAssemblies = ReferenceAssemblies.NetFramework.Net472.Default; test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(RequiredAttribute).Assembly.Location)); #endif test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ObservableObject).Assembly.Location)); // Add any editorconfig properties, if present if (editorconfig.Length > 0) { test.SolutionTransforms.Add((solution, projectId) => solution.AddAnalyzerConfigDocument( DocumentId.CreateNewId(projectId), "MvvmToolkitAnalyzers.editorconfig", SourceText.From($""" is_global = true {string.Join(Environment.NewLine, editorconfig.Select(static p => $"build_property.{p.PropertyName} = {p.PropertyValue}"))} """, Encoding.UTF8), filePath: "/MvvmToolkitAnalyzers.editorconfig")); } return test.RunAsync(CancellationToken.None); } }