Skip to content

Commit 60bc0ed

Browse files
authored
Merge pull request #2426 from sharwell/sa0002-test
Add a test for SA0002 when deserialization throws JsonParseException
2 parents 573011e + 6a240b3 commit 60bc0ed

2 files changed

Lines changed: 265 additions & 2 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpecialRules/SA0002UnitTests.cs

Lines changed: 262 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,23 @@
33

44
namespace StyleCop.Analyzers.Test.SpecialRules
55
{
6+
extern alias system;
7+
8+
using System;
69
using System.Collections.Generic;
10+
using System.Collections.Immutable;
711
using System.Threading;
812
using System.Threading.Tasks;
913
using Analyzers.Settings;
1014
using Analyzers.SpecialRules;
15+
using Microsoft.CodeAnalysis;
1116
using Microsoft.CodeAnalysis.Diagnostics;
17+
using Microsoft.CodeAnalysis.Text;
1218
using TestHelper;
1319
using Xunit;
1420

21+
using ExcludeFromCodeCoverageAttribute = system::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute;
22+
1523
/// <summary>
1624
/// Unit tests for <see cref="SA0002InvalidSettingsFile"/>.
1725
/// </summary>
@@ -60,7 +68,7 @@ public async Task TestInvalidSettingsAsync()
6068
}
6169

