// 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);
}
}