Skip to content

Commit f2ad339

Browse files
committed
xunit/xunit#3346: Update xUnit2002 and xUnit2024 to support unsafe pointers
1 parent e35b6e4 commit f2ad339

14 files changed

+142
-19
lines changed

src/Directory.Build.props

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,11 @@
6060
<Choose>
6161
<When Condition=" $(MSBuildProjectName.Contains('.tests')) ">
6262
<PropertyGroup>
63+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
6364
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
6465
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
6566
<CopyNuGetImplementations>true</CopyNuGetImplementations>
66-
<DefineConstants>$(DefineConstants);XUNIT_VISIBILITY_INTERNAL;XUNIT_NULLABLE</DefineConstants>
67+
<DefineConstants>$(DefineConstants);XUNIT_NULLABLE;XUNIT_POINTERS;XUNIT_VISIBILITY_INTERNAL</DefineConstants>
6768
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
6869
<GenerateDependencyFile>true</GenerateDependencyFile>
6970
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
@@ -78,8 +79,8 @@
7879
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
7980
<PackageReference Include="NSubstitute" Version="5.3.0" />
8081
<PackageReference Include="System.ValueTuple" Version="4.6.1" />
81-
<PackageReference Include="xunit.v3.assert.source" Version="3.0.0" />
82-
<PackageReference Include="xunit.v3.core" Version="3.0.0" />
82+
<PackageReference Include="xunit.v3.assert.source" Version="3.0.1-pre.3" />
83+
<PackageReference Include="xunit.v3.core" Version="3.0.1-pre.3" />
8384
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.2" />
8485
</ItemGroup>
8586

