using System.Collections.Immutable; using FluentAssertions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; using Xunit; namespace StellaOps.TestKit.Analyzers.Tests; /// /// Unit tests for . /// [Trait("Category", "Unit")] public sealed class IntentAnalyzerTests { [Fact] public async Task TrivialTest_NoWarning() { var code = """ using Xunit; public class MyTests { [Fact] public void TrivialTest() { Assert.True(true); } } """; await VerifyNoWarningsAsync(code); } [Fact] public async Task NonTrivialTest_WithIntent_NoWarning() { var code = """ using Xunit; public class MyTests { [Fact] [Intent("Safety", "Test security")] public void NonTrivialTest() { var a = 1; var b = 2; var c = 3; var d = 4; var e = 5; var f = 6; Assert.Equal(21, a + b + c + d + e + f); } } [System.AttributeUsage(System.AttributeTargets.Method)] public class IntentAttribute : System.Attribute { public IntentAttribute(string intent, string rationale = "") { } } """; await VerifyNoWarningsAsync(code); } [Fact] public async Task NonTrivialTest_WithTraitIntent_NoWarning() { var code = """ using Xunit; public class MyTests { [Fact] [Trait("Intent", "Safety")] public void NonTrivialTest() { var a = 1; var b = 2; var c = 3; var d = 4; var e = 5; var f = 6; Assert.Equal(21, a + b + c + d + e + f); } } """; await VerifyNoWarningsAsync(code); } [Fact] public async Task NonTrivialTest_WithIntentExempt_NoWarning() { var code = """ using Xunit; public class MyTests { [Fact] [Trait("IntentExempt", "true")] public void NonTrivialTest() { var a = 1; var b = 2; var c = 3; var d = 4; var e = 5; var f = 6; Assert.Equal(21, a + b + c + d + e + f); } } """; await VerifyNoWarningsAsync(code); } [Fact] public async Task NonTrivialTest_WithoutIntent_Warning() { var code = """ using Xunit; public class MyTests { [Fact] public void {|#0:NonTrivialTest|}() { var a = 1; var b = 2; var c = 3; var d = 4; var e = 5; var f = 6; Assert.Equal(21, a + b + c + d + e + f); } } """; var expected = new DiagnosticResult(IntentAnalyzer.MissingIntentDiagnosticId, DiagnosticSeverity.Warning) .WithLocation(0) .WithArguments("NonTrivialTest"); await VerifyWarningAsync(code, expected); } [Fact] public async Task MultipleAssertions_WithoutIntent_Warning() { var code = """ using Xunit; public class MyTests { [Fact] public void {|#0:MultiAssertTest|}() { var result = 42; Assert.NotNull(result); Assert.Equal(42, result); } } """; var expected = new DiagnosticResult(IntentAnalyzer.MissingIntentDiagnosticId, DiagnosticSeverity.Warning) .WithLocation(0) .WithArguments("MultiAssertTest"); await VerifyWarningAsync(code, expected); } [Fact] public async Task IntentWithoutRationale_Info() { var code = """ using Xunit; public class MyTests { [Fact] [Intent("Safety")] public void TestWithIntent() { var a = 1; var b = 2; var c = 3; var d = 4; var e = 5; var f = 6; Assert.Equal(21, a + b + c + d + e + f); } } [System.AttributeUsage(System.AttributeTargets.Method)] public class IntentAttribute : System.Attribute { public IntentAttribute(string intent, string rationale = "") { } } """; var expected = new DiagnosticResult(IntentAnalyzer.MissingRationaleDiagnosticId, DiagnosticSeverity.Info) .WithSpan(6, 6, 6, 22) .WithArguments("TestWithIntent"); await VerifyWarningAsync(code, expected); } [Fact] public async Task IntentWithRationale_NoInfo() { var code = """ using Xunit; public class MyTests { [Fact] [Intent("Safety", "Security requirement per OWASP")] public void TestWithIntent() { var a = 1; var b = 2; var c = 3; var d = 4; var e = 5; var f = 6; Assert.Equal(21, a + b + c + d + e + f); } } [System.AttributeUsage(System.AttributeTargets.Method)] public class IntentAttribute : System.Attribute { public IntentAttribute(string intent, string rationale = "") { } } """; await VerifyNoWarningsAsync(code); } [Fact] public async Task NonTestMethod_NoWarning() { var code = """ public class MyClass { public void NonTestMethod() { var a = 1; var b = 2; var c = 3; var d = 4; var e = 5; var f = 6; System.Console.WriteLine(a + b + c + d + e + f); } } """; await VerifyNoWarningsAsync(code); } private static async Task VerifyNoWarningsAsync(string code) { var test = new CSharpAnalyzerTest { TestCode = code, ReferenceAssemblies = ReferenceAssemblies.Net.Net80 }; test.TestState.AdditionalReferences.Add( MetadataReference.CreateFromFile(typeof(Xunit.FactAttribute).Assembly.Location)); test.TestState.AdditionalReferences.Add( MetadataReference.CreateFromFile(typeof(Xunit.Assert).Assembly.Location)); await test.RunAsync(); } private static async Task VerifyWarningAsync(string code, DiagnosticResult expected) { var test = new CSharpAnalyzerTest { TestCode = code, ReferenceAssemblies = ReferenceAssemblies.Net.Net80, ExpectedDiagnostics = { expected } }; test.TestState.AdditionalReferences.Add( MetadataReference.CreateFromFile(typeof(Xunit.FactAttribute).Assembly.Location)); test.TestState.AdditionalReferences.Add( MetadataReference.CreateFromFile(typeof(Xunit.Assert).Assembly.Location)); await test.RunAsync(); } }