@@ -7,6 +7,8 @@ namespace StyleCop.Analyzers.Test.DocumentationRules
77 using System . Threading ;
88 using System . Threading . Tasks ;
99 using Analyzers . DocumentationRules ;
10+ using Helpers ;
11+ using Microsoft . CodeAnalysis ;
1012 using Microsoft . CodeAnalysis . Diagnostics ;
1113 using TestHelper ;
1214 using Xunit ;
@@ -16,6 +18,9 @@ namespace StyleCop.Analyzers.Test.DocumentationRules
1618 /// </summary>
1719 public class SA1620UnitTests : DiagnosticVerifier
1820 {
21+ private const string OrderFormatString = "The type parameter documentation for '{0}' should be at position {1}." ;
22+ private const string ParameterDoesNotExistFormatString = "The type parameter '{0}' does not exist." ;
23+
1924 public static IEnumerable < object [ ] > Members
2025 {
2126 get
@@ -156,7 +161,7 @@ public class ClassName
156161}" ;
157162
158163 var diagnostic = this . CSharpDiagnostic ( )
159- . WithMessageFormat ( "The type parameter documentation for '{0}' should be at position {1}." ) ;
164+ . WithMessageFormat ( OrderFormatString ) ;
160165
161166 var expected = new [ ]
162167 {
@@ -180,7 +185,7 @@ public async Task TestTypesWithAllDocumentationWrongOrderAsync(string p)
180185public ##" ;
181186
182187 var diagnostic = this . CSharpDiagnostic ( )
183- . WithMessageFormat ( "The type parameter documentation for '{0}' should be at position {1}." ) ;
188+ . WithMessageFormat ( OrderFormatString ) ;
184189
185190 var expected = new [ ]
186191 {
@@ -293,7 +298,7 @@ public class ClassName
293298}" ;
294299
295300 var diagnostic = this . CSharpDiagnostic ( )
296- . WithMessageFormat ( "The type parameter '{0}' does not exist." ) ;
301+ . WithMessageFormat ( ParameterDoesNotExistFormatString ) ;
297302
298303 var expected = diagnostic . WithLocation ( 12 , 26 ) . WithArguments ( "Tc" ) ;
299304
@@ -314,7 +319,7 @@ public async Task TestTypesWithInvalidDocumentationAsync(string p)
314319public ##" ;
315320
316321 var diagnostic = this . CSharpDiagnostic ( )
317- . WithMessageFormat ( "The type parameter '{0}' does not exist." ) ;
322+ . WithMessageFormat ( ParameterDoesNotExistFormatString ) ;
318323
319324 var expected = diagnostic . WithLocation ( 7 , 22 ) . WithArguments ( "Tc" ) ;
320325
@@ -341,7 +346,7 @@ public class ClassName
341346}" ;
342347
343348 var diagnostic = this . CSharpDiagnostic ( )
344- . WithMessageFormat ( "The type parameter documentation for '{0}' should be at position {1}." ) ;
349+ . WithMessageFormat ( OrderFormatString ) ;
345350
346351 var expected = diagnostic . WithLocation ( 12 , 26 ) . WithArguments ( "Tb" , 2 ) ;
347352
@@ -362,13 +367,324 @@ public async Task TestTypesWithTooManyDocumentationAsync(string p)
362367public ##" ;
363368
364369 var diagnostic = this . CSharpDiagnostic ( )
365- . WithMessageFormat ( "The type parameter documentation for '{0}' should be at position {1}." ) ;
370+ . WithMessageFormat ( OrderFormatString ) ;
366371
367372 var expected = diagnostic . WithLocation ( 7 , 22 ) . WithArguments ( "Tb" , 2 ) ;
368373
369374 await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , expected , CancellationToken . None ) . ConfigureAwait ( false ) ;
370375 }
371376
377+ /// <summary>
378+ /// Verifies that a type with included documentation will produce no diagnostics.
379+ /// </summary>
380+ /// <param name="p">The type declaration text that will be used.</param>
381+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
382+ [ Theory ]
383+ [ MemberData ( nameof ( Types ) ) ]
384+ public async Task TestTypeWithIncludedDocumentationAsync ( string p )
385+ {
386+ var testCode = @"
387+ /// <include file='TypeWithTypeparamsDoc.xml' path='/Foo/*'/>
388+ public ##
389+ " ;
390+
391+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , EmptyDiagnosticResults , CancellationToken . None ) . ConfigureAwait ( false ) ;
392+ }
393+
394+ /// <summary>
395+ /// Verifies that a type without typeparam documentation in the included documentation will produce no diagnostics.
396+ /// </summary>
397+ /// <param name="p">The type declaration text that will be used.</param>
398+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
399+ [ Theory ]
400+ [ MemberData ( nameof ( Types ) ) ]
401+ public async Task TestTypeWithoutTypeparamInIncludedDocumentationAsync ( string p )
402+ {
403+ var testCode = @"
404+ /// <include file='TypeWithoutTypeparamsDoc.xml' path='/Foo/*'/>
405+ public ##
406+ " ;
407+
408+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , EmptyDiagnosticResults , CancellationToken . None ) . ConfigureAwait ( false ) ;
409+ }
410+
411+ /// <summary>
412+ /// Verifies that a type with inheritdoc in the included documentation will produce no diagnostics.
413+ /// </summary>
414+ /// <param name="p">The type declaration text that will be used.</param>
415+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
416+ [ Theory ]
417+ [ MemberData ( nameof ( Types ) ) ]
418+ public async Task TestTypeWithInheritDocInIncludedDocumentationAsync ( string p )
419+ {
420+ var testCode = @"
421+ /// <include file='TypeWithInheritdoc.xml' path='/Foo/*'/>
422+ public ##
423+ " ;
424+
425+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , EmptyDiagnosticResults , CancellationToken . None ) . ConfigureAwait ( false ) ;
426+ }
427+
428+ /// <summary>
429+ /// Verifies that a type with wrongly ordered typeparam documentation in the included documentation will produce the expected diagnostics.
430+ /// </summary>
431+ /// <param name="p">The type declaration text that will be used.</param>
432+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
433+ [ Theory ]
434+ [ MemberData ( nameof ( Types ) ) ]
435+ public async Task TestTypeWithWronglyOrderedTypeParamInIncludedDocumentationAsync ( string p )
436+ {
437+ var testCode = @"
438+ /// <include file='TypeWithWronglyOrderedTypeparamsDoc.xml' path='/Foo/*'/>
439+ public ##
440+ " ;
441+ DiagnosticResult [ ] expected =
442+ {
443+ this . CSharpDiagnostic ( ) . WithLocation ( 2 , 5 ) . WithMessageFormat ( OrderFormatString ) . WithArguments ( "Tb" , 2 ) ,
444+ this . CSharpDiagnostic ( ) . WithLocation ( 2 , 5 ) . WithMessageFormat ( OrderFormatString ) . WithArguments ( "Ta" , 1 ) ,
445+ } ;
446+
447+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , expected , CancellationToken . None ) . ConfigureAwait ( false ) ;
448+ }
449+
450+ /// <summary>
451+ /// Verifies that a type with a missing typeparam in the included documentation will produce the expected diagnostics.
452+ /// </summary>
453+ /// <param name="p">The type declaration text that will be used.</param>
454+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
455+ [ Theory ]
456+ [ MemberData ( nameof ( Types ) ) ]
457+ public async Task TestTypeWithMissingTypeParamInIncludedDocumentationAsync ( string p )
458+ {
459+ var testCode = @"
460+ /// <include file='TypeWithMissingTypeparamDoc.xml' path='/Foo/*'/>
461+ public ##
462+ " ;
463+ DiagnosticResult [ ] expected =
464+ {
465+ this . CSharpDiagnostic ( ) . WithLocation ( 2 , 5 ) . WithMessageFormat ( OrderFormatString ) . WithArguments ( "Tb" , 2 ) ,
466+ this . CSharpDiagnostic ( ) . WithLocation ( 2 , 5 ) . WithMessageFormat ( ParameterDoesNotExistFormatString ) . WithArguments ( "Tc" ) ,
467+ } ;
468+
469+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , expected , CancellationToken . None ) . ConfigureAwait ( false ) ;
470+ }
471+
472+ /// <summary>
473+ /// Verifies that a method with included documentation will produce no diagnostics.
474+ /// </summary>
475+ /// <param name="p">The method declaration text that will be used.</param>
476+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
477+ [ Theory ]
478+ [ MemberData ( nameof ( Members ) ) ]
479+ public async Task TestMethodWithIncludedDocumentationAsync ( string p )
480+ {
481+ var testCode = @"
482+ /// <summary>Test class</summary>
483+ public class TestClass
484+ {
485+ /// <include file='MethodWithTypeparamsDoc.xml' path='/TestClass/Foo/*'/>
486+ public ##
487+ }
488+ " ;
489+
490+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , EmptyDiagnosticResults , CancellationToken . None ) . ConfigureAwait ( false ) ;
491+ }
492+
493+ /// <summary>
494+ /// Verifies that a method without typeparam documentation in the included documentation will produce no diagnostics.
495+ /// </summary>
496+ /// <param name="p">The method declaration text that will be used.</param>
497+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
498+ [ Theory ]
499+ [ MemberData ( nameof ( Members ) ) ]
500+ public async Task TestMethodWithoutTypeparamInIncludedDocumentationAsync ( string p )
501+ {
502+ var testCode = @"
503+ /// <summary>Test class</summary>
504+ public class TestClass
505+ {
506+ /// <include file='MethodWithoutTypeparamsDoc.xml' path='/TestClass/Foo/*'/>
507+ public ##
508+ }
509+ " ;
510+
511+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , EmptyDiagnosticResults , CancellationToken . None ) . ConfigureAwait ( false ) ;
512+ }
513+
514+ /// <summary>
515+ /// Verifies that a method with inheritdoc in the included documentation will produce no diagnostics.
516+ /// </summary>
517+ /// <param name="p">The method declaration text that will be used.</param>
518+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
519+ [ Theory ]
520+ [ MemberData ( nameof ( Members ) ) ]
521+ public async Task TestMethodWithInheritDocInIncludedDocumentationAsync ( string p )
522+ {
523+ var testCode = @"
524+ /// <summary>Test class</summary>
525+ public class TestClass
526+ {
527+ /// <include file='MethodWithoutTypeparamsDoc.xml' path='/TestClass/Foo/*'/>
528+ public ##
529+ }
530+ " ;
531+
532+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , EmptyDiagnosticResults , CancellationToken . None ) . ConfigureAwait ( false ) ;
533+ }
534+
535+ /// <summary>
536+ /// Verifies that a method with wrongly ordered typeparam documentation in the included documentation will produce the expected diagnostics.
537+ /// </summary>
538+ /// <param name="p">The method declaration text that will be used.</param>
539+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
540+ [ Theory ]
541+ [ MemberData ( nameof ( Members ) ) ]
542+ public async Task TestMethodWithWronglyOrderedTypeParamInIncludedDocumentationAsync ( string p )
543+ {
544+ var testCode = @"
545+ /// <summary>Test class</summary>
546+ public class TestClass
547+ {
548+ /// <include file='MethodWithWronglyOrderedTypeparamsDoc.xml' path='/TestClass/Foo/*'/>
549+ public ##
550+ }
551+ " ;
552+ DiagnosticResult [ ] expected =
553+ {
554+ this . CSharpDiagnostic ( ) . WithLocation ( 5 , 9 ) . WithMessageFormat ( OrderFormatString ) . WithArguments ( "Tb" , 2 ) ,
555+ this . CSharpDiagnostic ( ) . WithLocation ( 5 , 9 ) . WithMessageFormat ( OrderFormatString ) . WithArguments ( "Ta" , 1 ) ,
556+ } ;
557+
558+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , expected , CancellationToken . None ) . ConfigureAwait ( false ) ;
559+ }
560+
561+ /// <summary>
562+ /// Verifies that a method with a missing typeparam in the included documentation will produce the expected diagnostics.
563+ /// </summary>
564+ /// <param name="p">The method declaration text that will be used.</param>
565+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
566+ [ Theory ]
567+ [ MemberData ( nameof ( Members ) ) ]
568+ public async Task TestMethodWithMissingTypeParamInIncludedDocumentationAsync ( string p )
569+ {
570+ var testCode = @"
571+ /// <summary>Test class</summary>
572+ public class TestClass
573+ {
574+ /// <include file='MethodWithMissingTypeparamDoc.xml' path='/TestClass/Foo/*'/>
575+ public ##
576+ }
577+ " ;
578+ DiagnosticResult [ ] expected =
579+ {
580+ this . CSharpDiagnostic ( ) . WithLocation ( 5 , 9 ) . WithMessageFormat ( OrderFormatString ) . WithArguments ( "Tb" , 2 ) ,
581+ this . CSharpDiagnostic ( ) . WithLocation ( 5 , 9 ) . WithMessageFormat ( ParameterDoesNotExistFormatString ) . WithArguments ( "Tc" ) ,
582+ } ;
583+
584+ await this . VerifyCSharpDiagnosticAsync ( testCode . Replace ( "##" , p ) , expected , CancellationToken . None ) . ConfigureAwait ( false ) ;
585+ }
586+
587+ protected override Project ApplyCompilationOptions ( Project project )
588+ {
589+ var resolver = new TestXmlReferenceResolver ( ) ;
590+
591+ string contentTypeWithTypeparamDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
592+ <Foo>
593+ <summary>Test class</summary>
594+ <typeparam name=""Ta"">Param 1</typeparam>
595+ <typeparam name=""Tb"">Param 2</typeparam>
596+ </Foo>
597+ " ;
598+ resolver . XmlReferences . Add ( "TypeWithTypeparamsDoc.xml" , contentTypeWithTypeparamDoc ) ;
599+
600+ string contentTypeWithoutTypeparamsDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
601+ <Foo>
602+ <summary>Test class</summary>
603+ </Foo>
604+ " ;
605+ resolver . XmlReferences . Add ( "TypeWithoutTypeparamsDoc.xml" , contentTypeWithoutTypeparamsDoc ) ;
606+
607+ string contentTypeInheritdoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
608+ <Foo>
609+ <inheritdoc/>
610+ </Foo>
611+ " ;
612+ resolver . XmlReferences . Add ( "TypeWithInheritdoc.xml" , contentTypeInheritdoc ) ;
613+
614+ string contentTypeWithWronglyOrderedTypeparamDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
615+ <Foo>
616+ <summary>Test class</summary>
617+ <typeparam name=""Tb"">Param 2</typeparam>
618+ <typeparam name=""Ta"">Param 1</typeparam>
619+ </Foo>
620+ " ;
621+ resolver . XmlReferences . Add ( "TypeWithWronglyOrderedTypeparamsDoc.xml" , contentTypeWithWronglyOrderedTypeparamDoc ) ;
622+
623+ string contentTypeWithMissingTypeparamDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
624+ <Foo>
625+ <summary>Test class</summary>
626+ <typeparam name=""Tb"">Param 2</typeparam>
627+ <typeparam name=""Tc"">Param 3</typeparam>
628+ </Foo>
629+ " ;
630+ resolver . XmlReferences . Add ( "TypeWithMissingTypeparamDoc.xml" , contentTypeWithMissingTypeparamDoc ) ;
631+
632+ string contentMethodWithTypeparamDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
633+ <TestClass>
634+ <Foo>
635+ <summary>Test class</summary>
636+ <typeparam name=""Ta"">Param 1</typeparam>
637+ <typeparam name=""Tb"">Param 2</typeparam>
638+ </Foo>
639+ </TestClass>
640+ " ;
641+ resolver . XmlReferences . Add ( "MethodWithTypeparamsDoc.xml" , contentMethodWithTypeparamDoc ) ;
642+
643+ string contentMethodWithoutTypeparamsDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
644+ <TestClass>
645+ <Foo>
646+ <summary>Test class</summary>
647+ </Foo>
648+ </TestClass>
649+ " ;
650+ resolver . XmlReferences . Add ( "MethodWithoutTypeparamsDoc.xml" , contentMethodWithoutTypeparamsDoc ) ;
651+
652+ string contentMethodInheritdoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
653+ <TestClass>
654+ <Foo>
655+ <inheritdoc/>
656+ </Foo>
657+ </TestClass>
658+ " ;
659+ resolver . XmlReferences . Add ( "MethodWithInheritdoc.xml" , contentMethodInheritdoc ) ;
660+
661+ string contentMethodWithWronglyOrderedTypeparamDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
662+ <TestClass>
663+ <Foo>
664+ <summary>Test class</summary>
665+ <typeparam name=""Tb"">Param 2</typeparam>
666+ <typeparam name=""Ta"">Param 1</typeparam>
667+ </Foo>
668+ </TestClass>
669+ " ;
670+ resolver . XmlReferences . Add ( "MethodWithWronglyOrderedTypeparamsDoc.xml" , contentMethodWithWronglyOrderedTypeparamDoc ) ;
671+
672+ string contentMethodWithMissingTypeparamDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
673+ <TestClass>
674+ <Foo>
675+ <summary>Test class</summary>
676+ <typeparam name=""Tb"">Param 2</typeparam>
677+ <typeparam name=""Tc"">Param 3</typeparam>
678+ </Foo>
679+ </TestClass>
680+ " ;
681+ resolver . XmlReferences . Add ( "MethodWithMissingTypeparamDoc.xml" , contentMethodWithMissingTypeparamDoc ) ;
682+
683+ project = base . ApplyCompilationOptions ( project ) ;
684+ project = project . WithCompilationOptions ( project . CompilationOptions . WithXmlReferenceResolver ( resolver ) ) ;
685+ return project ;
686+ }
687+
372688 protected override IEnumerable < DiagnosticAnalyzer > GetCSharpDiagnosticAnalyzers ( )
373689 {
374690 yield return new SA1620GenericTypeParameterDocumentationMustMatchTypeParameters ( ) ;
0 commit comments