src/xunit.analyzers.tests/Analyzers/X2000/AssertNullShouldNotBeCalledOnValueTypesTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,26 @@ void TestMethod() {{
5959
await Verify.VerifyAnalyzer(source);
6060
}
6161

62+
[Fact]
63+
public async Task ForPointerType_v3_DoesNotTrigger()
64+
{
65+
var source = /* lang=c#-test */ """
66+
using Xunit;
67+
68+
class TestClass {
69+
unsafe void TestMethod() {
70+
var value = 42;
71+
var ptr = &value;
72+
73+
Assert.Null(ptr);
74+
Assert.NotNull(ptr);
75+
}
76+
}
77+
""";
78+
79+
await Verify.VerifyAnalyzerV3(source);
80+
}
81+
6282
[Theory]
6383
[MemberData(nameof(Methods))]
6484
public async Task ForClassConstrainedGenericTypes_DoesNotTrigger(string method)

src/xunit.analyzers.tests/Analyzers/X2000/BooleanAssertsShouldNotBeUsedForSimpleEqualityCheckTests.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System.Threading.Tasks;
2+
using Microsoft.CodeAnalysis;
23
using Microsoft.CodeAnalysis.CSharp;
34
using Xunit;
45
using Xunit.Analyzers;
56
using Verify = CSharpVerifier<Xunit.Analyzers.BooleanAssertsShouldNotBeUsedForSimpleEqualityCheck>;
7+
using Verify_v3_Pre_301 = CSharpVerifier<BooleanAssertsShouldNotBeUsedForSimpleEqualityCheckTests.Analyzer_v3_Pre301>;
68

79
public class BooleanAssertsShouldNotBeUsedForSimpleEqualityCheckTests
810
{
@@ -173,6 +175,73 @@ public void TestMethod() {{
173175

174176
await Verify.VerifyAnalyzer(LanguageVersion.CSharp8, source, expected);
175177
}
178+
179+
[Fact]
180+
public async Task ComparingAgainstNullPointer_DoesNotTrigger()
181+
{
182+
var source = /* lang=c#-test */ """
183+
using Xunit;
184+
185+
public class TestClass {
186+
public unsafe void TestMethod() {
187+
var value = 42;
188+
var ptr = &value;
189+
190+
Assert.True(ptr == null);
191+
Assert.True(null == ptr);
192+
Assert.True(ptr != null);
193+
Assert.True(null != ptr);
194+
195+
Assert.False(ptr == null);
196+
Assert.False(null == ptr);
197+
Assert.False(ptr != null);
198+
Assert.False(null != ptr);
199+
}
200+
}
201+
""";
202+
203+
await Verify.VerifyAnalyzerV2(source);
204+
await Verify_v3_Pre_301.VerifyAnalyzerV3(source);
205+
}
206+
207+
[Fact]
208+
public async Task ComparingAgainstNullPointer_v3_301_Triggers()
209+
{
210+
var source = /* lang=c#-test */ """
211+
using Xunit;
212+
213+
public class TestClass {
214+
public unsafe void TestMethod() {
215+
var value = 42;
216+
var ptr = &value;
217+
218+
{|#0:Assert.True(ptr == null)|};
219+
{|#1:Assert.True(null == ptr)|};
220+
{|#2:Assert.True(ptr != null)|};
221+
{|#3:Assert.True(null != ptr)|};
222+
223+
{|#10:Assert.False(ptr == null)|};
224+
{|#11:Assert.False(null == ptr)|};
225+
{|#12:Assert.False(ptr != null)|};
226+
{|#13:Assert.False(null != ptr)|};
227+
}
228+
}
229+
""";
230+
var expected = new[]
231+
{
232+
Verify.Diagnostic("xUnit2024").WithLocation(0).WithArguments("True", "Null"),
233+
Verify.Diagnostic("xUnit2024").WithLocation(1).WithArguments("True", "Null"),
234+
Verify.Diagnostic("xUnit2024").WithLocation(2).WithArguments("True", "NotNull"),
235+
Verify.Diagnostic("xUnit2024").WithLocation(3).WithArguments("True", "NotNull"),
236+
237+
Verify.Diagnostic("xUnit2024").WithLocation(10).WithArguments("False", "NotNull"),
238+
Verify.Diagnostic("xUnit2024").WithLocation(11).WithArguments("False", "NotNull"),
239+
Verify.Diagnostic("xUnit2024").WithLocation(12).WithArguments("False", "Null"),
240+
Verify.Diagnostic("xUnit2024").WithLocation(13).WithArguments("False", "Null"),
241+
};
242+
243+
await Verify.VerifyAnalyzerV3(source, expected);
244+
}
176245
}
177246

178247
public class X2025_BooleanAssertionCanBeSimplified
@@ -216,4 +285,10 @@ void TestMethod() {{
216285
await Verify.VerifyAnalyzer(source, expected);
217286
}
218287
}
288+
289+
public class Analyzer_v3_Pre301 : BooleanAssertsShouldNotBeUsedForSimpleEqualityCheck
290+
{
291+
protected override XunitContext CreateXunitContext(Compilation compilation) =>
292+
XunitContext.ForV3(compilation, new(3, 0, 0));
293+
}
219294
}

src/xunit.analyzers.tests/Utility/CodeAnalyzerHelper.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ static CodeAnalyzerHelper()
6161
new PackageIdentity("Microsoft.Extensions.Primitives", "8.0.0"),
6262
new PackageIdentity("System.Threading.Tasks.Extensions", "4.5.4"),
6363
new PackageIdentity("System.Text.Json", "8.0.0"),
64-
new PackageIdentity("xunit.v3.assert", "3.0.0"),
65-
new PackageIdentity("xunit.v3.common", "3.0.0"),
66-
new PackageIdentity("xunit.v3.extensibility.core", "3.0.0"),
67-
new PackageIdentity("xunit.v3.runner.common", "3.0.0")
64+
new PackageIdentity("xunit.v3.assert", "3.0.1-pre.3"),
65+
new PackageIdentity("xunit.v3.common", "3.0.1-pre.3"),
66+
new PackageIdentity("xunit.v3.extensibility.core", "3.0.1-pre.3"),
67+
new PackageIdentity("xunit.v3.runner.common", "3.0.1-pre.3")
6868
)
6969
);
7070

@@ -74,8 +74,8 @@ static CodeAnalyzerHelper()
7474
new PackageIdentity("Microsoft.Extensions.Primitives", "8.0.0"),
7575
new PackageIdentity("System.Threading.Tasks.Extensions", "4.5.4"),
7676
new PackageIdentity("System.Text.Json", "8.0.0"),
77-
new PackageIdentity("xunit.v3.common", "3.0.0"),
78-
new PackageIdentity("xunit.v3.runner.utility", "3.0.0")
77+
new PackageIdentity("xunit.v3.common", "3.0.1-pre.3"),
78+
new PackageIdentity("xunit.v3.runner.utility", "3.0.1-pre.3")
7979
)
8080
);
8181
}

