33
44namespace 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}
0 commit comments