Files
RobustToolbox/Robust.Analyzers.Tests/ValidateMemberAnalyzerTest.cs
Tayrtahn d7abbad717 Add validation for DirtyField strings (#5713)
* Add ValidateMemberAttribute, analyzer and test

* Use attribute on DirtyFields methods

* Defer member lookup

* Additional test case

* Add support for collection types

* Poke tests

* Revert "Add support for collection types"

This reverts commit 2b8f5534bd.

* break, not continue

* Cheaper attribute check with AttributeHelper

* Clean up unused helper method

---------

Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
2025-12-17 19:32:34 +01:00

97 lines
3.7 KiB
C#

using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.ValidateMemberAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
public sealed class ValidateMemberAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<ValidateMemberAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code },
},
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.Analyzers.ValidateMemberAttribute.cs"
);
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task Test()
{
const string code = """
using System;
using Robust.Shared.Analyzers;
public sealed class TestComponent
{
public int IntField;
public bool BoolField;
}
public sealed class OtherComponent
{
public float FloatField;
public double DoubleField;
}
public sealed class TestManager
{
public static void DirtyField<T>(T comp, [ValidateMember]string fieldName) { }
public static void DirtyTwoFields<T>(T comp, [ValidateMember]string first, [ValidateMember]string second) { }
}
public sealed class TestCaller
{
public void Test()
{
var testComp = new TestComponent();
var otherComp = new OtherComponent();
TestManager.DirtyField(testComp, nameof(TestComponent.IntField));
TestManager.DirtyField(testComp, nameof(OtherComponent.FloatField));
TestManager.DirtyField(otherComp, nameof(TestComponent.IntField));
TestManager.DirtyField(otherComp, nameof(OtherComponent.FloatField));
TestManager.DirtyTwoFields(testComp, nameof(TestComponent.IntField), nameof(TestComponent.BoolField));
TestManager.DirtyTwoFields(testComp, nameof(TestComponent.IntField), nameof(OtherComponent.FloatField));
TestManager.DirtyTwoFields(testComp, nameof(OtherComponent.FloatField), nameof(OtherComponent.DoubleField));
}
}
""";
await Verifier(code,
// /0/Test0.cs(31,42): error RA0033: FloatField is not a member of TestComponent
VerifyCS.Diagnostic().WithSpan(31, 42, 31, 75).WithArguments("FloatField", "TestComponent"),
// /0/Test0.cs(33,43): error RA0033: IntField is not a member of OtherComponent
VerifyCS.Diagnostic().WithSpan(33, 43, 33, 73).WithArguments("IntField", "OtherComponent"),
// /0/Test0.cs(39,78): error RA0033: FloatField is not a member of TestComponent
VerifyCS.Diagnostic().WithSpan(39, 78, 39, 111).WithArguments("FloatField", "TestComponent"),
// /0/Test0.cs(41,46): error RA0033: FloatField is not a member of TestComponent
VerifyCS.Diagnostic().WithSpan(41, 46, 41, 79).WithArguments("FloatField", "TestComponent"),
// /0/Test0.cs(41,81): error RA0033: DoubleField is not a member of TestComponent
VerifyCS.Diagnostic().WithSpan(41, 81, 41, 115).WithArguments("DoubleField", "TestComponent")
);
}
}