-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Upgrade xUnit #75068
Upgrade xUnit #75068
Conversation
@dotnet/roslyn-compiler, @dotnet/roslyn-ide PTAL |
@@ -160,6 +161,9 @@ public static void AreEqual<T>(T expected, T actual, string message = null, IEqu | |||
} | |||
} | |||
|
|||
public static void Equal<T>(ImmutableArray<T> expected, IEnumerable<T> actual) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change added Assert.Equals<T>(T expected, T actual)
. This created an ambiguity with the following pattern in our code base:
AssertEx.Equals([1, 2], someImmutableArray);
That call matches both the new overload and the existing overloads that have ImmutableArray<T>
as a parameter. Unfortunately, the number of optional parameters is a tie breaker in overload resolution. That meant that the new overload was winning which is undesirable. Added the overloads without optional parameters to get the desired binding behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that's the pattern, should we perhaps add AssertEx.Equals<T>(ReadOnlySpan<T>, ImmutableArray<T>)
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you help me understand how that will help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just avoid creating the immutable array for the expected value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feeds into the equality that takes IEnumerable<T>
though. I could rewrite that as well. IS that what you're suggesting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was specifically going off of the pattern you showed above, which is collectionExpression, ImmutableArray
. Is that not the pattern?
src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Server/VBCSCompilerTests/NamedPipeClientConnectionHostTests.cs
Show resolved
Hide resolved
src/Compilers/Server/VBCSCompilerTests/NamedPipeClientConnectionHostTests.cs
Show resolved
Hide resolved
@@ -160,6 +161,9 @@ public static void AreEqual<T>(T expected, T actual, string message = null, IEqu | |||
} | |||
} | |||
|
|||
public static void Equal<T>(ImmutableArray<T> expected, IEnumerable<T> actual) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that's the pattern, should we perhaps add AssertEx.Equals<T>(ReadOnlySpan<T>, ImmutableArray<T>)
instead?
@@ -61,7 +61,7 @@ static void Main(string[] args) | |||
}"); | |||
var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 245, cancellationToken: default); | |||
Assert.NotNull(terms); | |||
AssertEx.Equal(["yy", "xx"], terms); | |||
AssertEx.Equal((string[])["yy", "xx"], terms); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's going on here? not loving that these IDE tests just got a lot more verbose (which goes against moving to collection exprs in the first place) :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately xUnit introduced overloads that make these ambiguous now. I'm open to suggestions on how to approach this but it's hard to see how to reconcile the platform issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good example of where Equals(ROSpan<T> span, T[] array)
won't fix all our issues. The terms
value in this case is IList<T>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know what it was using before? Was this an IEnumerable<T>
vs IEnumerable<T>
case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is an AssertEx
helper, not an Assert
helper. What methods are actually ambiguous here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will not be helped by the new overload because the RHS is IReadOnlyList<T>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but this is not a general xUnit API, this is our own extension. So we can just add whatever helpers we need to make it work.
@@ -63,10 +63,10 @@ public async Task TestWorkspaceDiagnosticsWithRemovedAdditionalFile(bool useVSDi | |||
var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); | |||
Assert.Equal(3, results.Length); | |||
|
|||
Assert.Empty(results[0].Diagnostics); | |||
AssertEx.Empty(results[0].Diagnostics); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
curious why Assert.Empty doesn't wor khere? (or in all the other places changed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CyrusNajmabadi tried to summarize a lot of the reasons like this in the PR description + doc comments on the methods. In this case it's because xUnit NRT annotated their APIs and Empty
, Single
, etc ... do not accept null
. Given that diagnostics assigns different meaning to null
and Empty
I didn't want to make broad changes to the test implementation. Instead I added null annotated versions of the methods to AssertEx
and redirected the impacted sites to those.
@@ -2138,7 +2138,7 @@ public void RemoveAnalyzerReference() | |||
solution = solution.WithAnalyzerReferences([analyzerRef1, analyzerRef2]); | |||
|
|||
var solution2 = solution.RemoveAnalyzerReference(analyzerRef1); | |||
AssertEx.Equal([analyzerRef2], solution2.AnalyzerReferences); | |||
AssertEx.Equal((AnalyzerReference[])[analyzerRef2], solution2.AnalyzerReferences); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:'(
is assertex something owned by roslyn? can we just fixup the signatures here so this works? (or make it do a runtime check to do the right thing)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will not be fixed by the new overload because the RHS is IReadOnlyList<T>
This seems... bad :) In particular, i validated much of the collection expr work we did against the xunit api to make sure people could use collection exprs with apis like that without an issue. Could you clarify what is not ambiguous there? I'm def worried as that seems like there's a trap where collection exprs can work well with an api, but then easily change into a form that causes problems, causing source-level breaks. While the user can work around them, the code is def no longer in the desirable form. Leading to worst of both worlds :( |
Clarified with @CyrusNajmabadi offline. In particular, these ambiguities will be solved in xUnit 2.9.1, when that comes out: xunit/xunit#3021. |
Ok. Fred walked me through this. Unpleasant. but this seems like an acceptable path forward until we get upgraded to xunit 2.9.1. Would we want to just wait on htat? |
This is a CG alert lying in wait. We need to solve it now, unfortunately. |
Yeah unfortunately this is all motivated by getting us CG clean. |
"CG"? |
Could we add an assertex overload akin to the one brad is adding to 2.9.1? Then we can call that, instead of adding all the cats. |
Component governance. Basically security issues.
If there is a pattern that works better here I'm happy to add it. |
That's what I suggested here: #75068 (comment) |
I didn't follow how the linked issue is related. The first-class span feature isn't merged into main, so it cannot cause ambiguities here. |
Isn't this just an ambiguity involving collection expressions? The overload we want to add (which will also come in 2.9.1) will be seen as better than the current ambiguous overloads. |
Oh yeah, I see, the xunit fix will help with some cases that became ambiguous even without the "first-class span" feature. |
Yup yup. So my preference is that we add the overload, update our code to call that, then upgrade xunit again, then remove the overload and update again. |
Yup, first-class spans made this slightly more breaking, but it was already broken. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with review pass (iteration 5)
.editorconfig
Outdated
@@ -151,6 +151,16 @@ dotnet_public_api_analyzer.require_api_files = true | |||
# Workaround for https://github.com/dotnet/roslyn/issues/70570 | |||
dotnet_diagnostic.IDE0055.severity = warning | |||
|
|||
# Enable the xUnit analyzer rules |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment says enable, but this is only disabling things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but it's referencing an issue that says enable the rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM Thanks (iteration 5)
@jaredpar revert 97e3b and define <MicrosoftTestPlatformVersion>17.11.1</MicrosoftTestPlatformVersion>
<MicrosoftNETTestSdkVersion>$(MicrosoftTestPlatformVersion)</MicrosoftNETTestSdkVersion> To update the version of test.sdk from the outdated 17.5 that arcade ships. That fixes the language server tests (details here microsoft/vstest#10355) And hopefully does not break any other tests. |
@333fred feedback addressed and tests are passing. Can you give it another look? |
@@ -160,6 +161,12 @@ public static void AreEqual<T>(T expected, T actual, string message = null, IEqu | |||
} | |||
} | |||
|
|||
public static void Equal<T>(ReadOnlySpan<T> expected, T[] actual) => | |||
Equal<T>(expected.ToArray(), actual); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: since we know allocations are a problem in tests, perhaps instead call Equal<T>(expected, actual.AsSpan())
?
One of our NuGet audit alerts was rooted in our xUnit packages as they only had `netstandard1.3` libraries. To resolve this alert I moved us to newer versions of the package which had `netstandard2.0` libraries. Upgrading the package revealed two problems in our code base: 1. The xUnit `Assert` APIs took advantage of the `unmanaged` constraint in a fwe places. That is not supported by Visual Basic and leads to errors on import. To work around this I inserted `AssertEx` thunks that our Visual Basic layer can call through. Longer term we will need to consider adding support for the constraint ([issue](dotnet#75063)) 2. The xUnit APIs significantly increased their nullable reference type annotations. This caught a number of places where the tests were passing potentially null values to APIs that don't accept null. There were enough hits that I added `AssertEx` methods that handle the nullable case. In a few places though I just suppressed the warning. The vulnerability: GHSA-cmhx-cq75-c4mj
One of our NuGet audit alerts was rooted in our xUnit packages as they only had
netstandard1.3
libraries. To resolve this alert I moved us to newer versions of the package which hadnetstandard2.0
libraries.Upgrading the package revealed two problems in our code base:
Assert
APIs took advantage of theunmanaged
constraint in a fwe places. That is not supported by Visual Basic and leads to errors on import. To work around this I insertedAssertEx
thunks that our Visual Basic layer can call through. Longer term we will need to consider adding support for the constraint (issue)AssertEx
methods that handle the nullable case. In a few places though I just suppressed the warning.The vulnerability: GHSA-cmhx-cq75-c4mj