Files
git.stella-ops.org/src/__Analyzers/StellaOps.TestKit.Analyzers.Tests/IntentAnalyzerTests.cs

298 lines
8.1 KiB
C#

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;
/// <summary>
/// Unit tests for <see cref="IntentAnalyzer"/>.
/// </summary>
[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<IntentAnalyzer, DefaultVerifier>
{
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<IntentAnalyzer, DefaultVerifier>
{
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();
}
}