Skip to content

Commit 536cd6a

Browse files
committed
Add SA1139 tests for literals with digit separators
1 parent 250090b commit 536cd6a

1 file changed

Lines changed: 252 additions & 0 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/ReadabilityRules/SA1139CSharp7UnitTests.cs

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,261 @@
33

44
namespace StyleCop.Analyzers.Test.CSharp7.ReadabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
68
using StyleCop.Analyzers.Test.ReadabilityRules;
9+
using TestHelper;
10+
using Xunit;
711

812
public class SA1139CSharp7UnitTests : SA1139UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that using literals with digit separators does not produce diagnostic.
16+
/// </summary>
17+
/// <param name="literalType">The type which is checked.</param>
18+
/// <param name="literalSuffix">The literal's suffix.</param>
19+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
20+
[Theory]
21+
[InlineData("int", "")]
22+
[InlineData("long", "L")]
23+
[InlineData("long", "l")]
24+
[InlineData("ulong", "UL")]
25+
[InlineData("ulong", "Ul")]
26+
[InlineData("ulong", "uL")]
27+
[InlineData("ulong", "ul")]
28+
[InlineData("ulong", "LU")]
29+
[InlineData("ulong", "lU")]
30+
[InlineData("ulong", "Lu")]
31+
[InlineData("ulong", "lu")]
32+
[InlineData("uint", "U")]
33+
[InlineData("uint", "u")]
34+
[InlineData("float", "F")]
35+
[InlineData("float", "f")]
36+
[InlineData("double", "D")]
37+
[InlineData("double", "d")]
38+
[InlineData("decimal", "M")]
39+
[InlineData("decimal", "m")]
40+
public async Task TestUsingLiteralsWithSeparatorsDoesNotProduceDiagnosticAsync(string literalType, string literalSuffix)
41+
{
42+
var testCode = $@"
43+
class ClassName
44+
{{
45+
{literalType} x = 0_1{literalSuffix};
46+
47+
public void Method()
48+
{{
49+
var x = 1{literalSuffix};
50+
}}
51+
}}
52+
";
53+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
54+
}
55+
56+
/// <summary>
57+
/// Verifies that using casts on literals with digit separators produces diagnostic and correct code fix.
58+
/// </summary>
59+
/// <param name="literalType">The type which is checked.</param>
60+
/// <param name="castedLiteral">The literal that is casted.</param>
61+
/// <param name="correctLiteral">A literal representing result of a cast.</param>
62+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
63+
[Theory]
64+
[InlineData("long", "0_1", "0_1L")]
65+
[InlineData("long", "+0_1", "+0_1L")]
66+
[InlineData("long", "-0_1", "-0_1L")]
67+
[InlineData("ulong", "0_1", "0_1UL")]
68+
[InlineData("ulong", "+0_1", "+0_1UL")]
69+
[InlineData("uint", "0_1", "0_1U")]
70+
[InlineData("uint", "+0_1", "+0_1U")]
71+
[InlineData("float", "0_1", "0_1F")]
72+
[InlineData("float", "+0_1", "+0_1F")]
73+
[InlineData("float", "-0_1", "-0_1F")]
74+
[InlineData("float", "0_1.0", "0_1.0F")]
75+
[InlineData("float", "-0_1e-10", "-0_1e-10F")]
76+
[InlineData("double", "0_1", "0_1D")]
77+
[InlineData("double", "+0_1", "+0_1D")]
78+
[InlineData("double", "-0_1", "-0_1D")]
79+
[InlineData("decimal", "0_1", "0_1M")]
80+
[InlineData("decimal", "+0_1", "+0_1M")]
81+
[InlineData("decimal", "-0_1", "-0_1M")]
82+
[InlineData("ulong", "0_1L", "0_1UL")]
83+
[InlineData("ulong", "+0_1L", "+0_1UL")]
84+
[InlineData("ulong", "0_1l", "0_1UL")]
85+
[InlineData("ulong", "0_1U", "0_1UL")]
86+
[InlineData("ulong", "0_1u", "0_1UL")]
87+
public async Task TestUsingCastsWithSeparatorsProducesDiagnosticAndCorrectCodefixAsync(string literalType, string castedLiteral, string correctLiteral)
88+
{
89+
var testCode = $@"
90+
class ClassName
91+
{{
92+
{literalType} x = ({literalType}){castedLiteral};
93+
94+
public object Method()
95+
{{
96+
var y = ({literalType}){castedLiteral};
97+
return y;
98+
}}
99+
}}
100+
";
101+
102+
var fixedCode = $@"
103+
class ClassName
104+
{{
105+
{literalType} x = {correctLiteral};
106+
107+
public object Method()
108+
{{
109+
var y = {correctLiteral};
110+
return y;
111+
}}
112+
}}
113+
";
114+
DiagnosticResult[] expectedDiagnosticResult =
115+
{
116+
this.CSharpDiagnostic().WithLocation(4, 10 + literalType.Length),
117+
this.CSharpDiagnostic().WithLocation(8, 17),
118+
};
119+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnosticResult, CancellationToken.None).ConfigureAwait(false);
120+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
121+
}
122+
123+
/// <summary>
124+
/// Verifies that redundant cast on literal with digit separators does not trigger diagnostic.
125+
/// </summary>
126+
/// <param name="literal">A literal that is casted</param>
127+
/// <param name="type">A type that literal is casted on</param>
128+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
129+
[Theory]
130+
[InlineData("0_1", "int")]
131+
[InlineData("0_1L", "long")]
132+
[InlineData("0_1l", "long")]
133+
[InlineData("0_1UL", "ulong")]
134+
[InlineData("0_1Ul", "ulong")]
135+
[InlineData("0_1uL", "ulong")]
136+
[InlineData("0_1ul", "ulong")]
137+
[InlineData("0_1LU", "ulong")]
138+
[InlineData("0_1Lu", "ulong")]
139+
[InlineData("0_1lU", "ulong")]
140+
[InlineData("0_1lu", "ulong")]
141+
[InlineData("0_1U", "uint")]
142+
[InlineData("0_1u", "uint")]
143+
[InlineData("0_1F", "float")]
144+
[InlineData("0_1f", "float")]
145+
[InlineData("0_1D", "double")]
146+
[InlineData("0_1d", "double")]
147+
[InlineData("0_1M", "decimal")]
148+
[InlineData("0_1m", "decimal")]
149+
public async Task TestDoNotReportDiagnosticOnRedundantCastWithSeparatorsAsync(string literal, string type)
150+
{
151+
var testCode = $@"
152+
class ClassName
153+
{{
154+
public void Method()
155+
{{
156+
var x = ({type}){literal};
157+
}}
158+
}}
159+
";
160+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
161+
}
162+
163+
/// <summary>
164+
/// Verifies that other types of casts should not produces diagnostics.
165+
/// </summary>
166+
/// <param name="correctCastExpression">A legal cast that should not trigger diagnostic</param>
167+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
168+
[Theory]
169+
[InlineData("(long)~0_1")]
170+
[InlineData("(long)~+0_1")]
171+
public async Task TestOtherTypesOfCastsWithSeparatorsShouldNotTriggerDiagnosticAsync(string correctCastExpression)
172+
{
173+
var testCode = $@"
174+
class ClassName
175+
{{
176+
public void Method()
177+
{{
178+
var x = {correctCastExpression};
179+
}}
180+
}}
181+
";
182+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
183+
}
184+
185+
/// <summary>
186+
/// Verifies that diagnostics is not produced when error CS0221 is reported.
187+
/// </summary>
188+
/// <param name="type">A type that a literal is casted on</param>
189+
/// <param name="castedLiteral">A literal that is casted</param>
190+
/// <param name="literalValue">The value of the literal reported in the compiler error</param>
191+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
192+
[Theory]
193+
[InlineData("ulong", "-0_1", "-1")]
194+
public async Task TestCodeTriggeringCs0221WithSeparatorsShouldNotTriggerDiagnosticAsync(string type, string castedLiteral, string literalValue)
195+
{
196+
var testCode = $@"
197+
class ClassName
198+
{{
199+
public void Method()
200+
{{
201+
var x = ({type}){castedLiteral};
202+
}}
203+
}}
204+
";
205+
206+
DiagnosticResult[] expectedDiagnosticResult =
207+
{
208+
this.CSharpCompilerError("CS0221")
209+
.WithMessage($"Constant value '{literalValue}' cannot be converted to a '{type}' (use 'unchecked' syntax to override)")
210+
.WithLocation(6, 17),
211+
};
212+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnosticResult, CancellationToken.None).ConfigureAwait(false);
213+
}
214+
215+
/// <summary>
216+
/// Verifies that using casts in unchecked environment produces diagnostics with a correct code fix.
217+
/// </summary>
218+
/// <param name="castExpression">A cast which can be performed in unchecked environment</param>
219+
/// <param name="correctLiteral">The corresponding literal with suffix</param>
220+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
221+
[Theory]
222+
[InlineData("(ulong)-0_1L", "18446744073709551615UL")]
223+
[InlineData("(int)1_000_000_000_000_000_000L", "-1486618624")]
224+
[InlineData("(int)0xFFFF_FFFF_FFFF_FFFFL", "-1")]
225+
[InlineData("(uint)0xFFFF_FFFF_FFFF_FFFFL", "4294967295U")]
226+
public async Task TestCastsWithSeparatorsInUncheckedEnviromentShouldPreserveValueAsync(string castExpression, string correctLiteral)
227+
{
228+
var testCode = $@"
229+
class ClassName
230+
{{
231+
public void Method()
232+
{{
233+
unchecked
234+
{{
235+
var x = {castExpression};
236+
}}
237+
var y = unchecked({castExpression});
238+
}}
239+
}}
240+
";
241+
var fixedCode = $@"
242+
class ClassName
243+
{{
244+
public void Method()
245+
{{
246+
unchecked
247+
{{
248+
var x = {correctLiteral};
249+
}}
250+
var y = unchecked({correctLiteral});
251+
}}
252+
}}
253+
";
254+
DiagnosticResult[] expectedDiagnosticResult =
255+
{
256+
this.CSharpDiagnostic().WithLocation(8, 21),
257+
this.CSharpDiagnostic().WithLocation(10, 27),
258+
};
259+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnosticResult, CancellationToken.None).ConfigureAwait(false);
260+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
261+
}
10262
}
11263
}

0 commit comments

Comments
 (0)