172 lines
5.5 KiB
C#
172 lines
5.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using Microsoft.CodeAnalysis.Diagnostics;
|
|
using StellaOps.TestKit;
|
|
|
|
namespace StellaOps.Concelier.Merge.Analyzers.Tests;
|
|
|
|
public sealed class MergeUsageAnalyzerTests
|
|
{
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task ReportsDiagnostic_ForAdvisoryMergeServiceInstantiation()
|
|
{
|
|
const string source = """
|
|
using StellaOps.Concelier.Merge.Services;
|
|
|
|
namespace Sample.App;
|
|
|
|
public sealed class Demo
|
|
{
|
|
public void Run()
|
|
{
|
|
var merge = new AdvisoryMergeService();
|
|
}
|
|
}
|
|
""";
|
|
|
|
var diagnostics = await AnalyzeAsync(source, "Sample.App");
|
|
Assert.Contains(diagnostics, d => d.Id == MergeUsageAnalyzer.DiagnosticId && d.GetMessage().Contains("AdvisoryMergeService", StringComparison.Ordinal));
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task ReportsDiagnostic_ForAddMergeModuleInvocation()
|
|
{
|
|
const string source = """
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using StellaOps.Concelier.Merge;
|
|
|
|
namespace Sample.Services;
|
|
|
|
public static class Installer
|
|
{
|
|
public static void Configure(IServiceCollection services, IConfiguration configuration)
|
|
{
|
|
services.AddMergeModule(configuration);
|
|
}
|
|
}
|
|
""";
|
|
|
|
var diagnostics = await AnalyzeAsync(source, "Sample.Services");
|
|
Assert.Contains(diagnostics, d => d.Id == MergeUsageAnalyzer.DiagnosticId && d.GetMessage().Contains("AddMergeModule", StringComparison.Ordinal));
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task ReportsDiagnostic_ForFieldDeclaration()
|
|
{
|
|
const string source = """
|
|
using StellaOps.Concelier.Merge.Services;
|
|
|
|
namespace Sample.Library;
|
|
|
|
public sealed class Demo
|
|
{
|
|
private AdvisoryMergeService? _mergeService;
|
|
}
|
|
""";
|
|
|
|
var diagnostics = await AnalyzeAsync(source, "Sample.Library");
|
|
Assert.Contains(diagnostics, d => d.Id == MergeUsageAnalyzer.DiagnosticId);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task DoesNotReportDiagnostic_InsideMergeAssembly()
|
|
{
|
|
const string source = """
|
|
using StellaOps.Concelier.Merge.Services;
|
|
|
|
namespace StellaOps.Concelier.Merge.Internal;
|
|
|
|
internal static class MergeDiagnostics
|
|
{
|
|
public static AdvisoryMergeService Create() => new AdvisoryMergeService();
|
|
}
|
|
""";
|
|
|
|
var diagnostics = await AnalyzeAsync(source, "StellaOps.Concelier.Merge");
|
|
Assert.DoesNotContain(diagnostics, d => d.Id == MergeUsageAnalyzer.DiagnosticId);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task ReportsDiagnostic_ForTypeOfUsage()
|
|
{
|
|
const string source = """
|
|
using System;
|
|
using StellaOps.Concelier.Merge.Services;
|
|
|
|
namespace Sample.TypeOf;
|
|
|
|
public static class Demo
|
|
{
|
|
public static Type TargetType => typeof(AdvisoryMergeService);
|
|
}
|
|
""";
|
|
|
|
var diagnostics = await AnalyzeAsync(source, "Sample.TypeOf");
|
|
Assert.Contains(diagnostics, d => d.Id == MergeUsageAnalyzer.DiagnosticId);
|
|
}
|
|
|
|
private static async Task<ImmutableArray<Diagnostic>> AnalyzeAsync(string source, string assemblyName)
|
|
{
|
|
var compilation = CSharpCompilation.Create(
|
|
assemblyName,
|
|
new[]
|
|
{
|
|
CSharpSyntaxTree.ParseText(source),
|
|
CSharpSyntaxTree.ParseText(Stubs)
|
|
},
|
|
CreateMetadataReferences(),
|
|
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
|
|
|
|
var analyzer = new MergeUsageAnalyzer();
|
|
var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create<DiagnosticAnalyzer>(analyzer));
|
|
return await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync();
|
|
}
|
|
|
|
private static IEnumerable<MetadataReference> CreateMetadataReferences()
|
|
{
|
|
yield return MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location);
|
|
yield return MetadataReference.CreateFromFile(typeof(Enumerable).GetTypeInfo().Assembly.Location);
|
|
}
|
|
|
|
private const string Stubs = """
|
|
namespace Microsoft.Extensions.DependencyInjection
|
|
{
|
|
public interface IServiceCollection { }
|
|
}
|
|
|
|
namespace Microsoft.Extensions.Configuration
|
|
{
|
|
public interface IConfiguration { }
|
|
}
|
|
|
|
namespace StellaOps.Concelier.Merge.Services
|
|
{
|
|
public sealed class AdvisoryMergeService { }
|
|
}
|
|
|
|
namespace StellaOps.Concelier.Merge
|
|
{
|
|
public static class MergeServiceCollectionExtensions
|
|
{
|
|
public static void AddMergeModule(
|
|
this Microsoft.Extensions.DependencyInjection.IServiceCollection services,
|
|
Microsoft.Extensions.Configuration.IConfiguration configuration)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
""";
|
|
}
|