using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using NUnit.Framework; using ShrinkSDK.CodeGen.Analyzers; public class AnalyzerTests { private static readonly MetadataReference[] SystemReferences = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")!).Split(Path.PathSeparator).Select(p => MetadataReference.CreateFromFile(p)).ToArray(); private static CSharpCompilation Compile(string name, string source, params MetadataReference[] references) => CSharpCompilation.Create(name, [CSharpSyntaxTree.ParseText(source)], SystemReferences.Concat(references), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); private static MetadataReference Emit(CSharpCompilation compilation) { using var stream = new MemoryStream(); var result = compilation.Emit(stream); Assert.That(result.Success, Is.True, string.Join(";", result.Diagnostics)); return MetadataReference.CreateFromImage(stream.ToArray()); } [Test] public async Task DuplicateContractsAcrossReferencedAssembliesAreErrors() { var contract = Emit(Compile("Contract", "namespace ShrinkNetwork { public class ShrinkNetworkMessageAttribute : System.Attribute { public ShrinkNetworkMessageAttribute(int opcode, string route) {} } }")); var a = Emit(Compile("A", "[ShrinkNetwork.ShrinkNetworkMessage(1, \"one\")] public class A {}".Replace("\\", ""), contract)); var b = Emit(Compile("B", "[ShrinkNetwork.ShrinkNetworkMessage(1, \"two\")] public class B {}".Replace("\\", ""), contract)); var diagnostics = await Compile("Consumer", "class Consumer {}", contract, a, b).WithAnalyzers(ImmutableArray.Create(new ShrinkCodeGenAnalyzer())).GetAnalyzerDiagnosticsAsync(); Assert.That(diagnostics.Count(d => d.Id == "SHRINK002"), Is.EqualTo(1)); } [Test] public async Task DefiniteKeyAndSubscriptionErrorsHaveStableCodes() { var compilation = Compile("Consumer", """ namespace ShrinkContext { public class ShrinkKey { public ShrinkKey(string package, string name, int major) {} } } namespace ShrinkEventBus { public interface IShrinkEvent {} public class ShrinkSubscribeAttribute : System.Attribute {} } class Consumer { object key = new ShrinkContext.ShrinkKey("", "rage", 0); [ShrinkEventBus.ShrinkSubscribe] void On(int wrong) {} } """); var diagnostics = await compilation.WithAnalyzers(ImmutableArray.Create(new ShrinkCodeGenAnalyzer())).GetAnalyzerDiagnosticsAsync(); Assert.That(diagnostics.Count(d => d.Id == "SHRINK004"), Is.EqualTo(2)); Assert.That(diagnostics.Count(d => d.Id == "SHRINK001"), Is.EqualTo(1)); } }