6270
[Fact]
63-
public async Task TestInvalidSettingValueAsync()
71+
public async Task TestInvalidSettingStringValueAsync()
6472
{
6573
this.settings = @"
6674
{
@@ -78,6 +86,176 @@ public async Task TestInvalidSettingValueAsync()
7886
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
7987
}
8088

89+
[Fact]
90+
public async Task TestInvalidSettingStringArrayElementValueAsync()
91+
{
92+
this.settings = @"
93+
{
94+
""settings"": {
95+
""namingRules"": {
96+
""allowedHungarianPrefixes"": [ 3 ]
97+
}
98+
}
99+
}
100+
";
101+
102+
// This diagnostic is reported without a location
103+
DiagnosticResult expected = this.CSharpDiagnostic();
104+
105+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
106+
}
107+
108+
[Fact]
109+
public async Task TestInvalidSettingBooleanValueAsync()
110+
{
111+
this.settings = @"
112+
{
113+
""settings"": {
114+
""documentationRules"": {
115+
""xmlHeader"": 3
116+
}
117+
}
118+
}
119+
";
120+
121+
// This diagnostic is reported without a location
122+
DiagnosticResult expected = this.CSharpDiagnostic();
123+
124+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
125+
}
126+
127+
[Fact]
128+
public async Task TestInvalidSettingIntegerValueAsync()
129+
{
130+
this.settings = @"
131+
{
132+
""settings"": {
133+
""indentation"": {
134+
""tabSize"": ""3""
135+
}
136+
}
137+
}
138+
";
139+
140+
// This diagnostic is reported without a location
141+
DiagnosticResult expected = this.CSharpDiagnostic();
142+
143+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
144+
}
145+
146+
[Fact]
147+
public async Task TestInvalidSettingEnumValueNotStringAsync()
148+
{
149+
this.settings = @"
150+
{
151+
""settings"": {
152+
""documentationRules"": {
153+
""fileNamingConvention"": 3
154+
}
155+
}
156+
}
157+
";
158+
159+
// This diagnostic is reported without a location
160+
DiagnosticResult expected = this.CSharpDiagnostic();
161+
162+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
163+
}
164+
165+
[Fact]
166+
public async Task TestInvalidSettingArrayElementEnumValueNotStringAsync()
167+
{
168+
this.settings = @"
169+
{
170+
""settings"": {
171+
""maintainabilityRules"": {
172+
""topLevelTypes"": [ 3 ]
173+
}
174+
}
175+
}
176+
";
177+
178+
// This diagnostic is reported without a location
179+
DiagnosticResult expected = this.CSharpDiagnostic();
180+
181+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
182+
}
183+
184+
[Fact]
185+
public async Task TestInvalidSettingArrayElementEnumValueNotRecognizedAsync()
186+
{
187+
this.settings = @"
188+
{
189+
""settings"": {
190+
""maintainabilityRules"": {
191+
""topLevelTypes"": [ ""Some incorrect value"" ]
192+
}
193+
}
194+
}
195+
";
196+
197+
// This diagnostic is reported without a location
198+
DiagnosticResult expected = this.CSharpDiagnostic();
199+
200+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
201+
}
202+
203+
[Fact]
204+
public async Task TestInvalidSettingArrayAsync()
205+
{
206+
this.settings = @"
207+
{
208+
""settings"": {
209+
""namingRules"": {
210+
""allowedHungarianPrefixes"": ""ah""
211+
}
212+
}
213+
}
214+
";
215+
216+
// This diagnostic is reported without a location
217+
DiagnosticResult expected = this.CSharpDiagnostic();
218+
219+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
220+
}
221+
222+
[Fact]
223+
public async Task TestInvalidSettingObjectAsync()
224+
{
225+
this.settings = @"
226+
{
227+
""settings"": {
228+
""namingRules"": true
229+
}
230+
}
231+
";
232+
233+
// This diagnostic is reported without a location
234+
DiagnosticResult expected = this.CSharpDiagnostic();
235+
236+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
237+
}
238+
239+
[Fact]
240+
public async Task TestInvalidSettingSyntaxAsync()
241+
{
242+
// Missing the ':' between "companyName" and "name"
243+
this.settings = @"
244+
{
245+
""settings"": {
246+
""documentationRules"": {
247+
""companyName"" ""name""
248+
}
249+
}
250+
}
251+
";
252+
253+
// This diagnostic is reported without a location
254+
DiagnosticResult expected = this.CSharpDiagnostic();
255+
256+
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
257+
}
258+
81259
[Fact]
82260
public async Task TestEmptySettingsAsync()
83261
{
@@ -91,6 +269,21 @@ public async Task TestEmptySettingsAsync()
91269
await this.VerifyCSharpDiagnosticAsync(TestCode, expected, CancellationToken.None).ConfigureAwait(false);
92270
}
93271

272+
[Fact]
273+
public void TestUnexpectedExceptionNotCaught()
274+
{
275+
var analysisContext = new AnalysisContextMissingOptions();
276+
var analyzer = new SA0002InvalidSettingsFile();
277+
analyzer.Initialize(analysisContext);
278+
Assert.NotNull(analysisContext.CompilationAction);
279+
280+
var additionalFiles = ImmutableArray.Create<AdditionalText>(new InvalidAdditionalText());
281+
Assert.Null(additionalFiles[0].Path);
282+
Assert.Null(additionalFiles[0].GetText(CancellationToken.None));
283+
var context = new CompilationAnalysisContext(compilation: null, options: new AnalyzerOptions(additionalFiles), reportDiagnostic: null, isSupportedDiagnostic: null, cancellationToken: CancellationToken.None);
284+
Assert.Throws<NullReferenceException>(() => analysisContext.CompilationAction(context));
285+
}
286+
94287
/// <inheritdoc/>
95288
protected override string GetSettings()
96289
{
@@ -102,5 +295,73 @@ protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers(
102295
{
103296
yield return new SA0002InvalidSettingsFile();
104297
}
298+
299+
private class InvalidAdditionalText : AdditionalText
300+
{
301+
public override string Path => null;
302+
303+
public override SourceText GetText(CancellationToken cancellationToken) => null;
304+
}
305+
306+
/// <summary>
307+
/// This analysis context is used for testing the specific case where an exception occurs while evaluating the
308+
/// stylecop.json settings file, but it is not one of the JSON deserialization exceptions caused by this
309+
/// library's code.
310+
/// </summary>
311+
private class AnalysisContextMissingOptions : AnalysisContext
312+
{
313+
public Action<CompilationAnalysisContext> CompilationAction
314+
{
315+
get;
316+
private set;
317+
}
318+
319+
[ExcludeFromCodeCoverage]
320+
public override void RegisterCodeBlockAction(Action<CodeBlockAnalysisContext> action)
321+
{
322+
throw new NotImplementedException();
323+
}
324+
325+
[ExcludeFromCodeCoverage]
326+
public override void RegisterCodeBlockStartAction<TLanguageKindEnum>(Action<CodeBlockStartAnalysisContext<TLanguageKindEnum>> action)
327+
{
328+
throw new NotImplementedException();
329+
}
330+
331+
public override void RegisterCompilationAction(Action<CompilationAnalysisContext> action)
332+
{
333+
this.CompilationAction = action;
334+
}
335+
336+
[ExcludeFromCodeCoverage]
337+
public override void RegisterCompilationStartAction(Action<CompilationStartAnalysisContext> action)
338+
{
339+
throw new NotImplementedException();
340+
}
341+
342+
[ExcludeFromCodeCoverage]
343+
public override void RegisterSemanticModelAction(Action<SemanticModelAnalysisContext> action)
344+
{
345+
throw new NotImplementedException();
346+
}
347+
348+
[ExcludeFromCodeCoverage]
349+
public override void RegisterSymbolAction(Action<SymbolAnalysisContext> action, ImmutableArray<SymbolKind> symbolKinds)
350+
{
351+
throw new NotImplementedException();
352+
}
353+
354+
[ExcludeFromCodeCoverage]
355+
public override void RegisterSyntaxNodeAction<TLanguageKindEnum>(Action<SyntaxNodeAnalysisContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds)
356+
{
357+
throw new NotImplementedException();
358+
}
359+
360+
[ExcludeFromCodeCoverage]
361+
public override void RegisterSyntaxTreeAction(Action<SyntaxTreeAnalysisContext> action)
362+
{
363+
throw new NotImplementedException();
364+
}
365+
}
105366
}
106367
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@
6464
<HintPath>..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.2.1\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll</HintPath>
6565
<Private>True</Private>
6666
</Reference>
67-
<Reference Include="System" />
67+
<Reference Include="System">
68+
<Aliases>global,system</Aliases>
69+
</Reference>
6870
<Reference Include="System.Collections.Immutable, Version=1.1.37.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
6971
<HintPath>..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll</HintPath>
7072
<Private>True</Private>

0 commit comments

Comments
 (0)