298 lines
8.1 KiB
C#
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();
|
|
}
|
|
}
|