Adjust NUnit1029 to account for TestCaseSource support for params and optional arguments#958
Adjust NUnit1029 to account for TestCaseSource support for params and optional arguments#958stevenaw wants to merge 4 commits intonunit:masterfrom
Conversation
|
@manfred-brands @mikkelbu I've made this as a draft already as it's most of the way there, however I have very little experience with the analyzers and am encountering an issue. There's a failing test, |
|
Ok I think I'm making a bit more headway here. I think I've moved past my issue and I'll continue chipping away at this. |
Just when I was going to have a look, now I can just sit and wait. |
a2f6b2d to
4955308
Compare
No testcasesource warnings for optional or params are present
4955308 to
eb23a58
Compare
|
I think this is ready for review. I ended up avoiding generic method scenarios since it looks like the existing code also option to avoid explicit type inference + validation for those cases |
There was a problem hiding this comment.
Pull request overview
This PR adjusts the NUnit1029 analyzer to properly handle TestCaseSource usage with params arrays and optional parameters. The analyzer now correctly accounts for methods that can accept a variable number of arguments through params or optional parameters, preventing false positive warnings.
Key Changes:
- Modified parameter count validation to include params parameters in the analysis
- Restructured the validation logic to allow methods with optional or params parameters to accept TestCaseSource data
- Added comprehensive test coverage for params arrays, optional parameters, and generic methods
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| TestCaseSourceUsesStringAnalyzer.cs | Updated parameter counting logic to include params parameters and restructured validation to handle optional/params scenarios |
| TestCaseSourceUsesStringAnalyzerTests.cs | Added four new test cases covering params arrays, generic methods, and optional parameters |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); | ||
| } | ||
|
|
||
| [TestCaseSource(↓nameof(TestData))] | ||
| public void ShortName(int a = 1, int b = 2) | ||
| { | ||
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); |
There was a problem hiding this comment.
Variable 'x' does not exist in this scope. The parameters are named 'a' and 'b', not 'x'.
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); | |
| } | |
| [TestCaseSource(↓nameof(TestData))] | |
| public void ShortName(int a = 1, int b = 2) | |
| { | |
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); | |
| Assert.That(a, Is.GreaterThanOrEqualTo(0)); | |
| Assert.That(b, Is.GreaterThanOrEqualTo(0)); | |
| } | |
| [TestCaseSource(↓nameof(TestData))] | |
| public void ShortName(int a = 1, int b = 2) | |
| { | |
| Assert.That(a, Is.GreaterThanOrEqualTo(0)); | |
| Assert.That(b, Is.GreaterThanOrEqualTo(0)); |
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); | ||
| } | ||
|
|
||
| [TestCaseSource(↓nameof(TestData))] | ||
| public void ShortName(int a = 1, int b = 2) | ||
| { | ||
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); |
There was a problem hiding this comment.
Variable 'x' does not exist in this scope. The parameters are named 'a' and 'b', not 'x'.
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); | |
| } | |
| [TestCaseSource(↓nameof(TestData))] | |
| public void ShortName(int a = 1, int b = 2) | |
| { | |
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); | |
| Assert.Pass(); | |
| } | |
| [TestCaseSource(↓nameof(TestData))] | |
| public void ShortName(int a = 1, int b = 2) | |
| { | |
| Assert.Pass(); |
manfred-brands
left a comment
There was a problem hiding this comment.
I had some small remarks on the use of RoslynAssert.
Your example test code didn't get to the analyzer as there were compile errors.
I pushed the necessary fixes up, but the underlying test code doesn't work when run in NUnit 4.4.0.
I'm trying it now on master and see if it is related to the bug you raised
| [TestCaseSource(↓nameof(TestData))] | ||
| public void ShortName(int a, int b = 2) | ||
| { | ||
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); |
There was a problem hiding this comment.
I'm surprised this compiles during testing as there is no x variable.
| [TestCaseSource(↓nameof(TestData))] | ||
| public void ShortName(int a = 1, int b = 2) | ||
| { | ||
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); | ||
| } |
There was a problem hiding this comment.
Duplicate function with same name and parameters. should also not compile.
| } | ||
| }", additionalUsings: "using System.Collections.Generic;"); | ||
|
|
||
| RoslynAssert.NoAnalyzerDiagnostics(analyzer, testCode); |
There was a problem hiding this comment.
This might explain it.
I thought we always used RoslynAssert.Valid to ensure the code is correct.
| [TestFixture] | ||
| public class NoWarningWhenNumberOfParametersOfTestWillFitIntoOptionalParams | ||
| { | ||
| [TestCaseSource(↓nameof(TestData))] |
There was a problem hiding this comment.
If the code is valid, there should be no ↓ character which otherwise indicates the expect error location.
| [TestFixture] | ||
| public class NoWarningWhenNumberOfParametersOfTestWillFitIntoParamsArrayForGenericMethod | ||
| { | ||
| [TestCaseSource(↓nameof(TestData))] | ||
| public void ShortName<T>(params T[] x) | ||
| { | ||
| Assert.That(x.Length, Is.GreaterThanOrEqualTo(0)); | ||
| } | ||
|
|
||
| static IEnumerable<int> TestData() | ||
| { | ||
| for (int i = 1; i <= 3; i++) | ||
| { | ||
| yield return i; | ||
| } | ||
| } | ||
| }", additionalUsings: "using System.Collections.Generic;"); |
There was a problem hiding this comment.
NUnit itself fails to run this test with Unable to determine type arguments for method.
I always extract the code from the string to see if NUnit will actually run it.
| [TestCaseSource(↓nameof(TestData))] | ||
| public static void TestLotsOfNonRequiredParams(params int[] z) | ||
| { | ||
| Assert.That(z, Is.Not.Default); |
There was a problem hiding this comment.
Default does not exist in NUnit 3.14. The analyzer test run against both 3.14 and 4.4
Also Default for an array is the same as Null, but a params array should never be null.
|
Thanks @manfred-brands ! Appreciate your fixes here. I mentioned that I am new on the analyzer side.
I hadn't realized this was the case but I can see now why we would want to. I suppose my using |
No. Only the tests that have Please revert your last commit! |
23522b6 to
3028d64
Compare
|
Done. Sorry about that, thanks for the clarification |
|
@manfred-brands Thanks for the review here. |
| { | ||
| // more than one required parameter is always a mismatch | ||
| // zero parameters of any kind is also a mismatch | ||
| context.ReportDiagnostic(Diagnostic.Create( |
There was a problem hiding this comment.
I don't see a new test case that validates this.
There was a problem hiding this comment.
Thanks @manfred-brands
Do you mean this comment?
// more than one required parameter is always a mismatch
// zero parameters of any kind is also a mismatch
That comment was added by me to clarify the existing logic for myself prior to and after refactoring the logic a bit. I had thought they're already covered through existing tests here:
Unless, would you prefer additional cases with 0 and two required args which also include optional args in the signature like this?
[TestCaseSource(↓nameof(TestData))]
public void ShortName(int x, int y, int z = 2)|
Coming back to this after the 4.5 release of the framework. |
Sorry about the slow response. I think I'll have time to look at it tonight. |
|
Thanks, and that's alright 🙂 I think we decided somewhere that we wanted to wait to release this until sometime after 4.5 of the framework went out. |
Fixes #957