src/xunit.analyzers.tests/xunit.analyzers.tests.csproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
<PackageDownload Include="xunit.extensibility.execution" Version="[2.9.3-pre.4]" />
2424
<PackageDownload Include="xunit.runner.utility" Version="[2.9.3-pre.4]" />
2525

26-
<PackageDownload Include="xunit.v3.assert" Version="[3.0.0]" />
27-
<PackageDownload Include="xunit.v3.common" Version="[3.0.0]" />
28-
<PackageDownload Include="xunit.v3.extensibility.core" Version="[3.0.0]" />
29-
<PackageDownload Include="xunit.v3.runner.common" Version="[3.0.0]" />
30-
<PackageDownload Include="xunit.v3.runner.utility" Version="[3.0.0]" />
26+
<PackageDownload Include="xunit.v3.assert" Version="[3.0.1-pre.3]" />
27+
<PackageDownload Include="xunit.v3.common" Version="[3.0.1-pre.3]" />
28+
<PackageDownload Include="xunit.v3.extensibility.core" Version="[3.0.1-pre.3]" />
29+
<PackageDownload Include="xunit.v3.runner.common" Version="[3.0.1-pre.3]" />
30+
<PackageDownload Include="xunit.v3.runner.utility" Version="[3.0.1-pre.3]" />
3131

3232
<!-- Download packages referenced by CodeAnalysisNetAnalyzers -->
3333
<PackageDownload Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="[9.0.0]" />

src/xunit.analyzers/Utility/CodeAnalysisExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ public static (bool isInTestMethod, IOperation? lambdaOwner) IsInTestMethod(
133133
return (false, null);
134134
}
135135

136+
public static bool IsPointer(
137+
this ExpressionSyntax expression,
138+
SemanticModel? semanticModel) =>
139+
semanticModel?.GetTypeInfo(expression).Type?.TypeKind == TypeKind.Pointer;
140+
136141
public static bool IsTestClass(
137142
this ITypeSymbol? type,
138143
XunitContext xunitContext,

src/xunit.analyzers/Utility/EmptyAssertContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public class EmptyAssertContext : IAssertContext
1414

1515
public bool SupportsAssertFail => false;
1616

17+
public bool SupportsAssertNullWithPointers => false;
18+
1719
public bool SupportsInexactTypeAssertions => false;
1820

1921
public Version Version { get; } = new();

src/xunit.analyzers/Utility/IAssertContext.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ public interface IAssertContext
1515
/// </summary>
1616
bool SupportsAssertFail { get; }
1717

18+
/// <summary>
19+
/// Gets a flag indicating whether <c>Assert.Null</c> and <c>Assert.NotNull</c> supports
20+
/// unsafe pointers.
21+
/// </summary>
22+
bool SupportsAssertNullWithPointers { get; }
23+
1824
/// <summary>
1925
/// Gets a flag indicating whether <c>Assert.IsType</c> and <c>Assert.IsNotType</c>
2026
/// support inexact matches (soft-deprecating <c>Assert.IsAssignableFrom</c>

src/xunit.analyzers/Utility/V2AssertContext.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public class V2AssertContext : IAssertContext
2828
public bool SupportsAssertFail =>
2929
Version >= Version_2_5_0;
3030

31+
/// <inheritdoc/>
32+
public bool SupportsAssertNullWithPointers =>
33+
false;
34+
3135
/// <inheritdoc/>
3236
public bool SupportsInexactTypeAssertions =>
3337
Version >= Version_2_9_3;

src/xunit.analyzers/Utility/V3AssertContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace Xunit.Analyzers;
77
public class V3AssertContext : IAssertContext
88
{
99
internal static readonly Version Version_0_6_0 = new("0.6.0");
10+
internal static readonly Version Version_3_0_1 = new("3.0.1");
1011

1112
readonly Lazy<INamedTypeSymbol?> lazyAssertType;
1213

@@ -26,6 +27,10 @@ public class V3AssertContext : IAssertContext
2627
/// <inheritdoc/>
2728
public bool SupportsAssertFail => true;
2829

30+
/// <inheritdoc/>
31+
public bool SupportsAssertNullWithPointers =>
32+
Version >= Version_3_0_1;
33+
2934
/// <inheritdoc/>
3035
public bool SupportsInexactTypeAssertions =>
3136
Version >= Version_0_6_0;

0 commit comments

Comments
 (0)